Skip to content

fix(activate): target title-bar commands to their click-origin instance - #1528

Draft
easonLiangWorldedtech wants to merge 1 commit into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:vps2/f0-button-targeting
Draft

fix(activate): target title-bar commands to their click-origin instance#1528
easonLiangWorldedtech wants to merge 1 commit into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:vps2/f0-button-targeting

Conversation

@easonLiangWorldedtech

@easonLiangWorldedtech easonLiangWorldedtech commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Part of the vps2 durable per-view state series — tracked in easonLiangWorldedtech#41 (cross-repo: this PR is standalone against upstream/main @ 0d937c0).

Issue (created at PR-open time): #1529

What

All title-bar commands (+ / Settings / History / Marketplace / popout / focus) resolve to a single surface-blind "visible" ClineProvider instance, and setPanel's mutual wipe of the sidebar/tab slots leaves stale references once a tab and the sidebar coexist. This PR makes each title-bar command target the instance its click originated from:

  • setPanel no longer wipes the other slot (each branch assigns only its own slot); the exported setPanel / getPanel signatures are kept.
  • The four sidebar title-bar handlers target the click-origin provider that registerCommands was handed.
  • Four new *InTab command ids (packages/types/src/vscode.ts) rewire the editor/title menu, reusing the existing i18n keys/icons (zero new strings); the tab handlers resolve the owning instance via the new static ClineProvider.getInstanceForView(panel) (identity match over activeInstances) instead of the surface-blind getVisibleInstance.
  • openClineInNewTab reuses the live tracked tab panel (reveal + didBecomeVisible post) instead of unconditionally creating a new provider + panel.
  • The focusInput post condition is sidebarPanel && !tabPanel.

Design decisions

  • D1 (mutual wipe): fixed by the no-wipe setPanel. The sidebar onDidDispose asymmetry (the sidebar slot is never cleared) is pre-existing and retained; with no-wipe a stale slot resolves to a disposed instance via getInstanceForView, and the InTab handlers then no-op safely.
  • D2 (no tab reuse): fixed by the panel reuse via getInstanceForView.
  • D3 (surface-blind targeting): the five title-bar commands are contributed to both view/title and editor/title in package.json (verified by the Phase-0 A6 audit); the editor/title entries are rewired to the *InTab ids.
  • D4 (focusPanel tab-first resolution): self-resolves once the no-wipe lands — focusPanel.ts is deliberately unchanged (no spec exists for it).
  • zoo-code.newTask (command-palette only) intentionally stays on the visible-provider path (focus-sidebar fallback); documented as a known limitation below.
  • Webview-originated actions are per-instance by construction (setWebviewMessageListener wires this); the single leak (focusPanelRequest) is out of scope here.

Measurements

  • a+d vs upstream/main @ 0d937c0: 484 (411+/73−) — over the 400 soft budget by 112: the mutation gate required per-post distinct-error catch pinning, an awaited InTab no-op matrix (all four commands), and real-class getInstanceForView coverage (registerCommands.spec auto-mocks ClineProvider, so the real find callback had no coverage). Under the 600 hard cap. Composition: ~372 first-cut (impl + spec) + ~112 mutation-killing tests.
  • src executable lines: 144 a+d (registerCommands.ts 99+/27−, ClineProvider.ts 10+, packages/types 8+) — inside the ~300 mutation preflight.

Gates

  • eslint --prune-suppressions: pass (suppression counts unchanged; prune-only reindent reverted)
  • check-types: pass (13 packages)
  • vitest: registerCommands.spec.ts 36 pass; ClineProvider.spec.ts 155 pass; packages/types 5 pass
  • stryker-diff ci @ 0d937c0: 72/72 killed, 0 surviving, 0 uncovered, 0 blocking (registerCommands.ts + ClineProvider.ts)
  • e2e / i18n / visual: n/a (zero new i18n strings; no webview-ui changes)

Parked / documented

  • zoo-code.newTask stays on the visible-provider path (palette-only surface; focus-sidebar fallback).
  • The A6 audit's alternate minimal-fix design (public renderContext / getSurfaceProviderOrLog / active-surface-first getVisibleInstance) was considered and not adopted.

Porting notes

None — new fix (F0) identified by the Phase-0 A6 button-targeting audit; no hunks ported from the closed draft PRs.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • coderabbit-review-active

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: 0e89e060-143f-482e-bd5f-542f6801af97

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Review status

Thanks for contributing. This comment tracks the review sequence and the next action.

Current step: Mark the PR ready. Required CI must pass before CodeRabbit starts.

Review-state labels are managed by this workflow; do not edit them manually.

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.

2 participants