mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-11 12:12:19 -10:00
* feat(web-shell): show workspace overview and a workspace menu in the sidebar Workspace rows gain session counts, the full path and facet chips (MCP, skills, extensions, channels, context files) while expanded, plus a workspace menu with rename, copy path, new worktree task, management entries, reload runtime and remove. Facets are fetched per expanded trusted workspace through the existing workspace-qualified routes and an uninitialized runtime is never rendered as zero. Layer A of #10399. * fix(web-shell): address review of the workspace overview sidebar - e2e: call the mock daemon's replay helper with its object form - stop fetching facets behind a custom (locked) header renderer and for the synthetic fallback workspace, which has nothing to display them - keep a row's last session counts while it is collapsed - rename: accept the daemon's 256-character display-name cap and treat a failed capabilities refresh after a successful rename as converged - chips: use the sidebar's warning token and say "unavailable" rather than "not initialized" for daemon-side facets; drop the unread loading state - record the Trust… deferral and the measured fan-out cost in the design doc; pin the reviewed behaviours with tests (hooks facet, user-question attention, poll default, in-flight invalidation, copy path, reload feedback, overview opt-out, worktree task) * fix(web-shell): second review round for the workspace overview sidebar - context files are answered by the daemon from disk, so a workspace without a QWEN.md renders a known 0 instead of "not initialized" - offer "New worktree task" only when the git poll reports a branch - keep retained session counts only while the catalog query is disabled, not across a source switch on an expanded row - tests: daemon-rejected rename keeps the dialog open, clipboard stub is restored, the display-name cap is pinned exactly, worktree gating * fix(web-shell): third review round for the workspace overview sidebar - primary row shows no counts while its session source is switching, instead of the previous source's numbers - poll git whenever header actions are wired, so the worktree entry no longer depends on the diff handler being present - render no chips until the first overview round lands - tests: primary-removal guard, branch-gated worktree entry on a non-git secondary workspace, untrusted rows never fetch, MCP disabled-server arithmetic, context file count, in-progress discovery is not a failure, and a deterministic wait for Radix's outside-press listener * fix(web-shell): fourth review round for the workspace overview sidebar - retained session counts are tagged with the source they were computed for, so a collapsed row drops them after a global source switch - a locked sidebar with a custom header passes no header actions, so the section skips the git poll that only feeds them - tests: primary-row wiring (no session list) for the loading guard, attention badge and truncation marker, overview reaches header actions, skills/extensions/channels tooltips, locked rows never poll git * chore: restore teamHelpers.test.ts to main's formatting after merge * fix(web-shell): fifth review round for the workspace overview sidebar - an armed branch/worktree intent no longer resets on a transient git-status gap; only a session, an untrusted workspace, a no-branch answer or a draft workspace switch clears it - the workspace header action wrapper stays visible while its menu is open, so Escape returns focus to the trigger - the git poll runs only when a consumer of the branch is wired (diff chip or worktree entry outside a locked sidebar) - the worktree entry shares the new-task re-entrancy guard, busy state and catalog refresh - the menu's management section is one flat group; facet summaries are isolated per facet so a malformed body cannot blank the whole round - tests for each of the above plus the items/cwd/re-enable transitions, placeholder overwrite on merge, skills placeholder, and action order * fix(web-shell): sixth review round for the workspace overview sidebar - the sidebar's worktree arm is dropped when another session start ran while the creation was in flight - header totals honour the daemon's page-level truncated flag as well as a next cursor, on both the primary and secondary derivations - rename is offered on registration-backed rows only; the rename dialog refuses control characters before the request is sent - the header menu keeps the row's last overview snapshot while collapsed and its live counts are part of the items' accessible names - a custom header still fetches the overview when header actions consume it; a facet reads as unavailable after three unanswered rounds and a cwd change never carries the previous workspace's facets over - mock daemon: per-workspace overview facets; e2e asserts the secondary row's own counts and pins the 30 s poll with a fake clock - main-boot.test mocks the provider module main.tsx imports (also opened separately against main) * fix(web-shell): count unanswered overview rounds even when superseded The SDK's request deadline equals the overview poll cadence, so while a daemon hangs every round times out just after the next tick has replaced it and never reached the miss bookkeeping; facets could freeze on their pre-hang counts for the whole hang. Misses are now recorded for every round that lands, and a superseded round that observes an expiry drops those facets without merging its stale data. A round from a previous cwd is ignored entirely. * fix(web-shell): set the worktree intent with the draft it belongs to The sidebar's worktree entry armed the intent after createNewSession settled, guarded by a composer-version token. Two gaps remained: a prompt submitted while the previous session was still clearing read the reset intent and got the current branch, and a draft re-targeted through the sidebar during the await kept the token so the arm still landed. createNewSession now takes the git intent and writes both the state and the ref in the same synchronous step that resets the previous one, so the intent belongs to that draft from the start; the sidebar entry passes worktree and no post-await arm exists. The invalidation effect also re-runs on intent changes so an intent set while a session already exists is cleared at once. * fix(web-shell): keep an armed git intent across no-op and cross-workspace draft moves Two paths still dropped a worktree intent that nothing had invalidated. Re-selecting the draft's own workspace from the composer picker (Radix fires onValueChange for the checked row too) went through the draft branch of switchWorkspace and hit the reset added for real switches. The branch now compares the target with the selected workspace before it overwrites the ref and skips only the reset when they match; the cwd re-set and composer version bump stay as before. Arming a worktree intent from another workspace's row while the draft workspace had a definitive no-branch answer (a non-repo primary) was undone in the same commit: activeWorkspaceCwd already pointed at the new workspace but selectedWorkspaceGitStatus still held the old answer, which the git-status effect clears only after the commit. The reset check now keys the status by workspaceCwd, the same rule the git_status_changed mirror effect uses, so a status for a workspace being left never decides for the new one. A definitive no-branch answer for the draft's own workspace still clears the intent. * fix(web-shell): scope overview miss budgets to one bookkeeping session The miss bookkeeping in reload() runs for every landed round on purpose — during a daemon hang every round is superseded before it lands, and only their observed misses can expire a facet. But it also ran for rounds launched before a reset boundary: a round held in flight across a cwd round trip (A→B→A passes the cwd guard) or across a collapse/expand cycle landed after missesRef was reset and booked into the fresh session, shortening the three-round grace, or — landing successfully — refilled the budget so a frozen count outlived it. Budgets are now scoped by an epoch that advances at the two reset boundaries (cwd change, disable); a round captures the epoch at launch and books nothing if a reset happened while it was in flight. Rounds inside one unbroken session still all count, and the hang-expiry test pins that a per-round epoch bump would break.
33 lines
1.1 KiB
TypeScript
33 lines
1.1 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Qwen
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import type { DaemonWorkspaceGitStatus } from '@qwen-code/sdk/daemon';
|
|
|
|
/**
|
|
* Whether an armed git-mode intent (new branch / worktree) for the next
|
|
* session can no longer apply and must fall back to the current branch.
|
|
*
|
|
* Only definitive states reset it: a session already exists, the workspace
|
|
* is not trusted, or git status answered and reported no branch. A status
|
|
* that is merely absent — not fetched yet, or a poll round that failed — is
|
|
* transient and leaves the intent alone; otherwise one rejected refetch
|
|
* while a draft sits would silently turn a requested worktree task into a
|
|
* plain session in the main checkout.
|
|
*/
|
|
export function gitModeIntentMustReset({
|
|
sessionId,
|
|
workspaceTrusted,
|
|
gitStatus,
|
|
}: {
|
|
sessionId: string | null | undefined;
|
|
workspaceTrusted: boolean | undefined;
|
|
gitStatus: Pick<DaemonWorkspaceGitStatus, 'branch'> | undefined;
|
|
}): boolean {
|
|
if (sessionId) return true;
|
|
if (workspaceTrusted !== true) return true;
|
|
return gitStatus !== undefined && !gitStatus.branch;
|
|
}
|