Repository navigation
fix(workspace): scope Switch Agents and Close Old Agents by project tab - #909
Conversation
…e Old Agents Refs #908 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vtjk6o4nukQp7Vfbt5TDc
Both scope pickers grouped agents by working directory, a fallback from before Grid Dispatch gave every tab a stable letter plus title. That split each worktree into a pseudo-project, so "everyone in this project" was not selectable exactly when a bulk switch is needed. One shared derivation now lists tabs in Dispatch order with the Dispatch label, keeps worktrees visible as directories inside the project, and owns the membership rule for both modals. Refs #908 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vtjk6o4nukQp7Vfbt5TDc
Refs #908 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vtjk6o4nukQp7Vfbt5TDc
Rename the bulk toggle's stale parameter, count only tabs that still exist in "N selected", drop the redundant title clause from the project filter, import the basename helper from its owner, make the ordering test decide by population rather than a tie, and drive the selected-scope path through the real modal so the checkbox-to-preview wiring that carried #908 has a component-level regression test. Refs #908 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vtjk6o4nukQp7Vfbt5TDc
|
Review pass (one orchestrated Claude Code reviewer, read-only, from the fix worktree): APPROVE WITH COMMENTS, no blocking findings. It verified selection consistency in both modals, the per-kill revalidation in Close Old Agents, the Dispatch label vocabulary, the sort-change consumers, and ran Its six non-blocking comments are all taken in the follow-up commit: stale |
…ose-safety Brings the agent-close safety work (#153, #886) onto current main. The only textual conflict was the CloseOldAgentsModal import block: main (#908/#909) added the tab-keyed project scope helpers and tabIndexLabel, while this branch added sessionDisplayTitle for per-agent row titles. Both are kept. The per-kill onlyIf revalidation reuses filterMatchingRows, which main now routes through rowsInSelectedProjects, so the bulk-close grant is re-checked against the tab-id project scope main introduced rather than the old cwd scope. pane.ts, undoClose.ts and hook/index.ts merged cleanly: main's changes there (MCP overrides, TLDR identity, provider runtime for orchestration children, extracted transcript hydration) do not overlap the close paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S4AoJJUBex14FAEZZfHPsV
Main's #908/#909 re-keyed the Close Old Agents project picker from working directory to project tab and labels each row like the Dispatch index (`A · Project`). This branch's #886 regression test still located the checkbox by the retired cwd label (`project /project`), so it failed after the merge even though the behavior it guards is unchanged: nothing closes until a project is ticked, ticking it admits exactly that project's agents, and an invalid threshold closes nothing. The matcher now derives the label from projectScopeLabel, the picker's own source of truth, so the test follows the vocabulary rather than a string snapshot of it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S4AoJJUBex14FAEZZfHPsV
Problem
The Selected projects scope in Switch Agents (bulk provider switch) and Close Old Agents grouped agents by working directory, keyed by the full path and labelled by the folder name. An agent in
.worktrees/grok-package-wiringtherefore showed up as a project called "grok-package-wiring", and a project tab with agents in several worktrees was shredded into one entry per directory. There was no way to say "every agent in this project" in one click, which is the whole point of the bulk switch when a provider's window is exhausted.This was never a product decision. Both modals were written in June, before Grid Dispatch rows had project bindings, when the tab title was the only project label and was not unique.
Implemented behavior
A · agent-code,E · agent-code), in tab order.matching/totalcount per tab.E · agent-code · /path) instead oftab 5.Design decisions
features/workspace/lib/projectScope.ts) owns grouping, labelling, filtering and membership for both modals, replacing two copy-pastedProjectRowimplementations. Labels come from the sametabIndexLabelthe Dispatch row filter uses, so no third vocabulary is introduced.Linked issues
Fixes #908
Tests and verification
projectScope.test.ts(new): two agents in one tab across different worktrees produce one entry with both directories; same-titled tabs get distinct letters and keep tab order regardless of counts;matchingcounts only the eligible rows; the filter finds a project by its worktree name; membership filters by tab.CloseOldAgentsModal.rows,BulkProviderSwitchModal.policyandclosedModalDerivationsrenderer suites pass unchanged.tsc -bclean on both projects under Node 24;npm run test:contractsatisfied.Known limitations
🤖 Generated with Claude Code
https://claude.ai/code/session_016vtjk6o4nukQp7Vfbt5TDc