From 7a46612f412ccd03a723ac1a5f0e9ba7def29001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Fri, 21 Aug 2026 18:30:14 +0000 Subject: [PATCH] the handoff watcher was built and never rendered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BackgroundJobDialog offers three fire behaviours and gates the third, `handoff` — exit, act, re-arm — on an `isCommander` prop. Nothing ever passed it. So it defaulted to false everywhere and the option appeared NOWHERE, including inside a Command HQ commander, where the dialog's own code makes it the default. Everything else was there: the fire rule, `handoffContract`, `armWatcher` reaching the server, and a note recording that it had run for hours self-re-arming without failure. Only the radio button was missing, which made a working mechanism look unbuilt — and it is the one a deploy watcher needs, since `keep-going` never hands back to an agent at all. Found while telling the owner how to start the deploy commander: the dialog in a commander showed two options where I had said there would be three. The fix is two lines and no new concept. `useEmbeddableChat` already receives `context` and passed it into `useChat`; it now also returns it, and InputArea gives the dialog `isCommander={context === 'command-hq'}`. Co-Authored-By: Claude Opus 5 --- .../src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts | 4 ++++ .../officerdev/src/apps/Chat/components/InputArea.tsx | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts index 7dfe209c..012feec5 100644 --- a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts +++ b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts @@ -575,6 +575,10 @@ export function useEmbeddableChat(params: UseEmbeddableChatParams, onMessageComp }, [autoSend, isConnected, messages.length, input]); return { + // Surfaced so the composer can offer what only makes sense here. The Command HQ context is the one + // place a `handoff` watcher can be promised — see BackgroundJobDialog — and it was invisible to the + // composer, so the option was never rendered anywhere at all. + context: params.context, messages, historicalCount, streamingText, diff --git a/src/workspaces/officerdev/src/apps/Chat/components/InputArea.tsx b/src/workspaces/officerdev/src/apps/Chat/components/InputArea.tsx index 5eb20159..9e3b5e8c 100644 --- a/src/workspaces/officerdev/src/apps/Chat/components/InputArea.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/components/InputArea.tsx @@ -173,6 +173,16 @@ export const InputArea = ({ manager }: InputAreaProps) => { open={jobDialogOpen} onOpenChange={setJobDialogOpen} cwd={cwd} + /* + `handoff` — exit, act, re-arm — is only offered inside a Command HQ commander, because it is a + promise the platform has to keep rather than only a sentence in the prompt. + + This prop was never passed by anybody, so `isCommander` defaulted to false everywhere and the + option was rendered NOWHERE — including in a commander, where the dialog's own code makes it the + default. The whole mechanism existed: the fire behaviour, the contract, `armWatcher` reaching the + server. Only the radio button was missing, so the feature looked unbuilt. + */ + isCommander={manager.context === 'command-hq'} onSubmit={(intent, preamble, armWatcher) => { // Claimed by the next job to start, which is how the preview tells this one apart from the // background jobs an agent starts on its own.