Commit graph

325 commits

Author SHA1 Message Date
samuelhsin
26600896d5
feat(web-shell): add split pane header action slot with overflow (#7808)
* 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>
2026-07-29 13:06:48 +00:00
ytahdn
6672573433
fix(web-shell): reduce composer input latency (#8015)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-29 08:06:53 +00:00
ytahdn
a1a03fd7e7
fix(web-shell): prefer artifact type metadata in cards (#7973)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-29 07:57:45 +00:00
ytahdn
f485970d61
feat(web-shell): refine advanced table controls (#7999)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-29 07:37:30 +00:00
qqqys
7836c919bf
fix(web-shell): polish Channel pairing requests (#7997)
* fix(web-shell): polish Channel pairing requests

* fix(web-shell): localize pairing transport failures

---------

Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
2026-07-29 06:36:10 +00:00
ytahdn
2ab3681157
fix(web-shell): preserve token and base path in session URLs (#7926)
* 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>
2026-07-29 06:12:37 +00:00
zhangxy-zju
1d55d290a0
feat(web-shell): render streaming charts with markdown-chart (#7916)
* feat(web-shell): use markdown-chart for streaming charts

* fix(web-shell): address markdown chart review feedback

* fix(web-shell): preserve legacy chart ref caching

* fix(web-shell): preserve chart safety and loader stability

* test(web-shell): strengthen markdown chart safety contracts

* test(web-shell): cover legacy chart streaming adapter
2026-07-29 06:04:56 +00:00
qwen-code-ci-bot
3144046c6b
chore(release): v0.21.1 (#7958)
* chore(release): v0.21.1

* docs(changelog): sync for v0.21.1

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-29 00:25:30 +00:00
carffuca
54d3997add
feat(web-shell): suggest BTW for side questions (#7935)
* test(web-shell): define composer intent suggestions

* feat(web-shell): suggest btw for side questions

* test(web-shell): cover pasted image suggestion gating

* fix(web-shell): block btw suggestions for inline tags

* test(web-shell): verify inline attachment snapshots

* feat(web-shell): refine BTW intent suggestions
2026-07-28 15:55:09 +00:00
Shaojin Wen
dade3ab334
feat(web-shell): add git branch picker, commit dialog, and create PR flow (#7731)
* 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>
2026-07-28 14:25:11 +00:00
qqqys
1ada1b1fcd
feat(web-shell): manage Channel pairing requests (#7909)
Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
2026-07-28 13:41:42 +00:00
callmeYe
63166bd544
feat(web-shell): honor voice hold mode (#7839)
* feat(web-shell): honor voice hold mode

* fix(web-shell): finalize held voice after connecting

* fix(web-shell): buffer voice while connecting

* test(web-shell): cover voice buffer overflow

* test(web-shell): add negative test for mouse click guard in hold mode (#7839)

* test(web-shell): add negative test for mouse click guard in hold mode (#7839)

* fix(web-shell): add recording-state pointercancel test and fix buffer error message (#7839)

* test(web-shell): add tap-mode pointer and non-primary button guard tests (#7839)

* fix(web-shell): clear start timeout in deferred-stop path (#7839)

---------

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>
2026-07-28 13:32:02 +00:00
Shaojin Wen
a68c4cb28b
fix(web-shell): report intended workspace to host when starting a new chat (#7910)
* 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>
2026-07-28 12:15:42 +00:00
qqqys
2db663bec8
feat(web-shell): add Channel configuration flows (#7893)
* feat(web-shell): add Channel configuration flows

* fix(web-shell): hide invalid secret clear action

---------

Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
2026-07-28 05:58:26 +00:00
qqqys
090b213ad8
feat(web-shell): add native workspace folder picker (#7849)
* 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>
2026-07-28 05:58:13 +00:00
chinesepowered
fad164c0c9
fix(web-shell): make /copy with a bare index work (#7789)
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.
2026-07-28 05:35:58 +00:00
ytahdn
6a432ad2eb
fix(web-shell): isolate history and session drafts (#7810)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* fix(web-shell): isolate history and session drafts

* fix(web-shell): reset history-browse flag on early commit return (#7810)

* fix(web-shell): address review feedback on paste and draft handling (#7810)

* fix(web-shell): address review feedback on paste pruning, draft flush, and mobile draft notify (#7810)

* fix(web-shell): update smoke test for large paste placeholder behavior (#7810)

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.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 <qwen-code@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-28 01:45:52 +00:00
dreamWB
15b8ad2d3c
feat(web-shell): add composer footer renderer (#7856)
* feat(web-shell): add composer footer renderer

* fix(web-shell): align split composer footer state

* test(web-shell): render hidden pane case through customization provider
2026-07-28 01:16:08 +00:00
qqqys
bd2c0b47f1
feat(core): add full-resolution image zoom tool (#7809)
* 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>
2026-07-27 23:40:26 +00:00
qqqys
3209b89f3b
feat(web-shell): add Channel management page (#7793)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* feat(web-shell): add Channel management page

* fix(web-shell): address Channel manager review blockers
2026-07-27 17:58:11 +00:00
jinye
2210a18482
feat(web-shell): Scope voice to composer workspace (#7754)
* feat(web-shell): Scope voice to composer workspace

Route voice status, settings, model discovery, and streaming through the workspace that owns each main or split-view composer while preserving legacy primary behavior.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(web-shell): Keep legacy voice fallback scoped

Prevent the Voice-only legacy workspace fallback from activating pre-session git polling, and cover both behaviors together.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(web-shell): Preserve active Voice capture owners

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(web-shell): Pin Voice trust and ambiguity gates

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-27 15:47:45 +00:00
ytahdn
8785216be5
feat(web-shell): add monitor task details (#7817)
* feat(web-shell): add monitor task details

* fix(web-shell): align monitor tab title with merged snapshot and reset expansion (#7817)

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-27 12:30:17 +00:00
ytahdn
2a248cc5a9
fix(web-shell): preserve pasted text in composer (#7824)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-27 12:26:00 +00:00
ytahdn
8a44b1b9f7
fix(web-shell): render task notifications as system messages (#7822)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* fix(web-shell): render background notifications as system messages

* fix(web-shell): use basic table rendering by default

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-27 09:15:18 +00:00
Shaojin Wen
738c50011d
fix(web-shell): allow shell commands in new tasks without a session (#7724)
* fix(web-shell): allow shell commands in new tasks without a session

Previously, typing a ! command in a brand-new task showed "No active
session yet" because requireActiveSessionForLocalCommand() rejected
the command when no session existed. Replace it with
ensureSessionForPrompt() — the same lazy session creation path used
by regular messages — so the session is created on demand before the
shell command executes.

* feat(web-shell): queue shell commands during a turn instead of blocking

When a turn is running, ! commands are now queued client-side and
executed sequentially after the turn finishes, instead of showing
an error toast. A drain effect watches streamingState returning to
idle and runs pending commands via sendShellCommand(). The user
gets an info toast confirming the command was queued.

* fix(web-shell): clear queued shell commands on session switch

* fix(web-shell): pin drain session, clear queue on cancel, deduplicate reload (#7724)

* fix(web-shell): stop active drain on cancel, warn on dropped commands (#7724)

* fix(web-shell): keep draining queued shell commands as streamingState changes (#7724)

* fix(web-shell): defer composer clear for ! commands until session creation succeeds (#7724)

* fix(web-shell): scope drain cancellation to generation and harden new-task ! branch (#7724)

* fix(web-shell): warn on cancel drop and guard queue wipe against language change (#7724)

* fix(web-shell): assert cancel call in tests and document drain ordering (#7724)

* fix(web-shell): guard inline ! command against cancel and session-switch races (#7724)

* fix(web-shell): exempt lazy session creation from drain-generation bump (#7724)

The session-switch effect bumped drainGenerationRef on every sessionId
transition, including the one caused by the submit's own lazy session
creation. This silently cancelled the ! command: the generation guard in
the .then() saw a changed counter and returned before sendShellCommand.

Skip the bump when the transition target matches preparingSessionIdRef
(the session ensureSessionForPrompt is creating), so only genuine
user-initiated switches cancel in-flight commands.

* fix(web-shell): prevent drain preemption when commands are queued mid-drain

Add isDrainingRef guard to prevent a new drain from starting while an
existing drain is still processing. The running drain now re-reads the
queue after each batch to pick up commands added during execution.

The drain lock is tied to the generation counter: cancel and session-switch
release the lock when they bump the generation, and the drain IIFE only
releases it in finally if it's still the active drainer. This allows a new
drain to start after a cancel while preventing the idle-transition preemption
that was dropping commands.

Fixes the Critical findings rc:3652998624 and rc:3653109525.

(#7724)

* fix(web-shell): reset shellSubmitInFlightRef on cancel to unblock new commands (#7724)

* fix(web-shell): drop whole queue on drain bail to preserve FIFO (#7724)

* fix(web-shell): scope drain-bail queue wipe to disconnect only (#7724)

The unconditional queue wipe in the drain bail path destroyed commands
queued after a cancel or session switch, because those generation-bump
sites already wipe the queue themselves. Only the disconnect case lacks
its own wipe, so scope the drain-bail wipe to that case alone.

Adds two regression probes: commands queued after cancel and after a
session switch while a drain command is still in flight must survive
the stale drain's bail and be dispatched by the next drain.

* fix(web-shell): use returned session ID instead of stale connectionRef (#7724)

connectionRef.current.sessionId is only updated at render time, but the
.then() microtask after ensureSessionForPrompt() runs before React
commits the setConnection state update — so the post-creation cleanup
(editor clear, session-change dispatch, sidebar reload) never executed
for lazily-created sessions.

Have ensureSessionForPrompt() return the allocated session ID and use
it directly in the submit handler. Also include the command text in
drain-loop error toasts and assert the queue-path return value in the
queueing test.

* test(web-shell): cover sendShellCommand rejection and bare-bang guard (#7724)

---------

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 Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code <qwen-code@alibabacloud.com>
2026-07-27 08:15:15 +00:00
ytahdn
1f9a1a90a3
fix(web-shell): stabilize mobile voice input (#7806)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-27 06:28:00 +00:00
qqqys
1acc511809
feat(core): add Goal v3 worker tools (#7729)
* feat(core): add Goal v3 worker tools

* fix(core): address Goal tool review blockers

* fix(cli): complete Goal tool locale keys

* test(core): cover Goal tool error propagation

* fix(core): align Goal tool verification guidance

* fix(core): harden Goal proposal validation

* fix(core): align Goal blocker audit and verifier budget

* fix(core): address Goal verification blockers

* fix(core): keep Goal completion verifiable

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-27 04:28:39 +00:00
Shaojin Wen
b0ce7dc518
feat(web-shell): allow widening sidebar up to half the window width (#7778)
The sidebar max width was a fixed constant, so long session names could
never be fully revealed by dragging. The cap now scales with the window
(50% of window width, floored at the previous fixed cap), and a resize
listener re-clamps a stored wider sidebar when the window shrinks.
2026-07-27 02:46:02 +00:00
pratik wayase
60be40e8f9
feat(web-shell): persist terminal history pagination errors (#7709)
* feat(web-shell): persist terminal history pagination errors

* fix: address review feedback for pagination error state
2026-07-26 11:31:36 +00:00
chinesepowered
f43a2e46c8
fix(web-shell): parse 256-color and truecolor SGR sequences in parseAnsi (#7620)
* fix(web-shell): parse 256-color and truecolor SGR sequences in parseAnsi

parseAnsi read every ';'-separated SGR parameter as a standalone code,
but the arguments of 38/48/58 (extended foreground/background/underline
color) are not codes. `38;5;<n>` and `38;2;<r>;<g>;<b>` were fed back
into the code loop, so:

- `38;5;2` set dim (from color index 2) and produced no color;
- any truecolor value with a zero channel hit the `code === 0` branch
  and wiped the color, bold and dim already set on the line;
- a background such as `48;5;22` fed 22 to the reset-intensity branch,
  silently un-bolding the text.

Consume the 38/48/58 arguments instead of reading them as codes, and
resolve the foreground to hex: 0-15 map onto the existing themed palette,
16-231 onto the 6x6x6 cube, 232-255 onto the grayscale ramp. Background
and underline color are parsed but not rendered (Segment has no such
field) so their arguments still cannot leak into the code stream.

parseAnsi feeds shell tool-output rendering in ToolGroup, so this
affects any 256-color CLI. Adds ansi.test.ts (none existed); the four
new cases fail on the previous parser.

* fix(web-shell): keep the current color when an extended-color sequence is malformed

An unreadable 38/48/58 sequence was assigning its undefined result straight
to the color, so `\x1b[31m\x1b[38;5;300m` dropped the red that code 31 had
already set. Ignore the sequence instead and leave the color as-is; a
well-formed one still replaces it.

Also widen toHex/xterm256 to accept `number | undefined` so the truncated
arguments they are actually handed match their declared types, and drop the
non-null assertions that were hiding that mismatch from the compiler.

Add the regression case the existing malformed-sequence test could not catch:
it started from no color, so a cleared color was invisible to it.

* test(web-shell): pin the 58 branch and the truecolor channel guard

The 58;5;2 case asserted only bold, so dropping 58 from the extended-color
trio left the test green: the leaked 2 argument turns on dim, not bold.
Assert the whole segment instead.

No case used an out-of-range truecolor channel either, so toHex's 0-255
guard was unpinned. Add 38;2;999;0;0 to both malformed-sequence loops.

Both gaps found by wenshao's mutation run in review.
2026-07-26 02:25:20 +00:00
Shaojin Wen
596abd9664
fix(web-shell): allow pin and group for secondary workspace sessions (#7716)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
Organization actions (pin/group) only mutate display metadata and never
execute code or touch the filesystem, so they are safe for any trusted
workspace — not just locked ones. Decouple them from the stricter
canUseWorkspaceQualifiedActions gate into a new canUseOrganizationActions
check that allows primary, locked, and restricted scopes (rejecting only
unknown/untrusted). Destructive actions (rename, delete, export) remain
gated behind the original locked-or-primary requirement.
2026-07-25 14:14:16 +00:00
Shaojin Wen
5c7c2ec0d0
fix(web-shell): enable Changes and History dialogs for worktree sessions (#7695)
* fix(web-shell): enable Changes and History dialogs for worktree sessions

* fix(web-shell): add containment and gitCwd forwarding tests, fix SDK nits (#7695)

* fix(cli): use realpathSync in resolveContainedCwd test assertions (#7695)

On macOS, os.tmpdir() returns /var/folders/... (a symlink to
/private/var/folders/...), but resolveContainedCwd resolves paths
via fs.realpathSync. The test assertions compared against the raw
os.tmpdir()-based paths, causing two tests to fail on macOS. Wrap
the expected values in fs.realpathSync to match the function's
actual return value on all platforms.

* test(web-shell): cover gitCwd forwarding through log pagination (#7695)

* test(sdk): cover cwd query encoding in workspace git client methods (#7695)

* fix(sdk): bump browser bundle size limit for worktree cwd params

---------

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>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-25 12:47:02 +00:00
Shaojin Wen
d61b0ea475
perf(web-shell): paint the composer git chip before git status completes (#7680)
* perf(web-shell): paint the composer git chip before git status completes

New sessions gated the chip on a full `git status --porcelain` subprocess
behind GET /workspaces/:ws/git, so the branch chip appeared hundreds of
milliseconds (worst case seconds) after the composer was ready.

The daemon now keeps a per-workspace last-known summary with in-flight
dedup and a 2s background-refresh throttle: the default GET returns the
cached status (branch-only on a cold start) immediately and recomputes in
the background, publishing git_status_changed over SSE only on a delta,
while ?wait=1 keeps the previous blocking semantics. The composer fetches
both paths concurrently — the fresh GET also covers the no-session state,
which has no per-session SSE stream — so the branch paints in ~3ms and
the counters land when the computation finishes. The sidebar keeps
wait:true since it has no SSE fill-in path.

* fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680)

* fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680)

* fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680)

* fix(cli): use writeStderrLineSafe in git-status refresh error path (#7680)

* fix(web-shell): add debug trail to fresh-path catch and test branch-watcher dispose guard (#7680)

* fix(cli): assert writeStderrLineSafe in git-status refresh failure test (#7680)

---------

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>
2026-07-25 07:05:52 +00:00
Shaojin Wen
efdcb63936
fix(web-shell): add :focus-visible outline to GitHub PR list rows (#7704)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-25 04:10:44 +00:00
Shaojin Wen
a4f5e50d19
feat(web-shell): add read-only GitHub pull requests panel (#7683)
* feat(web-shell): add read-only GitHub pull requests panel

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(web-shell): address review findings for GitHub PRs panel

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(web-shell): clamp GitDialog view when PR capability is withdrawn mid-session

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(web-shell): address review feedback for GitHub PRs panel (#7683)

- Add workspace_github_prs to integration test baseline capabilities
- Sanitize git root path in error responses to prevent path leakage
  when workspace is a repo subdirectory
- Add NEUTRAL check-run conclusion test case
- Add not.toContain path-leak assertion for sanitization test
- Add pending checks indicator UI test
- Add timeAgo utility unit test

* fix(web-shell): address review feedback for GitHub PRs panel (#7683)

- Sanitize workspace paths before truncating the error message so a path
  straddling the 512-char display boundary is redacted, not cut mid-token
- Render a badge for the review_required decision instead of leaving it dead
- Align PR row icon sizes (12px) with sibling git dialogs

---------

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-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-25 02:44:50 +00:00
Shaojin Wen
3493dab8a0
test(web-shell): capture the git-mode new-branch sub-state in the visuals suite (#7672)
* test(web-shell): capture the git-mode new-branch sub-state in the visuals suite

The `git mode selector` visuals scenario captured the composer chip and the
opened three-mode popover, but stopped there: selecting an option used to
dismiss the popover ~100ms later (the click bubbled through the React tree out
of the portaled content to the composer surface's onClick → core.focus() →
Radix focus-outside close), so the branch-name sub-state couldn't be shot
stably. #7668 fixed that dismissal, so it now can.

Extend the scenario to click "New branch", fill a valid branch name, and
capture the revealed input (validated) with its Create-branch affordance, in
both themes. All six git-mode captures are byte-stable across runs (0% pixel
diff). Match the option by role — its label is split across a name and a
description span, so getByText('New branch') is ambiguous (also fixed in #7668).

Beyond covering a state the preview never showed, this doubles as a visual
regression guard for #7668: if the popover ever dismisses on option-click again,
the input goes missing and the assertion fails here, not only in the screenshot.

* test(web-shell): strengthen git-mode branch assertion and trim comment (#7672)

* test(web-shell): harden git-mode branch capture into a real #7668 guard

Scope the New branch option to the popover locator and settle past the ~100ms dismissal window before re-asserting the popover and input stay visible, so a regression of #7668 hard-fails here instead of only producing a wrong (visually reviewed) screenshot. Mirrors the proven guard in web-shell.git-mode.spec.ts.

---------

Co-authored-by: wenshao <wenshao@example.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-25 00:57:56 +00:00
qwen-code-ci-bot
9e7acec863
chore(release): v0.21.0 (#7675)
* chore(release): v0.21.0

* docs(changelog): sync for v0.21.0

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-24 13:47:34 +00:00
Shaojin Wen
cc742ca31e
fix(web-shell): keep git mode popover open when picking branch/worktree (#7668)
Clicking the "New branch" or "Worktree" option dismissed the popover
instead of revealing the branch-name input / confirm button. The option
click bubbles as a React synthetic event through the portal up to the
composer surface onClick, which calls core.focus() and moves focus
outside the popover — tripping the Radix focus-outside dismissal (the
popover only guarded the pointer path via onInteractOutside).

Stop click propagation on the popover content, matching the composer
ToolbarPopover pattern in ChatEditor. Also fix the e2e selectors
(getByText('New branch') matched both the name and description spans)
and add a delayed still-open assertion so the flash-then-dismiss
regression cannot false-pass.
2026-07-24 12:36:34 +00:00
Shaojin Wen
1130865949
fix(web-shell): show full session names on hover (#7662)
* fix(web-shell): show full session names on hover

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(web-shell): cover archived session tooltip attribute (#7662)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
2026-07-24 12:10:58 +00:00
qqqys
a0b9512003
feat(core): add configurable image generation models (#7607)
* feat(core): add configurable image generation models

* fix(core): keep undici out of ACP bundle

* fix(core): address review feedback for image generation (#7607)

- Use loadUndici() instead of direct import('undici') in downloadPng
  to handle esbuild CJS bundling where named exports are unavailable
- Check response.ok before parsing JSON body so non-JSON error pages
  (e.g. 502 HTML) produce structured HTTP status errors
- Use matched.baseUrl instead of matched.registryBaseUrl in the image
  model handler for consistency with the vision model handler
- Add zh-CN and zh-TW translations for ImageGen tool display name,
  model command description with --image, and all new image model
  UI strings (fixes i18n test failures)
- Add tests: redirect-following path, max redirect limit, non-JSON
  error body, permission-disabled registration, imageOnly vision guard

* fix(cli): add missing English i18n keys for image model feature (#7607)

* fix(core): prevent signed-URL leak via error cause chain in image-gen (#7607)

* fix(core): add web-shell image_gen display name and fix safe-mode re-read (#7607)

---------

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>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-24 09:03:18 +00:00
dreamWB
5561ba1e92
fix(web-shell): honor locked workspace session actions (#7629)
* fix(web-shell): honor locked workspace session actions

* fix(web-shell): preserve scoped session actions

* test(web-shell): strengthen untrusted action coverage
2026-07-24 06:14:45 +00:00
Shaojin Wen
203e61b59b
feat(web-shell): add git mode selector for new session creation (#7471)
* feat(web-shell): add git mode selector for new session creation

Support three git workflows when creating a new session:
1. Current branch (default, unchanged behavior)
2. New branch — daemon runs git checkout -b before spawning
3. Worktree isolation (existing, now unified into the same UI)

The mode selector lives in the composer's git chip as a popover,
replacing the previous worktree-only toggle in the welcome header.

API: POST /session accepts branch: { name } (mutually exclusive
with worktree). Server validates branch name, checks dirty tree,
creates branch, and rolls back on spawn failure.

Design doc: docs/design/2026-07-22-webshell-session-git-mode.md

* fix(web-shell): prevent Radix popover dismissal in git mode selector

The portal container used by Web Shell's Popover primitive is not
recognized by Radix's DismissableLayer, causing the popover to close
on any interaction. Add onInteractOutside prevention so the popover
only closes via explicit selection.

Also replace prototype screenshots with real Playwright captures and
add e2e test + screenshot capture script.

* refactor(web-shell): remove redundant worktree toggle from welcome header

The composer git chip popover now fully covers worktree selection,
making the welcome header toggle/badge redundant. Remove the toggle
UI, its state (worktreeToggleEligible, refs, handlers, focus effect),
and all associated tests (unit + e2e + visuals).

* chore: re-capture PR screenshots after worktree toggle removal

* fix(web-shell): audit fixes for git mode selector

- Add missing setSessionBranch(undefined) in loadSidebarSession,
  createNewSession, and session switch effect (!sid path)
- Add setSessionBranch(summary.branch) in session status restore
- Add branch rollback in client disconnect (!res.writable) path
- Fix onInteractOutside: use containment check instead of
  unconditional prevention so genuine outside clicks close popover
- Hoist promisify(execFile) to module level
- Narrow reserved branch name check to only HEAD (FETCH_HEAD etc.
  are valid branch names)

* fix(web-shell): address review feedback for git mode selector (#7471)

* test(web-shell): capture the git-mode selector in the visuals suite

This PR adds the new-session git-mode selector (current branch / new branch /
worktree) but no visuals scenario renders it, so the before/after preview showed
no image for an entirely new UI — the empty result was a coverage gap, not a
clean bill of health. The PR also removed the `worktree empty state` scenario
(its `worktree-welcome-toggle` no longer exists, replaced by this popover),
leaving the suite with no view of the new-session empty state at all.

Add a `git mode selector` scenario that seeds a trusted git-repo workspace and
lands on the empty state (the only place App.tsx wires the intent props), then
captures the composer chip and the opened three-mode popover in both themes.
Both are byte-stable across runs (0% pixel diff), and asserting an option is
visible makes a regression that fails to open the popover fail here rather than
only in the screenshot.

The branch-name sub-state is deliberately not captured: its input autoFocuses
and the popover then dismisses on the idle frame the capture waits for, so it
can't be shot stably through this pipeline — the functional
web-shell.git-mode.spec.ts already drives that path. Restores the empty-state
coverage this PR dropped and gives the new selector a head-only (NEW) preview.

* fix: address review feedback for git mode selector (#7471)

- Forward the branch override in createDetachedSession so the cold-start
  (no active session) path no longer silently drops a user-selected new
  branch.
- Reserve the workspace before 'git checkout -b' to close the TOCTOU in
  the activeBranchSessions guard; two concurrent branch creations could
  both pass the guard and race on HEAD. The reservation is released on
  every exit path.
- Return (and close the browser) when the branch input never appears in
  the screenshot script instead of falling through to a guaranteed throw.
- Add an e2e test asserting the default current-branch submit sends
  neither branch nor worktree.

* fix(web-shell): address review feedback for git mode selector (#7471)

* fix(web-shell): address review feedback for git mode selector (#7471)

* fix(web-shell): address review feedback for git mode selector (#7471)

* fix(cli): sync ink patch with semantic selection types (#7471)

* fix(web-shell): remove orphaned worktree CSS and dead i18n keys (#7471)

* fix: address review feedback for git mode selector (#7471)

* fix: address review feedback for git mode selector (#7471)

Release the route-local in-flight branch reservation in the
disconnect-after-spawn cleanup path so a throwing killSession/
removeSession no longer permanently blocks the workspace from new
branch sessions. Also reject branch names ending in .git on both
the server and the composer validator, associate the branch-name
label with its input, abort the screenshot capture script cleanly
when the chip or popover is missing, and add focused coverage for
the git-mode gating, branch forwarding, and branch pass-through.

* test(cli): cover branch session route validation and mutual exclusion (#7471)

* fix(cli,web-shell): accept Unicode branch names in validation (#7471)

The branch name validation regex rejected all non-ASCII characters,
preventing users from creating branches with Unicode names that git
accepts (e.g. 功能/fix-login). Replace the ASCII-only character class
with Unicode property escapes (\p{L}\p{N}) and the u flag, applied
consistently to both the server-side route and the client-side
GitModePopover validation.

* fix(web-shell): address review feedback on git mode selector (#7471)

- Revert unrelated ink patch change (transformers: [] → newTransformers)
- Extract duplicated branch rollback logic into rollbackBranchCreation helper
- Pessimistically track activeBranchSessions when killSession throws in
  disconnect-reap path, preventing concurrent branch session on surviving
  session
- Use ref pattern for gitModeIntent in ensureSessionForPrompt to avoid
  callback cascade on every git-mode toggle
- Add aria-label to git mode clear button for screen reader accessibility

* fix(cli): harden git branch session creation and clarify UX (#7471)

Address review feedback on the git mode selector:

- Bound every branch git operation with a 30s timeout (mirroring
  GitWorktreeService) so a stuck repository lock or slow hook can no
  longer hang the request and leave the workspace permanently reserved
  in inFlightBranchWorkspaces.
- Run branch shape/name validation before the active-session conflict
  check so a malformed body gets 400 instead of 409.
- Compare the reserved HEAD name case-insensitively (ref storage is
  case-folding on macOS/Windows), in both the route and the popover.
- Surface the design-doc "switches the working directory to a new
  branch" hint in the popover so users know HEAD will move.
- Correct the design doc: branch metadata is in-memory only and does
  not survive a daemon restart.

* fix(web-shell,cli): fix light theme, stale intent, and branch init guard (#7471)

- Replace undefined --web-shell-* CSS variables with shadcn design tokens
  (--foreground, --muted-foreground, --border, --popover-foreground, etc.)
  and add --git-mode-* accent variables to both .themeDark and .themeLight
  so the git mode popover is readable in light theme.
- Add useEffect to clear gitModeIntent when gitModeEligible flips to
  false, preventing stale branch intent from leaking to another workspace.
- Move gitModeIntentRef assignment from render body into useEffect to
  avoid ref mutation during render (concurrent React safety).
- Wrap GitWorktreeService constructor in try/catch on the branch path,
  matching the worktree path's guard, so a constructor throw returns 500
  instead of hanging the request.
- Show branchConflictWarning hint only when a valid branch name is
  entered, not as a static default hint.
- Reword GIT_RESERVED_BRANCH comment and add cross-reference comments
  between the duplicated client/server validation predicates.

* fix(cli,web-shell): address review feedback on git-mode PR (#7471)

- Add clearBranchSessionEntry cleanup hook on session close/delete to
  prevent stale activeBranchSessions entries from causing spurious
  409 branch_session_conflict on the next branch creation request.

- Extract git branch mutations (rev-parse, status, checkout -b,
  rollback) into a mockable git-branch-ops module, closing the test
  gap on the git-mutation paths that previously had no CI coverage.

- Add 6 new server tests: branch_already_exists, branch_dirty_tree,
  branch_checkout_failed, happy-path 200 with branch metadata,
  rollback on spawn failure, and branch_session_conflict.

- Export validateBranchName and add shared test vectors matching the
  server-side validation to catch future client/server drift.

* fix(cli): close concurrency guard gap in branch session creation (#7471)

The synchronous reserve point only re-checked inFlightBranchWorkspaces,
not activeBranchSessions. A request that passed the early guard before a
concurrent request registered could slip through after the first request
completed and cleared inFlightBranchWorkspaces. Re-check both structures
at the reserve point (no await between check and add) to close the window.

Also clarifies the dirty-tree gate comment to explain the real intent
(surprise-prevention, not data protection).

* test(cli,web-shell): cover worktree intent forwarding and branch session delete lifecycle (#7471)

* fix(cli): address review feedback on git-mode branch sessions (#7471)

* test(cli): cover git-branch-ops git command semantics (#7471)

* fix(cli,web-shell): roll back failed checkouts and guard shared-checkout branch creation (#7471)

* fix(cli,web-shell): address review feedback on git-mode branch sessions (#7471)

---------

Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: wenshao <wenshao@example.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-24 03:48:43 +00:00
ComplexSimply
16f024338a
fix(web-shell): render a plain textarea composer on touch devices (#7587)
* fix(web-shell): render a plain textarea composer on touch devices

Mobile browsers could not type into the Web Shell composer (#5958):
CodeMirror's contenteditable interacts poorly with virtual keyboards, and
three non-gesture view.focus() calls claim activeElement on iOS without
opening the keyboard, after which taps may never refocus the editor.

On touch devices ('(hover: none) and (pointer: coarse)' plus
maxTouchPoints > 0 — touch laptops keep the desktop editor) useComposerCore
now skips creating an EditorView entirely and exposes a mobileComposer
backend that ChatEditor renders as a controlled <textarea> at the same
mount point. The internal submit pipeline was hoisted out of the
editor-creation effect and accepts view: EditorView | null, so history,
prompt building, tags, images, and slash/! text interpretation are shared
unchanged between both backends. Enter inserts a newline natively;
submission goes through the Send button.

Programmatic (non-gesture) focus is additionally suppressed on
coarse-pointer devices even when CodeMirror is forced, and
?composer=textarea|codemirror serves as a debugging and rollback escape
hatch. The choice is frozen at mount so a mid-session flip cannot drop the
draft.

Known textarea-backend degradations (commands still work as typed text):
no slash/@ completion menus, no inline tag chips (fall back to the top
placement), no history arrow navigation, no large-paste placeholders, and
no followup Tab-accept.

Fixes #5958

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(web-shell): address review — textarea auto-grow, change notifications, caret restore

Address the five inline review suggestions on #7587:

- Auto-grow the mobile textarea with its content, capped by the computed
  CSS max-height (so --chat-editor-input-max-height overrides stay
  authoritative). Previously rows={1} plus resize:none meant multi-line
  drafts scrolled inside ~1.5 visible lines and the CSS max-height was
  dead. Asserted in the mobile e2e spec via bounding-box growth.
- Fire onInputTextChange from setMobileText, matching the CodeMirror
  updateListener contract: programmatic draft changes (setText, history
  restore, post-submit clear) now notify parent trackers too.
  handleMobileChange delegates to setMobileText.
- Restore the caret after mobile insertText: a controlled textarea resets
  the caret to the end on value change; setSelectionRange puts it back
  after React re-renders (rAF with a setTimeout fallback), matching the
  CodeMirror path's explicit selection anchor.
- Cover the mobile submitSearchMatch path: select a history match, submit
  through the shared pipeline, draft cleared.
- Cover the ChatEditor mobile quick-action gating: the history quick
  action opens the search UI (never dispatches into a missing EditorView)
  and the keyboard shortcut hints grid is hidden on the mobile composer
  with a desktop control.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(web-shell): decide the touch composer by media query alone

Independent macOS verification on #7587 found that Playwright's stock
WebKit iPhone profiles match '(hover: none) and (pointer: coarse)' but
report navigator.maxTouchPoints === 0, so the automatic detection selected
CodeMirror under unmodified WebKit emulation.

The maxTouchPoints requirement added nothing the AND media query does not
already provide: touch laptops are excluded by the query itself (their
primary pointer hovers and is fine), and the only devices that match the
query with zero touch points are emulated profiles and TV-style browsers,
where the plain textarea is a safe fallback. Dropping it makes stock
iPhone/WebKit Playwright runs exercise the automatic detection branch.

Real-device behavior is unchanged: phones and tablets match the query and
report touch points either way.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(web-shell): keep the mobile textarea scrollable past its height cap

As .editorArea's last child the textarea inherited `overflow: clip` from
the `.editorArea > :last-child` wrapper rule (written for the CodeMirror
container, whose inner .cm-scroller does the scrolling). `clip` also
forbids programmatic scrolling, so once auto-grow reached the CSS
max-height, content beyond the cap was unreachable — scrollTop stayed
pinned at 0.

Override with `overflow-y: auto` via `.editorArea > textarea.mobileTextarea`
(the extra type selector outweighs the wrapper rule's specificity). New
mobile e2e regression fills 20 lines, asserts growth stops at the computed
300px cap, and verifies the overflow stays reachable: scrollHeight above
clientHeight and scrollTop actually moving to the bottom — the exact probe
from the review, which pinned at 0 before this fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: ComplexSimply <rudy.arrowsong@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:14:25 +00:00
ytahdn
abc9666f77
fix(web-shell): prevent React measure detail OOM (#7596)
Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-23 11:35:42 +00:00
Wu JiaCheng
aa11e8d126
fix(web-shell): initialize workspace selector from ID (#7518)
* fix(web-shell): initialize workspace selector from ID

* Update packages/web-shell/client/components/WorkspaceSessionProvider.tsx

fix: adjust initial workspace directory resolution logic to support embeddings passing only unlocked workspaceCwd
Replace condition check from effectiveWorkspaceId to !lockWorkspaceCwd && targetWorkspace, prevent sessions from incorrectly initializing under primary workspace for secondary workspace path inputs

Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>

---------

Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
2026-07-23 11:29:40 +00:00
ytahdn
c0fee1b609
feat(web-shell): add workspace agent management (#7572)
* feat(web-shell): add workspace agent management

* test(web-shell): remove unstable extensions page tests

* fix(agents): address management review feedback

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-23 08:42:08 +00:00
ytahdn
74a786dac3
fix(web-shell): isolate slash command plugin pages (#7581)
Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-23 08:39:10 +00:00
ytahdn
22cd9c7d7a
fix(web-shell): sync background agent status (#7561)
* fix(web-shell): sync background agent status

* fix(web-shell): harden background agent reconciliation

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-23 06:35:04 +00:00
ytahdn
228fdd830c
fix(web-shell): include managed id in artifact open requests (#7570)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-23 06:14:21 +00:00
yuanyuanAli
95fc7ca152
feat(web-shell): add renderChatHeader slot for custom session header (#7553) 2026-07-23 02:59:21 +00:00