test(webview): ClineProvider parallelMode suite with viewStates pruning edges - #1921
easonLiangWorldedtech wants to merge 26 commits into
Conversation
…en view-identity tests Track the in-flight tab panel creation with a module-level promise so concurrent openClineInNewTab calls reuse one panel and provider (adds a Promise.all regression test). ClineProvider.spec sets the private view via the public resolveWebviewView() instead of a ts-ignore assignment. registerCommands.spec types evictCurrentTask/refreshWorkspace on the fixture and drops the as any attachment. eslint-suppressions: prune the registerCommands.spec.ts entry (two as any suppressions removed).
…n the concurrency assertion
…-bar posts - openClineInNewTab: extract the unserialized creation body into createTabPanelUnlocked and guard the in-flight slot clear so a settled creation cannot clobber a replacement already stored in the slot. - onDidDispose: clear the tracked tab ref only when the disposing panel is still the tracked one, so a late disposal of a replaced panel cannot clobber the replacement's ref. - MDM lookup failure: log the fallback to the output channel instead of swallowing it silently. - Route the six title-bar button handlers through a shared postActions helper that posts each action in order and logs failures with the handler-specific prefix. - package.json: add the four InTab commands to the command palette, scoped to the active tab panel. - Tests: handler-level regression for openInNewTab + popoutButtonClicked started before the first creation resolves; fresh-creation test for a settled in-flight promise; stale-panel disposal regression; retained panel assertion for disposed tab instances; rightmost-editor column placement assertion; MDM fallback output assertion; %s placeholders for primitive it.each titles. - Stryker directives for the two equivalent setPanel type-literal mutants (setPanel branches only on type === sidebar).
Replace the weak toBeDefined() assertion in the dispose spec with an identity check against the panel returned during creation, per the CodeRabbit actionable comment on this PR (review run 7c4cfeb3-6dd9-4615- 9a58-70cfc705eca2). The tracked tab is now pinned with toBe(panel) before the dispose assertions, so a wrong or duplicated tracked panel fails the suite instead of passing a defined-only check. Upstream: Zoo-Code-Org#1528 (vps2 F0)
Retain the tracked tab panel in the InTab handler cases and assert that getInstanceForView was called with that exact panel, per the CodeRabbit actionable comment on this PR (review run 4afe1273-8739-4235-90d3-311db5f6ccb9, inline comment 3952466254 on the tabHandlerCases spec). A handler resolving any other view now fails instead of passing on the stubbed provider result alone; the same identity pin is applied to plusButtonClickedInTab. Upstream: Zoo-Code-Org#1528 (vps2 F0)
…States Each ClineProvider instance now owns a unique viewId (renderContext plus a monotonic counter) and registers a stable viewStateId for durable persistence. - Per-view state buffer (viewLocalState) holds mode / currentApiConfigName / apiConfiguration overrides in memory; saveViewState persists the non-secret subset durably under the active view id, rekeyed to the stable id on registration. - viewStates is stored as a map pruned to the newest 50 entries; writes go through a serialized queue so concurrent provider instances merge without lost updates. - setViewStateId sanitizes ids and rejects "__proto__" so a per-view entry can never be keyed through the Object.prototype setter. - postMessageToWebview no longer awaits the webview ack: a remounted or disposed page never acknowledges, and awaiting would wedge task-critical callers. - History restore falls back to the default mode view-locally instead of writing the shared global mode. - GlobalState gains the "viewStates" key and GLOBAL_STATE_KEYS tracks it. Adds F1a coverage in ClineProvider.spec.ts (viewId uniqueness, saveViewState persistence semantics, loadViewState fallback and failure, pruning, the __proto__ guard) and adapts the two history-restore tests in ClineProvider.sticky-mode.spec.ts to the view-local restore. getState() merging of hydrated per-view values and the remaining view-state suites land in the follow-up (F1b).
…lude viewStates from settings transfer
…ions through the view-local buffer
…nd target tab-instance commands Reapply in-flight view-local fields with Object.is identity so a field cleared during the load window stays cleared; route mode switches through setValue so the in-memory buffer and durable write agree, with rollback on failure; refresh cross-instance view-local state on profile upsert, activate and delete and re-pin the buffer after a delete; point focusInput and active-panel re-registration at the tracked tab provider and panel; log dropped webview postMessage failures with the message type; pin tab-instance, focusInput and active-panel identity in the registerCommands tests and type the mdm double in the provider spec.
…apture view pin on delete Address CodeRabbit walkthrough findings on the F1a unit: - handleModeSwitchUnlocked now bails before the task-level writes when the abort signal has fired, closing the partial-apply window where a cancelled switch could still rewrite the persisted task mode; the existing pre-write guard still covers in-flight aborts. - Replace bracket access to sibling-instance private members with a typed pinnedProfileName getter and direct private member access (compile-time safe across instances). - deleteProviderProfile now captures this view's pin before the currentApiConfigName rewrite so a view pinned to the deleted profile while the global selection points elsewhere is still reconfigured with the surviving profile's settings. Tests: focusInput asserts the tab panel by identity and that no error was logged on the success path; the stalled getProfile double fails loudly on a second lookup (only one lookup is resolvable).
…-local profile pins
handleModeSwitchUnlocked: an abort landing while updateTaskHistory is in flight previously left the new mode persisted in task history and assigned to task._taskMode before the pre-write signal check bailed; the landed write is now rolled back to the pre-switch item and the method returns before the TaskModeSwitched emit and the durable mode write. TaskModeSwitched now only fires for a completed transition. deleteProviderProfile: the unconditional setValue('currentApiConfigName', ...) overwrote a view's pin when an unrelated profile was deleted; the pin is now re-pointed only when it names the deleted profile, and a deleted-was-global deletion updates the shared store only. The nested apiConfiguration overlay is replaced with the surviving profile's settings only for a view pinned to the deleted profile.
…tore deleteProviderProfile pruned the UI-facing listApiConfigMeta entry but never removed the profile's settings from the ProviderSettingsManager store (context.secrets), so a later listApiConfigMeta sync could resurrect the deleted profile and a dangling per-mode mapping could re-activate it. The purge now calls providerSettingsManager.deleteConfig and branches on the typed ProviderSettingsNotFoundError (introduced here alongside) so an already-gone secret is an idempotent success -- the stale list entry is still pruned -- while any other failure (e.g. the store refusing to delete the last remaining configuration) propagates. Matching message text instead would let a profile whose name contains 'not found' swallow an unrelated failure. Tests: the dangling-mode-mapping resurrection scenario, the already-gone secret, the store-level last-profile refusal, the typed-signal contract in the manager spec, and provider-level not-found/propagation pins.
A failed task-history rollback during an aborted mode switch previously propagated into the outer persistence-error handler and surfaced as the switch's own persistence failure. Guard the rollback with its own try/catch so the rollback error is logged with task context and the cancellation return is preserved (CodeRabbit finding on this PR).
…d switch The in-flight abort rollback rewrote the whole task-history item with the pre-switch snapshot, clobbering any fields the running task persisted during the pending window (tokens, cost, status, apiConfigName). Re-read the item and restore only the mode this switch changed (CodeRabbit data-integrity finding on this PR).
Rebasing onto main tip merged main's createTabPanelUnlocked body with the PR's serialized creation. Main no longer resolves CodeIndexManager in this function, so the leftover line referenced an import the PR never added and the suite failed with ReferenceError. Removing it restores the PR's own delta: 48 registerCommands tests and 459 F1a tests pass.
…overrides Fold ClineProvider viewLocalState on top of ContextProxy values in getState() (mode, apiConfiguration, and all per-view fields) so each webview reports its own selections while falling back to shared global state for everything else. Ports the getState-merging and local-state-isolation spec coverage from the superseded vps2 source. Also pins the full default surface of the merged read path, including the apiConfiguration provider fill-in when provider settings sanitize the raw value away (mutation-diff gate).
Rebuilding the F1b unit as main tip + its own delta cleared the conflict with main. The patch was authored against an older main, so applying it dropped the alwaysDenyUnapprovedCommands entry from getState(); restoring it with the shared default constant keeps the settings round trip complete. 410 tests pass.
Applying the F1c delta (ad94239...8554307) onto the rebuilt F1b head cleared the conflict with main tip without changing content. 338 src tests and 39 webview-ui tests pass.
Part of the vps2 durable per-view state series, tracked in #41. Stacked on F2b. Content ported from the pinned source (kind: commit, base 8554307 -> head bff2a5c, PR Zoo-Code-Org#1555). Over the soft 400 a+d cap (739): one cohesive regression suite whose ~588 lines are shared mock setup for three describes.
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 21 minutes. View limit detailsLimit details: You’ve used all 4 included reviews currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (25)
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. Comment |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Review statusThanks for contributing. This comment tracks the review sequence and the next action. Current step: Required CI passed. Waiting for automated review of the latest commit. If automated review does not start, a maintainer must restart it. Review-state labels are managed by this workflow; do not edit them manually. |
The entry recorded 36 but the file only has 26 violations, so eslint exits 2 on stale suppressions. Same correction as unit F2a; the count is inherited from the shared content source.
Part of the vps2 durable per-view state series — tracked in easonLiangWorldedtech#41.
Unit F2c of the F2 split; supersedes #1555. Stacked on F2b. Content source of record:
kind: commit, base8554307ec-> headbff2a5ca8(PR #1555).Budget: 739 a+d standalone — over the soft 400 cap, under the hard 1000 cap. Rationale: one cohesive regression suite whose ~588 lines are shared mock setup for three describes; splitting the file would duplicate the setup rather than reduce what a reviewer reads. 0 changed executable lines. 3 tests pass.