diff --git a/src/cli/handlers/orchestration-gate-cli.test.ts b/src/cli/handlers/orchestration-gate-cli.test.ts index a2793ac9323..217e2f359f1 100644 --- a/src/cli/handlers/orchestration-gate-cli.test.ts +++ b/src/cli/handlers/orchestration-gate-cli.test.ts @@ -34,6 +34,9 @@ import { okFixture, queueFixtures } from '../test-fixtures' const originalTerminalHandle = process.env.ORCA_TERMINAL_HANDLE const originalPaneKey = process.env.ORCA_PANE_KEY +// Why: a structured-session marker inherited from the runner diverts these cases to the +// structured refusal, so which branch they exercise would depend on who ran them. +const originalStructuredSession = process.env.ORCA_STRUCTURED_SESSION const restoreEnv = (name: string, value: string | undefined): void => { if (value === undefined) { @@ -54,6 +57,7 @@ describe('orchestration gate commands carry caller identity', () => { errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) delete process.env.ORCA_TERMINAL_HANDLE delete process.env.ORCA_PANE_KEY + delete process.env.ORCA_STRUCTURED_SESSION process.exitCode = 0 }) @@ -62,6 +66,7 @@ describe('orchestration gate commands carry caller identity', () => { errorSpy.mockRestore() restoreEnv('ORCA_TERMINAL_HANDLE', originalTerminalHandle) restoreEnv('ORCA_PANE_KEY', originalPaneKey) + restoreEnv('ORCA_STRUCTURED_SESSION', originalStructuredSession) process.exitCode = 0 }) @@ -192,7 +197,7 @@ describe('orchestration gate commands carry caller identity', () => { expect(process.exitCode).toBe(1) const stderr = errorSpy.mock.calls.map((call) => String(call[0])).join('\n') - expect(stderr).toContain('Pass --from ') + expect(stderr).toContain("Pass --from with your own terminal's handle") expect(callMock).not.toHaveBeenCalledWith('orchestration.gateCreate', expect.anything()) }) diff --git a/src/cli/handlers/orchestration/terminal-identity.ts b/src/cli/handlers/orchestration/terminal-identity.ts index 505bfaac262..83097e02126 100644 --- a/src/cli/handlers/orchestration/terminal-identity.ts +++ b/src/cli/handlers/orchestration/terminal-identity.ts @@ -36,10 +36,14 @@ export async function resolveOrchestrationTerminalHandle( // rightful worker never saw its mail. Refusing is the only honest answer: this child genuinely // cannot infer its own identity. if (isStructuredSessionWithoutIdentity()) { + // Why not suggest --${flagName}: the explicit-flag branch above returns before this guard, so + // that advice succeeds — against a handle that necessarily belongs to another pane. throw new RuntimeClientError( 'no_active_sender_terminal', - `This chat session has no orchestration identity of its own, so --${flagName} cannot be inferred. ` + - `Pass --${flagName} explicitly; guessing would act on another pane's mailbox.` + `This chat session has no orchestration identity of its own, so --${flagName} cannot be inferred, ` + + `and no terminal handle names it — every live handle belongs to a different pane, whose mailbox ` + + `passing it would consume. Drive a worker directly instead: create a worktree, create a terminal ` + + `in it with an agent, then use terminal send and terminal read.` ) } if (flagName === 'from') { @@ -192,6 +196,7 @@ export function throwNoActiveSenderTerminal(): never { throw new RuntimeClientError( 'no_active_sender_terminal', 'Could not determine the sender terminal for this orchestration command. ' + - 'Pass --from or run the command inside a live Orca terminal with ORCA_TERMINAL_HANDLE set.' + "Pass --from with your own terminal's handle — another pane's handle would act on its mailbox — " + + 'or run the command inside a live Orca terminal with ORCA_TERMINAL_HANDLE set.' ) }