Skip to content

fix(orchestration): don't steal active-tab focus when a director opens a worktree - #29

Merged
zaridan merged 1 commit into
mainfrom
zaridan/fix-orch-worktree-focus-steal
Jun 24, 2026
Merged

fix(orchestration): don't steal active-tab focus when a director opens a worktree#29
zaridan merged 1 commit into
mainfrom
zaridan/fix-orch-worktree-focus-steal

Conversation

@zaridan

@zaridan zaridan commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Problem

When an Orcastrator opens a worktree programmatically (the Smart/LLM director shell, the recipe director shell, or coordinator-spawned workers), Orca switched the user's active tab/view to the new worktree — yanking you away from whatever you were doing. Manual +-button creation should keep jumping to the new worktree; only automated creation should stay quiet.

This is an in-app active-tab switch, not an OS window raise (no mainWindow.show/focus fires on create — those are tray/second-instance/notification handlers only).

Root cause

  • worktrees.ts hardcoded activate: true for startup-bearing creates (programmatic director/worker creates always launch an agent → always hit this).
  • activateAndRevealWorktree (worktree-activation.ts) called state.setActiveWorktree(...) unconditionally. (Sidebar reveal was already optional.)

Fix

Add a suppressActivation flag, threaded from the programmatic create sites:

  • worktree-activation.ts: when set, reveal the worktree (sidebar tree + Mission Control) and seed its terminal surface, but skip the active repo/view/worktree switch, the focus-recency stamp, and the paired-host terminal wake (the SSH/web-runtime case — waking the host would pull it onto the worktree).
  • worktrees.ts: activate is now options?.suppressActivation !== true instead of hardcoded true.
  • Call sites pass suppressActivation: true: the Smart director launch (orchestrator-launch.ts), the director worktree shell (director-worktree-shell.ts), and the recipe director (recipe-director-launch.ts).

Manual +-button creation is unchanged — no flag, still activates and jumps to the new worktree.

Reveal vs. activate

The worktree still appears in the sidebar tree and Mission Control (reveal is preserved); it just doesn't grab the user's active view.

Tests

  • worktree-activation-suppress.test.ts: with suppressActivation: true, revealWorktreeInSidebar is called but setActiveWorktree is not; without the flag, both fire (preserves existing behavior). Fails without the fix.
  • director-worktree-shell / recipe-director-launch / orchestrator-launch tests assert the programmatic paths pass the flag.

🤖 Generated with Claude Code

…s a worktree

Programmatic Orcastrator/coordinator worktree creates (Smart director shell,
recipe director shell, coordinator workers) were yanking the user's active
tab/view to the newly-opened worktree. Root cause: the store hardcoded
`activate: true` for startup-bearing creates and `activateAndRevealWorktree`
called `setActiveWorktree` unconditionally.

Add a `suppressActivation` flag: when set, reveal the worktree (sidebar tree +
Mission Control) and seed its terminal surface, but do NOT switch the active
repo/view/worktree or wake the paired host onto it. Programmatic create sites
pass it; manual (+-button) creates leave it unset and still jump to the new
worktree as before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zaridan
zaridan merged commit ea36f4f into main Jun 24, 2026
1 check passed
@zaridan
zaridan deleted the zaridan/fix-orch-worktree-focus-steal branch June 24, 2026 17:40
zaridan added a commit that referenced this pull request Jun 24, 2026
…ns a worker via the CLI (#35)

* fix(orchestration): don't steal active-tab focus when a director spawns 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>

* fix(orchestration): suppress director focus-steal even with --no-parent --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>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zaridan added a commit that referenced this pull request Jun 25, 2026
#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant