The sidebar git chip only polls every 60s, so after switching branches
through the branch picker it kept showing the old branch for up to a
minute — making the checkout look like it silently failed. Wire the
picker's branch-changed callback to an immediate status refetch,
matching the composer chip's realtime behavior.
* feat(web-shell): run read-only info commands immediately mid-turn
/stats, /about (/status) and /context were silently swallowed while a
turn was streaming, because their local user echo would act as a turn
boundary in applyTurnCollapse and split the active turn. Their output
is a status block, which is not a turn boundary and is not counted in
turn metrics, so only the echo needs to be skipped mid-turn.
Add appendLocalUserEchoIfIdle, which echoes when idle and skips the
echo while streaming without blocking the command, and switch these
three commands to it so their results render inline immediately even
during an active turn.
* fix(web-shell): keep streaming assistant block intact for mid-turn info commands
Address PR review. A status dispatch finalizes the active assistant
block by default, so running /stats, /about or /context mid-turn would
fragment the streaming answer around the status card and drop later
usage frames. Add an optional clearActiveText flag to the status event
and pass false from these three command dispatches, covered by
reducer-level tests.
Also collapse the echo gate into a single body (the new helper now
delegates to appendOrDeferLocalUserMessage), add App-level wiring tests
for the responding/idle behavior of /stats and /about, and surface
failed getStats via reportError instead of swallowing them.
* fix(web-shell): reset the echo user block when info output keeps streaming (#8496)
The clearActiveText: false opt-out skipped the whole clearActiveText call,
leaving the local command echo as the active user block indefinitely. A
peer client's prompt echo then merged into it, corrupting turn boundaries.
Keep the streaming assistant/thought block open on the opt-out path but
still drop the user pointer.
Also report /about load failures like /stats and /context already do, and
pin the new /context wiring plus the /stats failure path with tests.
* refactor(web-shell): centralize the mid-turn read-only status dispatch (#8496)
Address the round-3 review feedback on the mid-turn read-only commands:
- The read-only result dispatch (status block with clearActiveText:
false plus the follow-resume) was copied verbatim at the /context,
/stats, and /about sites, leaving the load-bearing flag enforced by
convention at three places. Centralize it in one
dispatchReadOnlyStatus callback next to echoLocalCommandIfIdle; the
three .then bodies now call it with their serialized text.
- Pin the /about catch the way the sibling /stats catch is pinned:
make collectSystemInfo throw once and assert the failure surfaces
through console.error instead of becoming an unhandled rejection
with zero user feedback.
* test: pin thought opt-out and serialized mid-turn status payloads (#8496)
* refactor(web-shell): consolidate read-only command echo into echoOrDeferLocalCommand (#8496)
* test(web-shell): cover /status routing and document the echo-suppression exception (#8496)
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
* feat(channels): support local gh authentication
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(channels): align registry catalog test and visuals with optional GitHub token (#8461)
* fix(channels): address review feedback for GitHub local gh auth (#8461)
Treat a blank replacement of an optional secret as a clear so an existing GitHub channel can no longer ship an empty or whitespace-only PAT to the daemon. Reuse the shared missing-field predicate in the editor's GitHub credential validation, wrap malformed baseUrl failures in an actionable channel error, and surface sanitized gh stderr in local authentication failures.
* fix(channels): address second-round review feedback for GitHub local gh auth (#8461)
Pin the whitespace-only token gate, the bounded gh stderr sanitization, and the required-secret blank-replacement guard with mutation-resistant tests. Log the authenticated account identity on channel connect so an out-of-band gh auth switch is visible to operators. Align test secret-source fixtures with the SDK union and complete the design doc's change footprint.
* fix(channels): address third-round review feedback for GitHub local gh auth (#8461)
* fix(channels): address fourth-round review feedback for GitHub local gh auth (#8461)
* fix(channels): address fifth-round review feedback for GitHub local gh auth (#8461)
* fix(channels): address sixth-round review feedback for GitHub local gh auth (#8461)
* fix(channels): address seventh-round review feedback for GitHub local gh auth (#8461)
* fix(channels): address eighth-round review feedback for GitHub local gh auth (#8461)
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
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>
* feat(web-shell): gate session workflow behind experimental setting
* feat(web-shell): bind plan approval to todo revision
* fix(cli): clear stale workflow revision on plan entry
* test(web-shell): pin revised workflow snapshot
* fix(cli): clear stale plan revisions on restore
* fix(cli): keep replayed history from rebinding plan revisions
History replay re-sends stale plan updates through Session.sendUpdate,
re-stamping activeTodoPlanRevision from finished plan cycles. Clear the
revision after every replay path (cold replayHistory and live non-bulk
loadSession) so a replayed snapshot can never bind a later exit_plan_mode
approval; reloaded sessions fall back to text-only approval until the next
live todo_write re-establishes the binding. Also drop the bulk-load restore
that could never be read before a plan-mode transition cleared it, and pin
the workflow gates and mode-entry clears with negative tests.
* test(web-shell): pin older plan revision in ChatPane approval test (#8393)
* test(cli): pin unbindable plan updates in approval revision test (#8393)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): clear Todo plan revision on history restore (#8393)
restoreHistory was the one history-resetting path that kept
activeTodoPlanRevision, so a restored snapshot could let a stale
revision bind the next exit_plan_mode approval. Clear it like the
sibling reset paths, pin the behavior with a test, and pin the
live-load clear ordering after the replayed updates.
* fix(cli): restore Todo stop guard clear on plan re-select (#8393)
The previous-mode guard added for the revision binding also skipped the
Todo Stop Guard trust clear on a redundant plan re-select; scope the
guard to the revision reset so every transition into plan clears the
stop guard as before. The replay-time revision clears now run in
finally blocks so a transport failure part-way through a replay cannot
leave a replayed binding on the live session, and the web-shell
exit-plan approval rule is unified in one predicate. Revision tests
assert through the observable qwenTodoApproval approval metadata
instead of the private field.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
* fix(web-shell): add explicit ::selection for message content in Firefox
Firefox does not paint the default selection highlight for text whose
element chain passes through a display:contents element (the
data-user-selectable wrapper on MessageItem). The logical selection
(copy, selectionchange popup) works fine - only the visual highlight is
missing. An explicit ::selection background makes Firefox paint the
highlight where the default painting fails.
Fixes#8214
* fix: use fixed color instead of non-existent CSS variable
--selection-bg was never defined in the codebase (only
--chat-editor-selection-bg exists in App.module.css). Use a fixed
hsl(210 100% 50% / 30%) to avoid confusion.
* test(web-shell): pin ::selection rule and soften root-cause framing
Reframe the standalone.css comment and PR description as a defensive
workaround, not a confirmed root-cause fix: the data-user-selectable
wrapper is shared by user and assistant rows, and the reporter's
screenshot shows an embedding-page toolbar this package does not ship.
Add a getComputedStyle(..., '::selection') assertion to the smoke e2e so
a future cleanup cannot silently drop the rule.
* fix(web-shell): move ::selection rule to component-scoped globals.css
The defensive ::selection rule for [data-user-selectable] message content
was in standalone.css, which is only loaded by the standalone app entry
(client/main.tsx) and the e2e harness. The npm package entry
(client/index.tsx via vite.lib.config.ts) never loads standalone.css, so
embedded deployments of @qwen-code/web-shell - including the reporter of
#8214 - did not receive the rule and still saw no selection highlight.
Move it to globals.css, which is imported by App.tsx and
WebShellTranscript.tsx and therefore ships with the component-scoped
stylesheet. Verified against the lib build: the rule now appears in
dist/index.js correctly scoped under
[data-web-shell-root][data-web-shell-shadcn]. The standalone app also
loads globals.css, so the e2e smoke pin still passes.
Addresses the review finding on standalone.css:119.
* test(web-shell): pin ::selection across all rows and in the lib bundle
Address review findings on the round-3 move to globals.css:
- The smoke e2e only sampled the first [data-user-selectable] row (the
user row in this fixture). Assert the rule on every selectable row so
a future narrowing to user rows keeps assistant rows covered.
- Nothing asserted the rule survives in the npm lib bundle - the
deployment this fix exists for. Add a build-artifact test that parses
the injected component CSS in dist/index.js and pins the scoped
[data-user-selectable] ::selection rule under [data-web-shell-root].
* test(web-shell): assert ::selection on selectable wrapper rows, not descendants
Per review: querySelectorAll('[data-user-selectable] *') counts element
descendants, not the wrapper rows themselves - a single user row renders
4+ descendants, so the >=2 invariant did not actually enforce that both
roles are present. Match the [data-user-selectable] wrappers directly and
sample one descendant per row.
* test(web-shell): match ::selection lib-bundle pin by effect, not notation
Per review (R6-1): the pin matched an exact selector substring
(including the space) and an exact prop name, coupling to the current
notation. A maintainer switching 'background' to 'background-color'
(the CSS Pseudo-Elements-4 name) would fail this test with a misleading
message while the e2e pin stayed green. Match the two selector halves
independently and accept either prop name.
---------
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
* fix(web-shell): keep pending background agents active
* test(web-shell): cover pending agent activity edge cases
* fix(web-shell): preserve background agent elapsed time
* test(web-shell): require shared active tool status classification
* refactor(web-shell): centralize active tool status
* fix(web-shell): keep parallel agents clock monotonic
* refactor(web-shell): consolidate active tool checks and walkers (#8413)
Drop the duplicate hasActiveTool wrapper in favor of the adapters'
hasActiveAgents so the package keeps a single any-active predicate,
share one turn walker between turnOwnsCallId and turnHasActiveAgent so
the tool-carrying DisplayItem set is encoded once, and cover the
parallel-agents clock latch re-arm when a second wave of agents starts
after the group went fully terminal.
* feat(review): add Web Shell review artifacts
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(web-shell): add code review artifact visual scenario (#8402)
* fix(review): address Web Shell review artifact feedback (#8402)
* save-artifact: document why paths resolve against the daemon workspace
root (QWEN_CODE_PROJECT_DIR) instead of cwd, and cover the relative-path
form the skill documents with a test where the two roots differ.
* CLI/renderer contract: the renderer hand-duplicates the findings
vocabulary and fails closed on unknown values, so name the renderer as a
second consumer beside the CLI's lists and check in a contract fixture
generated through the real pipeline (validateFindings -> buildReport ->
save-artifact) that exercises every source, severity, confidence and
outcome. Exporting the vocabulary through the SDK stays deferred: it is a
public cross-package API change beyond this PR's seam.
* resolve-anchors now validates `line` exactly like `findings` does
(positive safe integer); the two validators in one pipeline no longer
disagree. Note: an in-flight `.qwen/tmp` findings file carrying `line: 0`
fails where it previously did not.
* The renderer validates markdownReportPath (relative, no ".." segments,
.md suffix) before it becomes a readWorkspaceFile call, resets the
severity/confidence filters when switching artifacts, and surfaces
heldByMeasurement so a nonzero Held count is attributable.
* save-artifact refuses low effort structurally (choices and library guard)
instead of by prose, stats the Markdown report before reading it so a
directory reports "not a file", and the component no longer shadows the
DOM `document` global.
* The case-insensitive alias test now skips visibly on case-sensitive
filesystems instead of passing vacuously.
* Comment the kept `turnOutputs.review` key and document the JSON
companion in the user docs.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(review): address second Web Shell review artifact feedback round (#8402)
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
* feat(channels): add Web Shell management support for GitHub and GitLab
* test(channels): update channel-registry manageable expectation for GitHub and GitLab
* test(web-shell): add gitlab manageable:false negative case for symmetry
* fix(web-shell): add GitHub/GitLab platform marks, i18n labels, and empty-state copy
* feat(web-shell): descriptor-driven groupPolicy, senderPolicy, allowedUsers for GitHub/GitLab channels
* feat(web-shell): render field descriptions below inputs in channel editor
* feat(web-shell): add reasonFilter and action_prompt_template fields with record kind support
* fix(cli): validate string-list and record kinds in assertDescriptorValue
The daemon-side store validation only accepted string, secret, boolean,
number, and enum field kinds. Channels declaring string-list or record
fields in their management descriptor (GitHub allowedUsers/reasonFilter,
GitLab action_prompt_template) could never be saved through the Web Shell.
Teach assertDescriptorValue the two new kinds and add store-level tests
covering both acceptance and rejection paths.
* fix(web-shell): prevent silent config rewrite and record crash in editor
- initialFieldValue: for existing instances with an absent enum field,
return empty string instead of the first option. This forces the user
to explicitly choose rather than silently writing a new value on save.
- isMissingField: guard Object.values().every() with typeof check so
hand-edited configs with non-string record values show a validation
error instead of throwing TypeError.
* refactor(web-shell): extract hasDescriptorSenderPolicy helper, hide empty Access section
- Extract repeated descriptor.fields.some(f => f.key === 'senderPolicy')
into a shared hasDescriptorSenderPolicy() helper (was inline ×4).
- Conditionally render the Access section: for descriptor-driven types
with a non-pairing policy the section would show only a bare heading
with no content beneath it; now it is omitted entirely.
* fix(cli): accept undeclared record keys in assertDescriptorValue
record field options are UI hints for which rows to render, not a closed
set. The GitLab adapter resolves action_prompt_template by plain key
lookup and accepts any GitLab todo action_name, but the store rejected
keys outside the 9 declared options — silently bricking editing of
configs that use server-side actions the descriptor doesn't enumerate.
* fix(web-shell): harden channel editor parsing, defaults, and validation
- Guard the three record JSON.parse sites with an isRecord shape check
so a non-object payload can't throw during render or upsert.
- Add an explicit descriptor `default` for enum fields and prefer it over
option order when seeding a new channel, so an access-control default is
declared intent rather than an emergent property of array order.
- Declare the GitHub reasonFilter reasons as options and validate
string-list input against them in the form, surfacing typos before
submission instead of failing at channel start.
- Fall back to an uppercased display-name initial (or '?') for the
platform mark so an empty name can't render blank.
* fix(web-shell): use distinct validation message for string-list option errors
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* 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>