fix(orchestration): don't steal active-tab focus when a director spawns a worker via the CLI - #35
Conversation
…ns a worker via the CLI #29 stopped in-app renderer launches from stealing the user's active tab, but missed the CLI→IPC path: an in-app Orcastrator spawns each worker by running `orca worktree create --agent …` from its own terminal. `--agent` forces `activate: true`, so every worker switched the user's active tab — yanking them away from their work. Fix at the CLI layer (smallest, reuses the existing main-side `shouldActivate` gate — no IPC/renderer change): when the create originates from a director worktree, suppress the agent/run-hooks-derived activation so `notifyActivateWorktree` is never called. The worktree is still created, its agent spawned, and revealed in the sidebar + Mission Control — only the active-tab switch is skipped. A normal (non-director) origin still activates as before, and an explicit `--activate` overrides the suppression. Director identity is the durable worktree displayName prefix ("Orcastrator · "), moved to src/shared/orchestrator-identity.ts so the CLI and renderer share one constant. The CLI already resolves the originating worktree from cwd for lineage; that same lookup now also reports whether the origin is a director, so no extra round-trip is added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nt --repo The first pass only computed `originIsOrchestrator` inside the cwd parent/repo- inference block, gated by `(!explicitParentWorktree && !explicitParentWorkspace && !noParent) || needsCwdRepoInference`. The real /orcastrate pattern spawns workers parent-less (parent=None) with an explicit `--repo`, which skips that block — so suppression never applied and the focus-steal still happened. Make the orchestrator-origin suppression decision independent of the parent/repo gate: whenever activation would be derived (run-hooks or startupAgent) and `--activate` was not explicitly passed, resolve the cwd worktree context to learn whether the origin is a director. Reuse the context already resolved by the gated block when it ran; otherwise do one extra `resolveCurrentWorktreeContext` call — guarded so it is skipped when activation wouldn't be derived anyway (no extra RPC on the common non-agent create path). Tests: `--no-parent --repo --agent` from a director cwd → activate:false; the same from a normal cwd → activate:true. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revision: close the
|
#29 added a `suppressActivation` flag to keep a director from yanking the user's active tab when a worker is spawned programmatically. That flag was also applied to `launchOrchestratorForProject`, which is reached only by the user clicking "+" in the ORCASTRATORS sidebar section — a deliberate, manual action that SHOULD focus the new window, exactly like the "+" for a regular worktree. As a result, opening a new Orcastrator silently left the user on their current worktree. User-facing change: opening a new Orcastrator now activates (focuses) it. - orchestrator-launch.ts: stop passing `suppressActivation: true` to `activateAndRevealWorktree`. - director-worktree-shell.ts: drop the trailing `{ suppressActivation: true }` on the store create so the host-side (SSH/remote) `activate` gate also focuses the new director. `launchOrchestratorForProject` is its only caller, so no per-caller threading is needed. Worker-spawn focus suppression is untouched: the CLI worker-spawn path (#35) and any renderer worker-create path still suppress activation. A director spawning a WORKER must still not steal focus. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bug (CLI→IPC focus-steal gap #29 missed)
An in-app Orcastrator (Smart director) spawns each worker by running
orca worktree create --agent …from its own terminal. In the CLI create handler, any--agentforcedactivate: true:That flowed
activate: true→worktree.createRPC →createManagedWorktree'sshouldActivate→notifyActivateWorktree→ui:activateWorktreeIPC → renderersetActiveWorktree, switching the user's active tab to every new worker as the director created it.#29 added
suppressActivationto the in-app renderer launch functions, but never covered this CLI → IPC path.The fix — auto-suppress when the create originates from a director worktree
When
orca worktree createruns from within an Orcastrator/director worktree (the director spawning a worker), the agent/run-hooks-derived activation is suppressed:activate: falseis sent, sonotifyActivateWorktreeis simply never called. The worktree is still created, its agent spawned, and revealed in the sidebar + Mission Control — only the active-tab switch is skipped.--activate→ overrides the suppression (still activates).Which layer & why
CLI layer — the smallest change that reuses the existing main-side
shouldActivategate with no IPC/renderer changes and no focus-steal becausenotifyActivateWorktreeisn't called. The CLI is also the only layer that can distinguish an explicit--activatefrom the derived--agent/--run-hooksactivation, which is required for the override rule.Director identity is the durable worktree
displayNameprefix"Orcastrator · "(the same restart-surviving marker the sidebar uses to reattach directors). It's moved tosrc/shared/orchestrator-identity.tsso the CLI and renderer share one constant. The CLI already resolves the originating worktree from cwd for lineage; that same lookup now also reports whether the origin is a director — no extra round-trip.Tests (fail without the fix)
In
src/cli/index.test.ts:--agent→activate: falsebut still created/revealed (this one fails onmain).--agent→activate: true(no regression).--agent --activate→activate: true(explicit override wins).Verification
typecheck ✓ ·
pnpm test(20504 passed; the only failures were 2 flakynode-pty-fd-leaknative tests that pass in isolation, unrelated) ✓ · oxlint on changed files ✓ ·build:cli+ electron-vite build ✓🤖 Generated with Claude Code