* fix(core): ride indivisible transcript pages over the read budget
Backward history pagination dead-ended with HTTP 413 whenever a single
turn exceeded the 4 MiB page budget: a turn cannot be split across
pages, so the reader threw SessionTranscriptPageTooLargeError and the
Web Shell latched a permanent pagination error banner. Take at least
one indivisible unit per page (one aggregate record forward, one turn
backward) so pagination always makes progress; the 32 MiB response
serialization cap remains the hard ceiling.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(web-shell): add retry button for history pagination error
A non-retryable transcript page failure (4xx, partial replay) latched
paginationError with no in-UI recovery short of reloading the session.
The banner now offers a retry that force-clears the latch and refetches
the same page, whose cursor was never advanced by the failed attempt.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(cli): add TUI image display tool
* fix(cli): report terminal image rendering failures
* fix(cli): disable Kitty placeholders in Warp
* fix(cli): constrain terminal image previews
* fix(core): preserve fork image tool cache prefix
* fix(cli): address display_image review feedback (#8217)
Add the missing DisplayImage zh/zh-TW locale entries (and en for parity)
that broke the i18n guard test, detect chafa via a PATH lookup instead of a
synchronous probe render during display_image execution, and reject
truncated PNGs by reading the full 24-byte header before reporting success.
* fix(web-shell): add display_image to tool display contract (#8217)
* test(cli): cover display image validation edges
* fix(cli): harden chafa executable lookup (#8217)
Resolve chafa through the mermaid renderer's hardened findExecutable and
spawn the resolved path, so a project-local node_modules/.bin/chafa is
never executed unless the user opted in. display_image is a
non-prompting Read tool, so the previous bare-name PATH resolution
allowed arbitrary code execution from a malicious repository.
Also add review-requested coverage: isTerminalImageDisplay routing, the
truncated-PNG rejection branch, the chafa stderr fallback, and the Kitty
re-emit dedup guard.
* fix(cli): address TUI image display review feedback (#8217)
- Cache rendered terminal images (bounded LRU keyed on path, mtime, size,
shape, and renderer) so a terminal resize or a restored session no longer
re-reads the file or re-spawns chafa for every visible image.
- Reject cmd.exe metacharacters in the model-supplied path before spawning
chafa through a shell, closing a command-injection surface on Windows
.cmd/.bat shims.
- Bound a failing chafa's stderr to a capped first line before rendering it
into permanent scrollback.
- Enforce the main-agent-only display_image ban inside the tool execution
(isInForkExecution) and fail resolveForkExecutionAllowedTools closed when
display_image is advertised without a concrete allowlist.
- Move the fileName computation to its use site, drop misleading awaits on the
synchronous renderer, and add Kitty/Ghostty detection plus renderer cache,
truncation, and shell-metacharacter tests.
* fix(cli): preserve color in chafa image fallback
* feat(cli): render images directly in Warp
* fix(cli): disable native images in Warp
* test(cli): cover chafa shell path guard
* fix(cli): skip re-transmitting Kitty image payload on remount (#8217)
---------
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
* feat: visualize ordinary session plan execution
* fix(web-shell): complete plan workflow rendering
* fix: preserve authoritative plan state
* fix(core): isolate teammate todo state
* fix: reject ambiguous empty plan snapshots
* test(web-shell): cover workflow dialog wiring
* feat(web-shell): preview workflow before execution
* feat(web-shell): inspect workflow step details
* feat(web-shell): preserve session workflow history
* test: align failing CI tests with plan-isolation behavior
SubAgentTracker: the emitter now guards subagent TodoWrite results
(tool-call-emitter emitResult early-returns on subagentMeta), so a
subagent todo no longer promotes into a session-level plan. Flip the
stale assertion to expect no plan emission, mirroring the dedicated
guard test in tool-call-emitter.test.ts.
HistoricalPlanExecution: the pagination fixture's onLoadOlderHistory
returned Promise<void>, but PlanExecutionHistoryProvider requires
Promise<boolean> and throws 'Unable to load earlier session history'
on a falsy resolution. Production wires loadOlderHistory (resolves
true after layout); return true in the fixture to model a successful
load.
* refactor: simplify session plan execution workflow
* fix(web-shell): preserve split plan approval workflow
---------
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
* feat(web-shell): support mutable default mid-turn messages
* fix(serve): register mid-turn removal telemetry route
* test(serve): update telemetry route totals
* fix(test): add session_mid_turn_message_mutation to expected features list
* fix(webui): forward clientId on cross-session mid-turn removal (#8229)
- Forward the session clientId in the cross-session removeMidTurnMessage
branch so the bridge's exact-originator match can succeed; without it the
removal resolved to an undefined originator and could never remove the
message stamped at enqueue.
- Strip a misaligned/malformed messageIds from mid_turn_message_injected in
asKnownDaemonEvent instead of rejecting the whole event, mirroring the
sidechannel parser so a buggy daemon can't silently lose the injection
signal.
- Log a mid-turn removal miss in the bridge like the enqueue/pending-removal
siblings, to make removal races diagnosable from daemon logs.
* fix(web-shell): exclude annotations from mid-turn path and harden idle cleanup (#8229)
* fix(web-shell): add container-type to .queuedPrompts so @container query applies (#8229)
* fix(web-shell): harden mid-turn dedupe and capability gate per review (#8229)
- removeInjectedFromQueue now matches by id first (position-independent)
and falls back to text only when no id match exists, so two same-text
sends can't remove the wrong row and double-deliver.
- Thread canMutateMidTurn into useQueuedPrompts and gate the mid-turn
delete/edit mutation on it, so the keyboard path can't hit a DELETE
route the daemon doesn't advertise.
- asMidTurnMessageInjectedData omits a malformed messageIds key instead
of leaving a present undefined, matching the sidechannel parser.
- Narrow MidTurnQueueItem.midTurnState, document the load-bearing effect
order, and make clearQueuedPrompts return false on a no-op clear.
* fix: harden mid-turn removal per review (log escape, cross-session client id) (#8229)
- Escape the caller-controlled messageId (and sessionId) in the mid-turn
removal-miss stderr line to prevent log injection (CWE-117).
- Forward the target session's persisted client id on cross-session mid-turn
removal so the bridge's exact-originator match no longer rejects valid
removals after a session switch with per-session client ids.
- Strengthen tests: distinct-id independence for two queued messages, deferred
removal proving the composer waits for daemon removal, and the active-turn
delete failed-action flag.
---------
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
* fix(web-shell): deduplicate permission options with same display label
When the server sends duplicate permission options (e.g. two allow_once
entries with identical labels), the Web Shell renders duplicate buttons.
Add a deduplicateByLabel pass after ordering to collapse options that
resolve to the same i18n key or raw label, keeping the first occurrence.
Fixes#8248
* fix(web-shell): deduplicate permission options by id, not i18n category (#8250)
* fix(web-shell): prefer server-provided option labels over i18n override (#8250)
* fix(web-shell): use data-option-id for ordering test assertions (#8250)
* fix(web-shell): document server-label precedence and test empty-label fallback (#8250)
* fix(web-shell): reuse memoized display options for initial selection (#8250)
* fix(web-shell): localize permission options, using server label only on i18n-key collision (#8250)
* test(web-shell): re-add label assertions to option ordering test (#8250)
* fix(web-shell): localize plan-mode restore option, never render blank option (#8250)
Give restore_previous its own i18n key so plan mode stops colliding with proceed_once and renders fully localized in every language. The collision fallback now degrades an empty server label to the localized string instead of an unlabeled button, and the selection reset stays keyed to request identity so a mid-request option change cannot re-enable a second confirm.
* test(web-shell): cover collision guard server-label fallback (#8250)
* test(web-shell): guard reset-effect lifecycle and double-submit in ToolApproval (#8250)
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
* fix(web-shell): stabilize mobile composer effects
* fix(web-shell): tear down all specular listeners on WebGL context loss (#8263)
---------
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
* feat(web-shell): add artifact downloads
* fix(web-shell): scope review download state per file and cancel on unmount (#8234)
* fix(web-shell): restore mount ref under StrictMode and test review MIME mapping (#8234)
Reset mountedRef in the effect setup so React StrictMode's dev-time
double-mount no longer leaves it false and silently cancels artifact and
review downloads. Move getReviewDownloadMimeType into artifactUtils and
cover the extension-to-MIME mapping with a unit test.
* test(web-shell): cover ReviewChanges cancellation-on-unmount path (#8234)
* test(web-shell): assert artifact download MIME type (#8234)
---------
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
The toolbar popover used a fixed 18rem width, truncating long model
names in the dropdown list. Change to max-content so the popover
adapts to its content width (capped at the available viewport width).
Also add title attributes on dropdown items and the model trigger
button so the full name is accessible via hover and screen readers.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
SubAgent type identifiers (general-purpose, Explore, etc.) were rendered
verbatim in the UI. Add agentType.* i18n keys and a localizeAgentTypeName()
helper so Chinese users see 通用/探索/状态栏设置 instead of raw English
identifiers. User-defined agent names still display as-is.
* feat(web-shell): add contextual task panels
* fix(web-shell): harden contextual task panels
* fix(web-shell): preserve side task titles
* fix(web-shell): address review feedback on context panels PR (#7929)
- Add POST /session/:id/side-task to telemetry route catalog (51 routes)
- Increase SDK browser bundle size limit to 184KB
- Fix duplicated data-testid="chat-pane" → "chat-pane-container" on container
- Gate sourceType behind session_source_metadata capability check
- Add removeSession cleanup after killSession in !res.writable path
- Add i18n key sideTask.renameFailed for error fallback
- Add unit tests for selectVisibleHistoryRecords invariant
* fix(cli): update telemetry-catalog route drift guard to 51 routes (#7929)
* fix(web-shell): address review feedback round 2 on context panels PR (#7929)
- Fix /fork sider discarding createSideTask() return value: show toast
when side tasks are unavailable
- Fix layout feedback loop: availableWidth no longer depends on
environmentPanelVisible since the CSS overlay does not change the
chat pane DOM width
- Remove dead environmentPanelSuppressed state (never set to true)
- Restore setArtifactPanelOpen(false) in closeArtifactPanelTab when
the last tab is closed
- Extract agentDisplayName(task) to a local variable to avoid triple
invocation per render
* fix(web-shell): dedupe completed background agents in environment panel (#7929)
getEnvironmentAgentTasks correlated a transcript tool card with the live
/tasks snapshot only on toolUseId, the notification taskId, and a
<subagentType>-<callId> derived id. A completed background agent can lose
that linkage (its live task carries no usable toolUseId and its daemon id
is general-purpose-<internalId>), so the trailing loop appended the live
task as a second entry. Add a conservative content fallback (prompt, or
description+subagentType) mirroring the daemon's legacy resolver.
* feat(web-shell): support side tasks during active turns
* fix(web-shell): deduplicate completed subagents and gate sourceType on capability (#7929)
* fix(web-shell): restore background agent reconciliation and fix agent dedupe (#7929)
Restore the one-shot subagent reconciliation for inline background Agent tool
cards. Persisted notification records do not always retain a toolUseId, so the
SSE discrete-notification path alone can leave a card stuck in Running; the
documented fallback resolves pending cards through the subagent endpoint after
catch-up, reconnect, and terminal notifications.
Also stop the loose description content fallback in getEnvironmentAgentTasks
from claiming a live task that another transcript tool call already links
precisely (by toolUseId, message taskId, or derived id). Two agents sharing a
description previously collapsed into one: the fallback stole the linked task,
its owner re-matched the same task, and the orphan was dropped.
* fix(web-shell): address critical review feedback on context panels (#7929)
* fix(web-shell): reconcile side-task state across sessions and listings (#7929)
* fix(web-shell): preserve contextual panel fallbacks
---------
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
* feat(web-shell): add split pane header action slot with overflow
Let hosts render per-session actions in each split pane header, collapsing them into a … menu when the pane is too narrow.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs(web-shell): add pane header actions PR screenshots
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): tighten pane header overflow measurement
Drop the per-render children effect dependency that rebuilt ResizeObserver during streaming, and reserve workspace-tag width when computing available header space.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): address pane header overflow review blockers
Mount host actions in only one tree, and wrap overflow entries as DropdownMenuItems so Radix selection and keyboard navigation work.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): keep pane header actions alive across overflow
Flatten Fragment host actions before building the overflow menu, and keep the same host instances mounted when collapsing so stateful actions are not reset.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): address pane header overflow review suggestions (#7808)
* fix(web-shell): proxy overflow clicks via action slots
Wrap host pane actions in stable slots so the overflow menu can activate interactive descendants without requiring opaque custom components to forward internal data attributes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): address overflow menu review suggestions (#7808)
* fix(web-shell): harden pane header overflow actions (#7808)
Restore the 8px gap between the built-in maximize/close controls, ignore
aria-hidden glyphs when labelling overflow items, omit non-interactive
children from the overflow menu, and document the popover constraint on
renderHeaderActions. Refreshes the design doc to match the mount-once
implementation.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
* fix(web-shell): preserve session URL context
* fix(web-shell): keep daemon token out of the session URL (#7926)
Restore the daemon token stripping that was dropped alongside the
base-path fix: removeDaemonTokenFromUrl() on startup and the ?token=
delete in replaceStandaloneSessionUrl. The ?token= query path is still
supported for backward compatibility, so without stripping it leaks into
the address bar, history, access logs, and Referer headers.
Also extract the session pathname building into buildSessionPathname()
with unit tests covering root/sub-path deployments, the no-session case,
trailing slashes, and id encoding.
* fix(web-shell): anchor session URL parser to agree with writer (#7926)
Extract parseSessionId() next to buildSessionPathname() and anchor it to the last /session/<id> segment so the parser agrees with the greedy writer. Previously a base path ending in a session segment produced /app/session/session/<id>, which the first-match parser read back as the literal id "session". Add round-trip and trailing-slash coverage.
* test(web-shell): cover parseSessionId malformed-encoding catch branch (#7926)
* fix(web-shell): preserve base path in split-view URL (#7926)
---------
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
* feat(web-shell): add git branch picker, commit dialog, and create PR flow
Add an IntelliJ-style branch picker popover to the web shell git
workspace, accessible from the branch chip in both the composer toolbar
and sidebar. The picker provides search-filtered branch listing (local,
remote, tags, recent), branch checkout, new branch creation, pull, push,
and a commit view integrated into the existing GitDialog.
The commit view reuses the diff panel (expandable file diffs with syntax
highlighting, fullscreen support) and adds a commit message textarea with
Commit / Commit and Push buttons. When a session is available (or one is
auto-created), the commit message and PR title/body are generated via the
model using session side-queries (btwSession), giving the agent full
conversation context for accurate generation.
The Create PR flow provides an inline form with auto-detected base branch
and model-generated title/description, backed by a new daemon route that
shells out to gh pr create.
New daemon routes:
- GET /workspaces/:workspace/git/branches
- POST /workspaces/:workspace/git/checkout
- POST /workspaces/:workspace/git/branch
- POST /workspaces/:workspace/git/push
- POST /workspaces/:workspace/git/pull
- POST /workspaces/:workspace/git/commit
- POST /workspaces/:workspace/github/prs/create
- GET /workspaces/:workspace/github/default-branch
* fix(web-shell): resolve correct workspace session for AI generation
The commit message and PR title/body generation now resolves the
most recent session for the target workspace via listWorkspaceSessions,
rather than using the globally active connection.sessionId which may
belong to a different workspace or session. Falls back to creating a
new session only when no sessions exist for the workspace.
Also improves the PR body editor with an Edit/Preview toggle using
the existing Markdown component, and updates the generation prompt
to follow the project PR template structure from AGENTS.md.
* fix(web-shell): stabilize session resolver prop to prevent infinite re-generation
Pass resolveSessionForWorkspace as a stable useCallback reference
instead of an inline arrow function. The inline function created a
new reference on every App render, causing the GitDialog useEffect
to abort and restart generation in an infinite loop.
* fix(web-shell): group remote branches by remote name and add PR target branch dropdown
Remote branches in the branch picker are now grouped by remote
(origin, upstream, etc.) with sub-headers, making fork workflows
clear. The PR create form's base branch field is now a select
dropdown populated from the workspace's branch list, grouped by
remote with optgroup labels, instead of a free-text input.
* fix(web-shell): use ref for session resolver to prevent effect re-run abort
When resolveSessionForWorkspace creates a new session, it updates
connection.sessionId in the provider, which changes the useCallback
reference, which triggers the useEffect to re-run and abort the
in-flight btwSession generation. Store the callback in a ref so the
effect never depends on its identity.
* fix(web-shell): resolve session per workspace, not from global active session
The commit/PR generation effects used connection.sessionId directly
without checking if it belongs to the target workspace. When opening
the commit dialog from a sidebar workspace different from the active
session's workspace, the wrong session was used for generation,
producing incorrect content. Now always routes through
resolveSessionForWorkspace(workspaceCwd) which checks workspace
membership before reusing the active session.
Also replaces 'PR' with 'Pull Request' / '合并请求' in all UI strings
and adds error logging to the generation catch blocks.
* fix(web-shell): retry btwSession with fresh session when stale session detected
When listWorkspaceSessions returns a session that no longer exists in
the daemon's memory (e.g. after daemon restart), btwSession fails with
'No session with id ...'. The generation effects now catch this error,
force-create a new session via resolveSessionForWorkspace(cwd, true),
and retry the btwSession call once. Both btwWithRetry and
resolveSessionForWorkspace are stored in refs to avoid useEffect
dependency chain aborts.
* fix(web-shell): base PR generation on branch diff, not working tree
PR title/body generation now fetches the commit log between the
resolved base branch and HEAD (git log <base>..HEAD) plus any
uncommitted changes, instead of only the working tree diff. The
base branch is resolved inside the effect's promise chain (not
from state) to avoid stale values and dependency warnings. Also
adds range parameter support to fetchGitLog and workspaceGitLog.
* feat(web-shell): replace PR base branch select with searchable popover
The native <select> for the PR target branch is replaced with a
custom searchable popover (BranchSelect) that shows a search input
and a filtered branch list grouped by remote. The default selection
is the target repository's main branch (resolved via
getDefaultBranch). Supports filtering by typing in the search box.
* fix(web-shell): show full remote ref in branch select (origin/main)
Branch select now stores and displays full remote refs like
origin/main instead of stripped names. getDefaultBranch returns
the full ref (origin/main) instead of stripping the prefix.
When creating the PR, the remote prefix is stripped for the
gh pr create --base flag (origin/main → main).
* fix(web-shell): stop pointer propagation in branch picker list to prevent popover dismiss
Radix Popover's outside-click detection was incorrectly firing when
clicking section headers (Recent/Local/Remote/Tags) inside the popover
content, causing the popover to close immediately. Adding
onPointerDown stopPropagation on the list container prevents pointer
events from reaching Radix's document-level handlers.
* fix(web-shell): use onPointerDownOutside guard for branch picker popover
The previous stopPropagation approach failed because Radix Popover
uses capture-phase document listeners for outside-click detection,
which fire before bubble-phase stopPropagation. The correct fix is
onPointerDownOutside on PopoverContent: when Radix incorrectly fires
the outside handler for a click that is actually inside the content
(can happen with portal containers), we check contentRef.contains()
and preventDefault to keep the popover open.
* fix(web-shell): stop click propagation on branch picker popover content
Root cause: the ChatEditor composer container has onClick that calls
core.focus(), stealing focus from the popover. React synthetic events
bubble through the React tree (not DOM tree), so portaled popover
clicks reach the container handler. Radix then detects focus-outside
and dismisses the popover.
Fix: onClick stopPropagation on PopoverContent, matching the existing
pattern in GitModePopover and ToolbarPopover which already have this
fix with an explanatory comment.
* docs: add PR verification screenshots for branch picker feature
* fix(web-shell): mock useWorkspace in tests for BranchPickerPopover
BranchPickerPopover calls useWorkspace() which requires
DaemonWorkspaceProvider context. The existing WorkspaceSection and
ChatEditor tests didn't provide this context, causing 5 test failures.
Added vi.mock with importActual to preserve other exports while
providing a mock useWorkspace. Also updated the git chip click test
to reflect that clicking now opens the branch picker popover instead
of directly calling onOpenGitDiff.
* fix: harden git write paths against argument injection
Address review feedback on the web-shell git surface:
- Reject option/pathspec injection in git checkout ref and branch start
point (isValidCheckoutRef), and terminate `git checkout` argv with `--`.
- Drop `git log` range values that start with `-` and terminate the argv
with `--` so a range can never be reinterpreted as `--output=<file>`.
- Fix getDefaultBranch always falling back to origin/main: the promisified
exec lacked `encoding: 'utf8'`, so stdout was a Buffer and .trim() threw.
- Parameterize ghErrorMessage so `gh pr create` timeouts name the right
command and duration; sanitize workspace paths in PR-create errors.
- GitDialog: guard doCommit against double-submit (button + keyboard), and
strip only a known remote prefix from the PR base so local branches with
"/" are not mangled; use theme tokens for commit button/success colors.
- BranchPickerPopover: guard checkout/new-branch behind busyAction, reset
inline-input text on reopen, and hide the commit action when unavailable.
Adds regression tests for the checkout/branch validation and the git log
range guard.
* fix(web-shell): address review feedback on branch picker PR (#7731)
- Fix Commit+Push error masking: split try/catch so push failure
reports alongside the successful commit SHA
- Replace hardcoded screenshot path with captureScreenshot harness
- Replace silent if-isVisible skip with explicit assertion in visual test
- Add focus-visible style for search input accessibility
- Fix CSS specificity for active PR tab hover state
- Add viewChanges to actionsVisible search filter
- Wrap toggleSection in useCallback to avoid unnecessary re-renders
- Add windowsHide: true to getDefaultBranch subprocess
- Fix trailing slash handling in mockDaemon git action routing
- Add git methods to top-level client mock in tests
- Remove dead branchPicker.commitSuccess i18n key
- Remove dead .actionShortcut CSS class
- Show generation failure feedback in commit message placeholder
* fix(web-shell): address review feedback on branch picker PR (#7731)
- Add workspace trust checks to bound git branch routes
- Use workspace-scoped client in BranchPickerPopover (fixes wrong-workspace mutation)
- Add branch name validation and -- terminator to gitCreateBranch
- Filter refs/remotes/*/HEAD from branch listings
- Force LC_ALL=C for reflog parsing (non-English locale fix)
- Narrow 'could not resolve' error regex to avoid DNS false positives
- Add range validation to git log (reject path traversal)
- Fix commit+push error i18n (dedicated key instead of concatenation)
- Add i18n for BranchSelect component strings
- Fix commit tab ARIA attributes
- Add onBranchChanged callback to handlePush
- Add btw to mockDaemon isDaemonPath regex
- Add workspace_github_prs to visuals spec capabilities
- Add -- terminator regression test
- Remove docs/pr-assets/ from repo
* fix(web-shell): address review feedback on branch picker PR (#7731)
* fix(cli): reject dash-prefixed branch name with 400 in branch route (#7731)
* fix(web-shell): address review feedback on git branch picker (#7731)
Security:
- Clear GIT_DIR/GIT_WORK_TREE/GIT_COMMON_DIR/GIT_INDEX_FILE from git
subprocess env to prevent repository redirection
- Add strict mutation gate to all POST git branch routes
- Add generation guard to qualified write routes
- Fail closed on invalid ?cwd= in mutation routes (resolveContainedCwdOrFail)
- Reject wrong-typed startPoint, fetchOnly, rebase, and PR options with 400
Correctness:
- Filter remote symbolic refs (origin/HEAD) by %(symref) instead of /HEAD
name suffix, preserving valid branches like feature/HEAD
- Add git rev-parse --git-dir probe so non-git dirs get 404 instead of
empty available:true
- Push preserves existing upstream; only adds --set-upstream when unset,
resolving the remote from branch config or the sole configured remote
- git commit -a replaced with git add -A + git commit so untracked files
displayed in the UI are included
- Always pass --body to gh pr create to prevent interactive prompts
- getDefaultBranch returns null instead of fabricating origin/main
- Memoize workspaceByCwd client in BranchPickerPopover to fix infinite
render loop
- Move sessionId to a ref in GitDialog effects to prevent self-abort
- Bound commit-message prompt to fit /btw 4096-char limit
- Mark all platforms as unverified in PR template (no fabricated ✅)
- Guard PR auto-fill effect against wiping user edits on reconnect
Accessibility:
- Add tabIndex and onKeyDown to commit-mode tab span
- Add aria-label to BranchSelect trigger and search input
Cleanup:
- Remove dead CSS (.prInputSmall, .prSelect)
- Remove 9 unused i18n keys
- Add ^ to git log range validation regex
- Add busyAction guard to handlePush/handlePull
- Add unit tests for gitCommit, gitPull, and route input validation
* fix(web-shell): address review feedback on git branch picker PR (#7731)
- Change commit tab from <span> to <button> for keyboard accessibility
- Move setCommitMsg('') to success-only branches so the message is
preserved when push fails after a successful commit
- Add mutate middleware and generationGuard to PR creation route,
matching all other POST mutation routes
- Set genFailed when session resolution returns undefined so the user
sees the failure indicator instead of a silent empty textarea
- Make PR number nullable when URL regex does not match instead of
returning a misleading 0
- Add LC_ALL=C and LANG=C to gitEnv() so for-each-ref upstream track
parsing is locale-independent
- Validate setUpstream and force as booleans in handlePush, matching
the existing validation in handlePull
- Add missing workspaceCwd and available fields to test mocks
- Use stable data-web-shell-git-branch attribute in e2e selector
* fix(web-shell): address R5 review feedback on git branch picker PR (#7731)
- Classify git errors on stdout+stderr instead of err.message to fix
false-positive no_upstream on every push failure and dead
nothing_to_commit classifier
- Sanitize workspace paths and cap error message length in sendGitError
- Fix remote branch checkout to strip remote prefix so git DWIM creates
a local tracking branch instead of detaching HEAD
- Restore keyboard accessibility on composer branch chip (span → button)
- Trim startPoint in handleCreateBranch before forwarding to git
- Return bare branch name from getDefaultBranch (strip remote prefix)
- Fix i18n shortcut hint to show ⌘/Ctrl+Enter for cross-platform
- Update aria-label to reflect git management menu, not just changes
- Add available: true to mockDaemon gitDiff default payload
- Add regression tests: upstream preservation, sole remote resolution,
strengthened fetch-only with divergent remote commit
- Add aria-expanded assertion to sidebar picker test
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(web-shell): address R6 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R7 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R8 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R9 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R10 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R11 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R12 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R13 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R14 review feedback on git branch picker PR (#7731)
* fix(web-shell): address R15 review feedback on git branch picker PR (#7731)
- Validate localName derived from remote-tracking ref to prevent option
injection (e.g. origin/-f → git checkout -f)
- Add gitCwd prop to BranchPickerPopover and pass it to all git SDK calls
so worktree sessions target the correct directory
- Add symlink-escape and non-existent-path tests for resolveContainedCwdOrFail
- Pin initial branch name in makeRepo() with git init -b master
- Add gitPull merge and rebase integration tests
* fix(web-shell): address git branch picker review feedback (#7731)
* fix(web-shell): address R6 review feedback on git branch picker PR (#7731)
* fix(web-shell): address review feedback on git branch picker PR (#7731)
- Strip GIT_CONFIG_GLOBAL/SYSTEM/NOSYSTEM in gitEnv to prevent
inherited config redirection (consistent with extension/github.ts)
- Pass gitCwd to workspaceGitBranches in GitDialog loadPrBranches
so worktree sessions fetch branches from the correct repository
- Add aria-expanded to collapsible branch section headers
- Add happy-path tests for PR create (201) and default-branch (200)
routes, including the null fallback to origin/main
* fix(cli): add sendGenerationClosedError to POST routes and cover untested branches (#7731)
* fix(web-shell): address review feedback on branch picker and PR creation (#7731)
- Refresh branch list after push/pull to avoid stale ahead/behind counts
- Add pre-flight check for unpushed branches before PR creation
- Fix base branch prefix stripping when branch list is unavailable
- Cap PR body file list at MAX_SUMMARY_CHARS to bound model prompt size
- Add qualified route tests: trust guard, input validation, cwd containment
* fix(web-shell): hoist MAX_SUMMARY_CHARS to module scope for PR body generation (#7731)
* fix(web-shell): address review feedback for git branch picker (#7731)
- Hoist onOpenCommit to useCallback to fix App.test.tsx prop stability test
- Keep commit tab visible after navigating away (startedInCommit ref)
- Add onClick handler to commit tab for navigation back to commit view
- Fix branch-prefix strip mangling local branch names containing '/'
- Update sessionIdRef after force-creating a stale session replacement
- Pin core.hooksPath in test makeRepo for reliable rollback tests
- Add test asserting --force-with-lease is used for force pushes
* fix(web-shell): target the worktree for sidebar commits and harden git actions (#7731)
Scope the sidebar commit dialog to the active session's worktree checkout
(matching the composer path) so linked-worktree sessions commit to the right
checkout, guard PR creation against a double-click race, and surface an error
when an invalid branch name is submitted. Adds focused coverage for the branch
picker action wiring and the git branch route validation paths.
* fix(web-shell): address review feedback for git branch picker (#7731)
---------
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code <qwen-code@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
* fix(web-shell): report intended workspace to host when starting a new chat
Clearing a session leaves connection.workspaceCwd pointing at the previous session's workspace. The onSessionIdChange notification read that stale value, so starting a new chat in workspace A routed the host back to the old workspace (e.g. one with a running task) and the composer showed the wrong workspace. With no active session, report the workspace picked for the next session instead.
* fix(web-shell): reuse activeWorkspaceCwd for the no-session host report (#7910)
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
* feat(web-shell): add native workspace folder picker
* fix(serve): harden native directory picker and add coverage (#7849)
Add a 5-minute timeout to each native picker subprocess and to the
webui action so a dismissed dialog cannot leave an orphaned GUI process,
and distinguish a headless Linux "cannot open display" failure from a
deliberate zenity cancellation. Cover pickNativeDirectory's platform
branches, the route's 501/500 error paths, and the dialog's picker
failure path with focused tests.
* fix(serve): log directory picker failures to daemon stderr (#7849)
* fix(serve): abort directory picker on client disconnect and stagger timeouts (#7849)
* test(webui): add unit tests for pickWorkspaceDirectory action (#7849)
* fix(serve): set UTF-8 console encoding for PowerShell picker and treat timeout kills as cancels (#7849)
* fix(serve): abort directory picker on response close, not request close (#7849)
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code CI <qwen-code-ci@users.noreply.github.com>
selectCodeBlock seeded lang from the first token before the loop that
classifies tokens. For '/copy 3' the one token was used twice: it set
lang to "3" and requestedIndex to 3, so the filter looked for blocks
written in a language called "3", found none, and returned early with
'No matching code block found' before the index was consulted.
The command's own argument hint advertises
'[code|<lang>|latex|inline-latex] [index]' with both groups optional, so
a bare index is a documented form - and it was the only one that failed.
Drop the pre-loop assignment. It was redundant: when the first token is
not 'code' it is already in selectorTokens, and the loop assigns lang for
every non-numeric token.
* feat(core): add full-resolution image zoom tool
* chore(vscode): refresh third-party notices
* fix(ui): satisfy zoom image display drift checks
* fix(web-shell): translate zoom image tool
* fix(core): wire sharp into packaging and load it lazily (#7809)
Externalize sharp in esbuild and declare it (plus the @img platform
binaries) in the published package's optionalDependencies so an
npm-installed CLI resolves the native binding. Import sharp dynamically
inside execute() so a missing binding returns a bounded tool error
instead of crashing startup during strict tool warmup, and so the module
is only loaded when zoom_image actually runs. Also pin the EXIF
auto-orientation test with a discriminating fixture and cover the
.qwenignore and y1>=y2 validation paths.
* fix(core): gate zoom_image at execute time and cap tiny-crop upscale (#7809)
Register zoom_image unconditionally and move the image-modality check to
execute time so first-run sessions and hot /model switches resolve the
tool without re-running initialize(). Cap magnification at 8x so a tiny
crop no longer inflates to the full image-token budget. Drop the redundant
@img/* platform pins; sharp's own optionalDependencies install the matching
binary for each OS/arch.
* fix(core): emit zoom_image file telemetry and cover guard branches (#7809)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: qwen-code-autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>