Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5425513
feat(acp): add mode selection and scoped catalog lifecycle
Sun-GLiang Sep 29, 2026
c925d26
fix(acp): preserve executor configuration authority
Sun-GLiang Sep 29, 2026
cdc7686
fix(protocol): validate optional executor catalog fields
Sun-GLiang Sep 29, 2026
84660f1
fix(acp): reconcile reviewed configuration races
Sun-GLiang Sep 29, 2026
086cbb0
fix(acp): preserve confirmed selection across agent drift
Sun-GLiang Sep 29, 2026
8edbcbb
fix(acp): keep saved selection across agent drift
Sun-GLiang Sep 29, 2026
c2edb3f
docs(acp): reconcile official agent acceptance findings
Sun-GLiang Sep 29, 2026
a85b381
fix(desktop): select extracted ACP directory on macOS
Sun-GLiang Sep 29, 2026
17db8d7
Merge apache/main into ACP mode catalog
Sun-GLiang Sep 30, 2026
054b051
Merge latest apache/main and advance ACP protocol epoch
Sun-GLiang Sep 30, 2026
3643698
fix(acp): validate mode after model selection
Sun-GLiang Sep 30, 2026
88a36a2
docs(acp): record real directory refresh isolation
Sun-GLiang Sep 30, 2026
812ef47
docs(acp): record second project desktop catalog
Sun-GLiang Sep 30, 2026
82d0d33
docs(acp): reconcile second project acceptance summary
Sun-GLiang Sep 30, 2026
da5aa4e
docs(acp): record desktop cross-project acceptance
Sun-GLiang Sep 30, 2026
00464c1
docs(acp): complete repeatable PR 5826 acceptance procedure
Sun-GLiang Oct 1, 2026
b051b17
docs(acp): record inconclusive eligibility recheck
Sun-GLiang Oct 1, 2026
ce46c48
fix(acp): advance mode catalog protocol epoch beyond main
Sun-GLiang Oct 1, 2026
487ae0d
Merge main and reconcile ACP mode catalog epoch
Sun-GLiang Oct 1, 2026
a023bba
docs(acp): record successful official execution recheck
Sun-GLiang Oct 1, 2026
0c4dbac
docs: close official Agent Desktop acceptance
Sun-GLiang Oct 1, 2026
3263e48
fix(acp): restore model before dependent mode on rollback
Sun-GLiang Oct 1, 2026
6c4cd2d
fix(ui): block sends until executor mode is confirmed
Sun-GLiang Oct 1, 2026
cc9c012
fix(acp): isolate draft catalog probes from project sessions
Sun-GLiang Oct 2, 2026
8ef0105
fix(acp): validate program selection and consolidate protocol history
Sun-GLiang Oct 2, 2026
82d6b12
chore(test): sync Windows program selection skip inventory
Sun-GLiang Oct 2, 2026
4fefdc1
fix(acp): reuse leased catalog paths and restart invalidated waiters
Sun-GLiang Oct 2, 2026
4c12e19
docs(acp): record stable probe and preceding desktop acceptance
Sun-GLiang Oct 2, 2026
4b7fb5e
test(acp): cover catalog refresh and mode configuration boundaries
Sun-GLiang Oct 2, 2026
91df4ac
fix(desktop): preserve executor controls during first send
Sun-GLiang Oct 3, 2026
a103d2f
fix(test): import executor composer through conversation API
Sun-GLiang Oct 3, 2026
2d016ea
Merge main and preserve executor handoff within architecture budget
Sun-GLiang Oct 3, 2026
b51fd2e
fix(acp): reject unavailable explicit modes before prompting
Sun-GLiang Oct 3, 2026
3779a65
fix(acp): recover stale modes and restore catalog refresh
Sun-GLiang Oct 3, 2026
eb37fa6
Merge main and preserve executor handoff in Composer ownership
Sun-GLiang Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/desktop/renderer-architecture.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@
"chatTurnActivity",
"createComposerStagingCommands",
"createComposerSubmissionCommands",
"createExecutorSessionActivator",
"desktopSlashCommandPresentation",
"executorComposerProps",
"resolveTaskReadinessModelTarget",
Expand Down Expand Up @@ -761,7 +762,7 @@
"react": 1
},
"importSpecifiers": 60,
"nonTriviaTokens": 8017
"nonTriviaTokens": 8009
},
"src/renderer/use-app-shell-session-list.ts": {
"importDeclarations": 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { act, createElement, Fragment } from 'react';
import type { StoredMessage } from '@maka/core/session';
import type { UserQuestionResponse } from '@maka/core/user-question';
import type { SandboxBoundaryResponse } from '@maka/core/sandbox-boundary';
import { AstryxLocaleProvider, LocaleProvider, ToastProvider } from '@maka/ui';
import { AstryxLocaleProvider, LocaleProvider, ToastProvider, type ComposerProps } from '@maka/ui';
import type { DesktopSessionSummary } from '../../shared/desktop-session-projection.js';
import {
createSessionCatalogController,
Expand Down Expand Up @@ -65,6 +65,8 @@ type Owner = { sessionId: string | undefined };
type ProviderProps = Parameters<typeof ComposerSubmissionProvider<Owner>>[0];

interface RegionProps {
executorPicker?: ComposerProps['executorPicker'];
sendBlocked?: boolean;
onSend(text: string, metadata?: { followUpMode?: 'steer' | 'queue' }): Promise<boolean | void>;
newTaskSendPending: boolean;
revisionNotice?: { title: string; detail: string; cancelLabel: string; onCancel(): void };
Expand Down Expand Up @@ -100,6 +102,8 @@ function harness(options: {
newTask?: Partial<ProviderProps['newTask']>;
sharedSessionActive?: boolean;
listMessages?: ReturnType<typeof stubConversationServices>['listMessages'];
executorPicker?: ComposerProps['executorPicker'];
sendBlocked?: boolean;
} = {}) {
const { root } = installReactRenderer();
const catalog = createSessionCatalogController();
Expand Down Expand Up @@ -150,6 +154,7 @@ function harness(options: {
}),
createElement(ConversationComposerRegion<RegionProps>, {
surface: Composer, contextPickEnabled: true, directoryPickerEnabled: true,
executorPicker: options.executorPicker, sendBlocked: options.sendBlocked,
}),
);
}
Expand Down Expand Up @@ -189,6 +194,9 @@ describe('ComposerSubmissionProvider', () => {
const submitted: unknown[] = [];
const admission = deferred<Awaited<ReturnType<ComposerSubmissionServices['submitMessage']>>>();
const h = harness({
executorPicker: {
catalog: [], onSelect() {}, onSetup() {}, onRetry() {}, onNewTask() {},
},
services: {
submitMessage: (sessionId, placement, command) => {
submitted.push({ sessionId, placement, text: command.text });
Expand All @@ -199,10 +207,14 @@ describe('ComposerSubmissionProvider', () => {
await act(async () => h.target.setActiveId('A'));
await act(async () => h.published[0]!([userTurn('turn-1', 'earlier')]));
assert.equal(h.region.newTaskSendPending, false);
assert.equal(h.region.executorPicker?.disabled, false);
assert.equal(h.region.sendBlocked, false);

let sending!: Promise<boolean | void>;
await act(async () => { sending = h.region.onSend('hello'); });
assert.equal(h.region.newTaskSendPending, true, 'the flag is the owner\'s, read by the Composer slot');
assert.equal(h.region.executorPicker?.disabled, true, 'executor changes stay locked until Host admission settles');
assert.equal(h.region.sendBlocked, true);
assert.deepEqual(submitted, [{ sessionId: 'A', placement: 'next_turn', text: 'hello' }]);

await act(async () => {
Expand All @@ -213,6 +225,20 @@ describe('ComposerSubmissionProvider', () => {
assert.equal(await sending, true);
});
assert.equal(h.region.newTaskSendPending, false);
assert.equal(h.region.executorPicker?.disabled, false);
assert.equal(h.region.sendBlocked, false);
});

test('retains existing executor and send gates while no submission is pending', () => {
const h = harness({
executorPicker: {
catalog: [], disabled: true, onSelect() {}, onSetup() {}, onRetry() {}, onNewTask() {},
},
sendBlocked: true,
});
assert.equal(h.region.newTaskSendPending, false);
assert.equal(h.region.executorPicker?.disabled, true);
assert.equal(h.region.sendBlocked, true);
});

test('steers into the running Host Turn: the pending row names that Turn before the Host answers', async () => {
Expand Down
Loading
Loading