From 25677fe58723d6304bdc6b211f7be401b8b830b2 Mon Sep 17 00:00:00 2001 From: Andrew Mikofalvy <5668128+amikofalvy@users.noreply.github.com> Date: Thu, 25 Jun 2026 17:52:07 -0700 Subject: [PATCH] fix(open-knowledge): thread composer instruction into Terminal CLI launch (#2156) The bottom Ask AI composer carries its typed instruction in input.compose, but composeTerminalLaunchPrompt only checked the top-level input.instruction used by the toolbar popover. Composer dispatches to a Terminal CLI therefore fell through to the bare load-and-stop prompt and silently dropped the user's message, so the launched CLI never saw what the user asked. Route compose-scope inputs through selectScopedPrompt (which already threads input.compose through assembleHandoffPrompt) so the instruction reaches the launched CLI exactly as it does the deep-link handoff. Adds a regression test pinning the compose-scope launch to selectScopedPrompt. GitOrigin-RevId: 45cb9ec04a0e878d0667096b1de89298ec488f48 --- .../terminal-composer-instruction-threaded.md | 5 ++++ .../handoff/useHandoffDispatch.test.ts | 30 +++++++++++++++++++ .../components/handoff/useHandoffDispatch.ts | 2 +- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 .changeset/terminal-composer-instruction-threaded.md diff --git a/.changeset/terminal-composer-instruction-threaded.md b/.changeset/terminal-composer-instruction-threaded.md new file mode 100644 index 000000000..c90cb09af --- /dev/null +++ b/.changeset/terminal-composer-instruction-threaded.md @@ -0,0 +1,5 @@ +--- +"@inkeep/open-knowledge-app": patch +--- + +Fix the bottom "Ask AI" composer dropping the typed instruction when launching a Terminal CLI. A composer dispatch carries its instruction (and `@`-mentions / selection) in `input.compose`, but the docked-terminal launcher only checked the top-level `input.instruction` the toolbar popover uses — so every composer-typed message fell through to the bare "load OK, then stop" prompt and the agent never saw what the user asked. The terminal launcher now routes compose-scope dispatches through the same prompt assembler as the deep-link handoff, so the instruction threads through to the launched CLI exactly as it does to a Claude/Codex/Cursor deep link. diff --git a/packages/app/src/components/handoff/useHandoffDispatch.test.ts b/packages/app/src/components/handoff/useHandoffDispatch.test.ts index 0830b8c64..8a4524ec4 100644 --- a/packages/app/src/components/handoff/useHandoffDispatch.test.ts +++ b/packages/app/src/components/handoff/useHandoffDispatch.test.ts @@ -1488,6 +1488,36 @@ describe('composeTerminalLaunchPrompt — docked-terminal bare launch is load + expect(claudeOut).not.toContain(OK_TERMINAL_SURFACE_PREAMBLE); }); + test('composer (compose scope) threads the typed instruction — NOT a bare launch', async () => { + const { composeTerminalLaunchPrompt, selectScopedPrompt } = await import( + './useHandoffDispatch' + ); + const input = { + docContext: null, + compose: { + scope: 'doc' as const, + docRelativePath: 'notes/work-log.md', + instruction: 'What does this file do?', + mentions: [], + }, + projectDir: '/proj', + docPath: '/proj/notes/work-log.md', + }; + expect(composeTerminalLaunchPrompt(input, 'claude')).toBe( + selectScopedPrompt(input, 'claude-code', false), + ); + expect(composeTerminalLaunchPrompt(input, 'codex')).toBe( + selectScopedPrompt(input, 'codex', false), + ); + expect(composeTerminalLaunchPrompt(input, 'cursor')).toBe( + selectScopedPrompt(input, 'cursor', false), + ); + const claudeOut = composeTerminalLaunchPrompt(input, 'claude'); + expect(claudeOut).toContain('What does this file do?'); + expect(claudeOut).not.toBe(composeTerminalBareLaunchPrompt('notes/work-log.md')); + expect(claudeOut).not.toContain(OK_TERMINAL_SURFACE_PREAMBLE); + }); + test('whitespace-only instruction is treated as a bare launch', async () => { const { composeTerminalLaunchPrompt } = await import('./useHandoffDispatch'); const out = composeTerminalLaunchPrompt( diff --git a/packages/app/src/components/handoff/useHandoffDispatch.ts b/packages/app/src/components/handoff/useHandoffDispatch.ts index aed38ad9a..8916ba5b8 100644 --- a/packages/app/src/components/handoff/useHandoffDispatch.ts +++ b/packages/app/src/components/handoff/useHandoffDispatch.ts @@ -417,7 +417,7 @@ export function selectScopedPrompt( export function composeTerminalLaunchPrompt(input: HandoffDispatchInput, cli: TerminalCli): string { const hasInstruction = typeof input.instruction === 'string' && input.instruction.trim() !== ''; - if (input.createDescription !== undefined || hasInstruction) { + if (input.compose !== undefined || input.createDescription !== undefined || hasInstruction) { return selectScopedPrompt(input, TERMINAL_CLIS[cli].handoffTarget, false); } return composeTerminalBareLaunchPrompt(input.docContext?.relativePath ?? null);