Commit graph

1076 commits

Author SHA1 Message Date
BaboBen
a9a6ca4ac6
feat(channels): observe group names from inbound messages (#7155)
* feat(channels): expose observed workspace contacts

* fix(channels): address observed contacts review feedback

* docs(channels): design observed group names

* docs(channels): plan observed group names

* feat(channels): observe inbound group names

---------

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>
2026-07-18 09:26:12 +00:00
Dragon
d4db5fcfab
feat(core): improve subagent delegation defaults and guardrails (#7048)
* docs(design): define default background subagents

* feat(core): improve subagent delegation defaults

* docs(core): cross-reference the three background-classification sites

Add pointer comments linking the core dispatch source of truth
(AgentTool.execute) and its two UI mirrors (web-shell
isBackgroundSubAgentToolCall, desktop detectBackgroundEvents) so the
replicated top-level-agent background heuristic is not changed in
isolation. Addresses PR review feedback.

* fix(core): align background classification for fork and named-teammate launches

Address review feedback on the background-classification rule so core dispatch
and the two UI classifiers stay consistent:

- core: exclude a name-without-active-team launch from the default-background
  path so it stays foreground, matching both UI classifiers (which exclude
  name). Previously such a launch was backgrounded by core but tracked as
  foreground by the UIs.
- web-shell and desktop classifiers: exclude subagent_type "fork" from the
  default-background heuristic, mirroring core's !isForkRequested guard. A
  top-level fork request with an omitted flag runs foreground in core but was
  classified as background by the UIs.
- add a core dispatch test asserting a working_dir launch with an omitted
  run_in_background flag stays in the foreground.

* test: cover fork/background classification and precedence per review feedback

Address unresolved review threads on PR #7048:
- Add web-shell and desktop UI classifier tests asserting an omitted-flag
  `subagent_type: "fork"` launch stays in the foreground, verifying the
  documented `!isForkRequested` parity with core dispatch.
- Add a core AgentTool test asserting an explicit `run_in_background: false`
  overrides a subagent config with `background: true`, locking in the
  `run_in_background ?? config` precedence against a `||` regression.
- Harden the Explore read-only prompt: pipelines must not send data to a
  network endpoint (no curl/wget/nc), closing the `cat file | curl`
  exfiltration gap.

* fix(core): restore general no-unnecessary-files guard in general-purpose prompt

Address review feedback: the rewritten general-purpose prompt dropped the
broad guard against creating unrequested files, keeping only the
documentation-specific line. Restore a general 'do not create files unless
necessary' guard so speculative utility/config files are not created.

* test(desktop): cover named-teammate foreground guard in detectBackgroundEvents

Add a desktop tool-matching test asserting a top-level Agent with a
`name` set (named teammate) stays foreground and emits no
task_backgrounded event, mirroring the web-shell classifier's
named-teammate coverage and the existing fork-exclusion test.

* test(core): cover named-teammate foreground dispatch when flag omitted

Add a core-dispatch test asserting a top-level Agent launch with `name`
set and `run_in_background` omitted stays foreground when no team is
active, guarding the `this.params.name === undefined` exclusion in
backgroundRequested directly (previously only covered by the UI
classifiers).

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-18 08:52:48 +00:00
chinesepowered
d51c21de86
fix: correct typos in comments, a tool description, and docs (#7131)
- settings.ts comment: loadEnviroment -> loadEnvironment
- ide-server.ts openDiff tool description: rejcted -> rejected
- fileHistoryService.test.ts comment: forgetten -> forgotten
- settings.md: togglable -> toggleable (repo consistently uses toggleable)
2026-07-18 07:40:14 +00:00
BaboBen
02cb3a6380
feat(channels): expose workspace-scoped observed contacts (#7109)
* feat(channels): expose observed workspace contacts

* fix(channels): address observed contacts review feedback

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-18 07:35:45 +00:00
易良
878747b1ff
feat(vscode): route logs to the Qwen Code Companion output channel (#7121)
* feat(vscode): route logs to the Champion output channel

* fix(vscode): preserve the output channel name

* refactor(vscode): simplify output logger setup

* fix(vscode): close output logging review gaps

* fix(vscode): harden output log forwarding

* fix(vscode): close webview logging review gaps

* fix(vscode): close output logging review nits

* fix(vscode): preserve log response redaction

* fix(vscode): close output logging review gaps
2026-07-18 06:58:14 +00:00
jinye
b67506b70b
feat(daemon): Profile ACP channel initialization (#7145)
* feat(daemon): Profile ACP channel initialization

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

* codex: address PR review feedback (#7145)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-18 05:27:59 +00:00
jinye
b4559dc8ba
feat(cli): add daemon Todo stop guard (#6945)
* feat(cli): add daemon Todo stop guard

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

* codex: address PR review feedback (#6945)

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

* fix(cli): Preserve Stop hook output on mid-turn input

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

* codex: address PR review feedback (#6945)

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

* codex: address PR review feedback (#6945)

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

* codex: resolve PR merge conflict (#6945)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-18 01:48:20 +00:00
易良
20e4351d28
feat: support full-turn multimodal routing for image prompts (#7045)
* feat: support full-turn multimodal routing

* fix: keep full-turn multimodal routes exact

* test(cli): sync serve capabilities baseline

* fix(cli): close multimodal routing review gaps

* fix(cli): normalize full-turn vision parts

* fix(cli): fail closed on full-turn scheduling errors

* fix(core): close multimodal routing review gaps
2026-07-17 23:22:46 +00:00
ytahdn
de44c74732
feat(web-shell): paginate restored session history (#7064)
* feat(web-shell): paginate restored session history

* test(web-shell): align workspace visual assertion

* fix(web-shell): harden history pagination

* fix(web-shell): keep history paging retryable

* fix(webui): skip malformed transcript page events

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-17 22:09:19 +00:00
Shaojin Wen
a9d338684d
fix(core): make the per-turn tool-call cap adaptive (#7052)
* fix(core): make the per-turn tool-call cap adaptive

The per-turn tool-call cap (model.maxToolCallsPerTurn, default 100) was a
blunt circuit breaker: it halted any turn on the 101st tool call regardless
of whether the model was stuck or doing productive work. Large multi-package
implementation turns legitimately exceed 100 calls, so the cap killed
productive turns — a false positive.

Make the cap adaptive. The configured value is now a soft cap: once a turn
exceeds it, the cap halts only when a stuck-repetition signal is present (the
same (tool, args) call repeated 6+ times); a productive turn (diverse calls,
no repetition) continues up to a hard backstop of 3x the soft cap, which
always halts to bound an argument-varying runaway.

Validated against a real session whose 100-call turn was halted mid-build
with no repetition (max key repeat 2): that turn now continues, while genuine
stuck loops still halt at the soft cap. The always-on cap keeps its own
per-(tool,args) repeat tracker so it stays independent of skipLoopDetection.

The ACP/daemon path has a separate blunt cap that is not aligned here; noted
as a follow-up in the design doc.

* chore: regenerate settings schema for adaptive cap

* fix(core): clarify adaptive cap is interactive-only; strengthen cap tests

Address review feedback:
- The setting description now notes the daemon/ACP path still halts at the
  configured value regardless of repetition, so it no longer overclaims the
  adaptive behavior for non-interactive paths.
- Rename the misleading "fires at the built-in default soft cap value" test
  (it only asserts diverse calls are allowed past the cap).
- Add a retry test that builds a stuck-repetition signal before the retry and
  verifies it is cleared, so removing the capMaxKeyRepeat reset would fail.

* test(core): cover productive-then-stuck cap; clarify cap halt hint

Address review round 2:
- Add a test for a turn that crosses the soft cap with diverse calls and then
  becomes stuck mid-range, so the stuck check is verified across the whole
  (softCap, hardCap] range, not just at the boundary.
- Make the headless cap-halt message accurate for both triggers: it no longer
  only suggests raising maxToolCallsPerTurn (correct for the hard backstop but
  misleading for a stuck repeat) and now also points at the repetition.

* refactor(core): hash tool-call key once in always-on cap path; tighten cap tests

Address review round 3:
- Compute the (tool,args) key once in checkAlwaysOnSafeties and share it
  between the consecutive-identical guard and the cap stuck tracker (was
  hashed twice per call; args can be large). Skip hashing entirely when loop
  detection is disabled for the session (no consumer).
- Add a test that the stuck signal accumulates across Finished round-trip
  boundaries within a turn.
- Tighten the Stop-hook continuation budget test (cap 4 -> 1) so it still
  guards the reset under the adaptive cap, where diverse calls no longer trip
  the soft cap.
- Document the monotone stuck-signal non-goal and the telemetry-differentiation
  follow-up in the design doc.

* fix(core): canonicalize tool-call key fields; clarify adaptive cap scope

Address Codex review (2 Critical):
- getToolCallKey now canonicalizes object keys recursively (preserving array
  order) before hashing, so a stuck model cannot evade the repeat guards by
  reordering argument fields. Adds a reordered-arguments regression test.
- Correct the maxToolCallsPerTurn description: the adaptive behavior applies to
  both the interactive TUI and non-interactive (-p / JSON / stream-JSON)
  core-client runs; only the daemon/ACP path is strict. Updated in
  settingsSchema.ts, settings.md, and the regenerated settings.schema.json.

* test(core): cover nested key reordering and the consecutive guard's canonicalization

Address review:
- Extend the reordered-args stuck-signal test to include nested objects, so a
  regression that breaks canonicalizeForHash's recursion is caught.
- Add a reordered-args test for the consecutive-identical guard, pinning the
  canonicalization contract for that always-on detector (not just the cap).

* fix(core): treat explicit maxToolCallsPerTurn as a hard cap; keep default adaptive

Address yiliang114's Critical: v0.19.10 shipped maxToolCallsPerTurn as a hard
cap, but the adaptive change multiplied every configured value by 3, turning an
explicit N into a 3N budget — a breaking change for users who set it to bound
unattended cost.

Behavior now depends on whether the value was explicitly configured
(Config.isMaxToolCallsPerTurnExplicit):
- Explicit N -> hard cap (halt at N+1), preserving the released contract.
- Default (unset) -> adaptive: soft cap 100, halt only on a stuck-repetition
  signal, with the hard backstop raised to 1000 (10x) so modern models making
  hundreds of legitimate calls per task are not false-positived.

Adds the explicit-hard-cap regression (cap of 2 halts call 3) and a contrast
test proving the explicit flag drives the behavior. Updates the setting
description, headless hint/label, and design doc accordingly.
2026-07-17 16:42:41 +00:00
callmeYe
62ad0cddcb
fix(web-shell): render built-in tag icons (#7024)
* fix(web-shell): render built-in tag icons

* docs(web-shell): add tag icon comparison

* test(web-shell): strengthen tag icon coverage
2026-07-17 15:33:34 +00:00
ChiGao
a064e5d0cb
feat(core): Enable artifact defaults and write reminders (#7068)
* fix(core): remind models to record artifact writes

* feat(core): enable artifacts by default

* test(core): cover artifact reminder extension casing

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
2026-07-17 15:27:27 +00:00
jinye
e74c0cd33c
feat(serve): Complete legacy session workspace telemetry (#7003)
* feat(serve): Complete legacy session workspace telemetry

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

* codex: address PR review feedback (#7003)

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

* codex: address PR review feedback (#7003)

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

* codex: address PR review feedback (#7003)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-17 15:25:15 +00:00
qqqys
7705f08305
feat(channels): save explicit multi-fact memory safely (#7092)
* feat(core): guard channel memory secrets

* feat(channels): classify multiple memory facts

* feat(channels): save multiple memory facts

* fix(channels): snapshot classifier memory fields

* fix(channels): snapshot classifier memory elements

* docs(channels): explain multi-fact memory

* docs(channels): clarify multi-fact memory example

* fix(channels): harden memory input snapshots

* fix(channels): log memory intent validation failures
2026-07-17 15:24:11 +00:00
qqqys
b826420d4d
feat(channels): confirm natural memory mutations (#7066)
* feat(channels): add memory mutation confirmations

* feat(channels): confirm natural memory mutations

* docs(channels): explain memory mutation confirmations

* fix(channels): harden pending memory mutations

* fix(channels): activate memory proposals after delivery
2026-07-17 15:06:44 +00:00
sunday
e75aec9d5b
feat(channels): stamp daemon sourceId with channel instance name on created sessions (#7078)
* feat(channels): stamp daemon sourceId with channel instance name on created sessions

Channel workers tagged created sessions with sourceType 'channel' (#6991,
refs #6962) but no sourceId, leaving sessions from different channel
instances (e.g. dingtalk-main vs feishu-main) indistinguishable on the
daemon data plane (session lists, transcripts, ?sourceType= filters).
The session-source mechanism already supports a paired sourceId —
scheduled tasks use it for the task id.

Plumb the channel instance name through the creation path:
SessionRouter.createLiveSession → bridge.newSession options
(ChannelAgentBridgeSessionOptions.sourceId) → session-factory request →
createOrAttach. loadSession deliberately never forwards it: loading an
existing session never re-stamps its creation attribution, matching the
issue's 'only newly created channel sessions should be tagged' rule and
the daemon's single-attach source rule.

Tests: channels/base suite (764) and cli daemon-worker suite (66) green.
New cases cover router stamping, bridge new-vs-load forwarding, and the
worker factory create-vs-load behavior.

* fix(channels): declare sourceId in createOrAttach DI type and cover replacement-path stamping

Review feedback on #7078:

- DaemonSessionClientStaticLike.createOrAttach's request type declared
  sourceType but not sourceId; the field type-checked only via object-spread
  excess-property exemption. Declare sourceId?: string so the contract
  documents the request and direct-property edits keep compiling.
- Add a sourceId assertion to the load-failure replacement test so the
  recovery path's per-instance attribution is regression-guarded.

---------

Co-authored-by: 欢伯 <ri.xur@alibaba-inc.com>
2026-07-17 14:57:27 +00:00
ChiGao
401170d488
feat(cli): mouse text selection and copy in VP mode (#6937)
* docs(cli): design for VP mode mouse text selection and copy

First step of the VP mouse-selection feature: the design doc, submitted
ahead of implementation so the approach can be reviewed before code lands.

Proposes an application-level selection and copy system for VP mode, where
SGR mouse tracking currently suppresses native terminal selection. Evaluates
two routes and commits to exposing the Ink renderer cell grid via the
existing Ink patch, which makes coordinate-to-text mapping uniform across all
content types. Implementation follows as staged milestones on this branch.

* docs(cli): revise VP selection design per feasibility audit

Rework the design after the implementation-feasibility audit against the
Ink 7 renderer source. Key corrections and scope changes:

- Two-PR plan. PR 1 (this branch) delivers the Ink frame-buffer foundation
  and a visible-region visual-selection MVP (visual-cell copy, clear on
  scroll). PR 2 adds cross-screen selection and semantic copy fidelity
  (soft-wrap rejoin, gutter exclusion), which need renderer semantic metadata.
- Highlight goes through a bidirectional frame controller with a
  pre-serialization transform and throttled repaint; the earlier read-only
  accessor plus post-commit callback could not highlight the current frame.
- Immutable cell/style allocation to avoid leaking the highlight onto other
  on-screen occurrences of the same text via shared cached styled chars.
- Corrected coordinate formula (frame is not unconditionally top-anchored),
  OSC 52 behavior (over-cap skips and returns false; surface a copy failure),
  and the note that release already has non-selection consumers.
- Merge gate and milestones aligned to the two-PR split.

* feat(cli): M0 Ink frame-buffer controller for VP text selection

First implementation milestone of VP-mode mouse text selection: the Ink
frame-buffer foundation and its read-side wrapper, with the design's M0
go/no-go criteria proven by tests.

Extend the Ink patch into a small bidirectional frame controller. The
renderer now retains the composited cell grid, applies a selection-range
background highlight before serialization (allocating new cells so the
shared cached styled chars are never mutated), and publishes an immutable
frame each render. setSelection deduplicates and schedules exactly one
repaint through Ink's own throttle; getFrameController(stdout) exposes the
bridge to the application.

Add ScreenBuffer, the read-side wrapper the selection state machine (M1)
will build on: getCellAt / lineText / dimensions plus setSelection and
subscribe. Tests cover addressable cells, wide-character spacer handling,
pre-serialization highlight and clear, no highlight leakage onto identical
on-screen text, and single-frame-per-change dedup (no render loop).

The package.json export additions from the existing patch are preserved.

* feat(cli): M1 mouse text selection with live highlight in VP mode

Turn mouse press/drag/release in the VP history viewport into a text
selection, highlighted live and copied on release.

- SelectionState: anchor/focus model in composited-frame coordinates,
  normalized to reading order, with collapsed/empty queries.
- selection-text: extract the visual text of a range, emitting a wide glyph
  once (skipping its spacer) and trimming per-line trailing padding. B1
  fidelity — visual cells as shown; soft-wrap rejoin and gutter exclusion
  are PR 2.
- selection-coords: map a terminal cell to frame grid coordinates via the
  frame anchor (bottom-pinned on overflow), plus viewport bounds/clamp.
- TextSelectionController: headless controller that subscribes button-level
  mouse events, drives the state machine, highlights the range through the
  frame controller (setSelection), and copies on release. Ignores the
  scrollbar column and presses outside the viewport; clears on any scroll
  (visible-region only in B1).
- VirtualizedList/ScrollableList expose getViewportRect(); MainContent mounts
  the controller in the VP branch.

Copy-failure feedback, key preemption (Esc/Ctrl+Shift+C), streaming/resize
invalidation, and word/line selection follow in M3/M4.

* feat(cli): gate VP text selection behind ui.textSelection settings

Add ui.textSelection.enabled (default true) and ui.textSelection.copyOnSelect
(default true) and wire them into the selection controller: selection is only
active when enabled, and release copies only when copyOnSelect is on. Disabling
enabled leaves the mouse to the terminal for those who prefer it.

* feat(cli): M4 word/line select, selection invalidation, and docs

- Double-click selects a word, triple-click selects a line, driven by a
  multi-click detector in the controller; word/line spans come from the
  composited frame (non-whitespace run / first-to-last-content cell) and are
  copied on select.
- Invalidate the selection when the content scrolls, streams (scrollHeight
  changes), or the terminal resizes (frame height changes / resize event),
  detected via a frame subscription with a baseline captured at selection
  start. Our own highlight renders leave those unchanged, so there is no
  render loop.
- Document mouse selection in the keyboard-shortcuts reference and the
  ui.textSelection settings in the settings reference; refresh the
  useTerminalBuffer description and regenerate the IDE settings schema.

A single click already clears a selection, so Esc-to-clear, the manual
copy keybinding, the footer "copied" toast, and a drag discoverability hint
are deferred follow-ups within this PR.

* fix(cli): drop redundant resize listener in selection controller

Real-terminal testing surfaced a MaxListenersExceededWarning (11 resize
listeners) on startup: the selection controller added a stdout 'resize'
listener on top of the existing ones. A resize reflows content, which changes
the frame/scroll height already watched by the frame subscription, so the
explicit listener was redundant. Remove it to stay under the max-listeners
cap; invalidation on resize still works via the subscription.

* fix(cli): close VP selection review gaps

* refactor(cli): make VP text selection unconditional

* fix(cli): make VP mouse selection usable

* fix(cli): preserve selection in thought blocks

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-17 08:04:07 +00:00
ytahdn
0ecba4b3c7
feat(web-shell): add skill management pages (#7018)
* feat(web-shell): add skill management pages

* fix(cli): inject GitHub token for skill installs

* test(integration): include skill management capability

* fix(cli): harden skill installation failures

* fix(skills): preserve management compatibility

* fix(cli): isolate skill install transactions

* fix(cli): address skill install review findings

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-17 06:42:46 +00:00
samuelhsin
b40978d6e6
feat(serve): add GET /workspace/:id/session-info for session totals (#7077)
Expose persisted active/archived/total (plus live) via a dedicated aggregate
endpoint so clients do not need to page the full session list. Counts reuse the
existing chats-dir disk scan pattern from session title search; responses mark
expensive/disk_scan so callers know not to poll.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-07-17 06:18:49 +00:00
jinye
b84ad89614
fix(core): Require explicit approval to exit Plan mode (#6967)
* fix(core): require explicit approval to exit plan mode

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

* codex: address PR review feedback (#6967)

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

* codex: address PR review feedback (#6967)

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

* test(core): cover plan exit denial guards

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

* codex: address PR review feedback (#6967)

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

* codex: address PR review feedback (#6967)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-17 02:51:11 +00:00
Shaojin Wen
c56ae42fed
fix(web-shell): batch transcript dispatch to avoid tab-return freeze (#7012)
* fix(web-shell): batch transcript dispatch to avoid tab-return freeze

Dispatching each buffered SSE event individually makes a tab-return burst O(events x blocks) on the main thread (per-dispatch block-array copy + freeze), freezing very long sessions for minutes. Coalesce the live stream into one dispatch per macrotask, cap the client's in-memory transcript window, and skip the dev-only block freeze in production.

* fix(web-shell): flush transcript buffer on teardown, guard freeze for browser

Address review feedback: teardown now flushes buffered transcript events instead of dropping them (the SSE client advances lastSeenEventId as events are yielded, so a dropped buffer would be skipped by a same-session incremental resume). Guard FREEZE_TRANSCRIPT_BLOCKS with typeof process so an unbundled browser consumer of the daemon/ui surface does not throw a ReferenceError. Add a dispatch-count assertion to the burst test and an unmount-flush regression test, and align the design doc (setTimeout-only flush, verification plan).

* fix(web-shell): flush before observer debug guard to keep assistant bursts in one block

Address ytahdn's PR #7012 review: the batched-dispatch debug guard read the committed store's activeAssistantBlockId, which lags the pending buffer within a burst, so a debug event interleaved in an observer assistant burst was not filtered and split the block. Flush the buffer before the guard, scoped to observer-mode debug events (rare) so steady streaming keeps batching. Add a focused burst regression test, make the unmount-flush test deterministic with fake timers (it was timing-racy), and update the design doc.

* fix(web-shell): flush buffered transcript on SSE loop error

The catch block at the end of the connection loop skipped the post-loop
flush, leaving buffered transcript events on a scheduled timer. The
retriable path resumes via Last-Event-ID without resetting the store,
and lastSeenEventId has already advanced past those events, so clearing
the buffer would drop them on the incremental delta-resume. Flush
instead.

Also route the restored-prompt settle and replay_complete control
dispatches through dispatchTranscriptNow so each is self-contained
(flush + dispatch) rather than relying on an earlier flush by timing,
and tighten the burst regression test from toContain(CHUNK_COUNT) to
toEqual([CHUNK_COUNT]) so a regression emitting redundant per-event
dispatches also fails.

Addresses the ci-bot review.

* fix(web-shell): keep a batched transcript dispatch throw from cascading

A reducer throw inside runTranscriptFlush escaped as an uncaught
setTimeout error on the macrotask path and, via flushTranscriptSync,
propagated out of the catch block (aborting lastSeenEventId bookkeeping,
reconnect, auth branching, terminal cleanup, and pendingSessionLoad
rejection) and out of the useEffect cleanup (leaving half-torn-down
state). Wrap the dispatch in try/catch and log it with the batch size so
the throw is surfaced without crashing the session or skipping teardown;
one guard fixes all three paths.

Also document the flush precondition on settleActivePromptFromTurnEvent,
which dispatches assistant.done directly and previously carried that
contract only as an inline comment at the call site.

Addresses the ci-bot review.
2026-07-17 00:58:27 +00:00
易良
f8e6e89316
fix(acp): disambiguate model routes (#7028)
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
* fix(acp): disambiguate model routes

* fix(acp): harden model route identity

* fix(acp): align workspace provider route identity
2026-07-16 18:24:41 +00:00
易良
0ba33dc743
fix: bound usage-only streams and abort on quit (#7038) 2026-07-16 18:11:53 +00:00
jinye
660ae9f712
feat(web-shell): add archived session export (#6910)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-16 17:38:43 +00:00
jinye
357660f32b
docs(serve): Close multi-workspace hardening gaps (#7019)
* docs(serve): close multi-workspace hardening gaps

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

* codex: address PR review feedback (#7019)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-16 17:33:53 +00:00
jinye
10a39d15d2
feat(daemon): Trace cold first-session startup (#6907)
* feat(daemon): trace cold first-session startup

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

* test: address PR review feedback (#6907)

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

* codex: fix CI failure on PR #6907

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

* codex: address PR review feedback (#6907)

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

* codex: address PR review feedback (#6907)

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

* codex: address PR review feedback (#6907)

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

* codex: address PR review feedback (#6907)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-16 16:53:56 +00:00
callmeYe
3d4601489e
revert: remove local PR verification gate (#7031)
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
Reverts QwenLM/qwen-code#6873 and QwenLM/qwen-code#7025.
2026-07-16 11:24:38 +00:00
ytahdn
bd87dcb5ce
fix(web-shell): filter sessions by source (#6995)
Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-16 04:56:50 +00:00
ytahdn
4bc31cb608
feat(serve): add workspace MCP management (#6954)
* feat(serve): add workspace MCP management

* fix(serve): refine workspace MCP management

* fix(web-shell): align MCP action expectation

* fix(serve): address MCP review findings

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.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-Coder <qwen-coder@alibabacloud.com>
2026-07-16 02:24:07 +00:00
jinye
ad65ba3bde
feat(daemon): Aggregate deep health across workspaces (#6961)
* feat(daemon): aggregate deep health across workspaces

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

* codex: address PR review feedback (#6961)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-16 01:30:55 +00:00
jinye
2e496b5ab8
fix(cli): Preserve channel startup failure details (#6950)
* fix(cli): preserve channel startup failure details

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

* codex: address PR review feedback (#6950)

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

* codex: address PR review feedback (#6950)

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

* codex: address PR review feedback (#6950)

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

* codex: address PR review feedback (#6950)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-16 01:17:19 +00:00
ytahdn
19fc52aa93
feat(daemon): add stateless generation SSE (#6947)
* feat(daemon): add stateless generation SSE

* test(integration): expect session generation capability

* fix(daemon): address generation review findings

* fix(daemon): harden generation regressions

* fix(daemon): preserve generation error events

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-16 00:00:08 +00:00
qqqys
859095bc98
feat(channels): support natural memory references (#6952)
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
* feat(channels): plan targeted memory intents

* fix(channels): harden targeted memory planner

* fix(channels): bound serialized memory manifest

* feat(channels): resolve natural memory references

* fix(channels): harden memory intent routing

* docs(channels): explain natural memory references

* fix(channels): type resolved memory intent dispatch

* fix(channels): route Chinese preference filters
2026-07-15 17:46:23 +00:00
顾盼
53ce8a2a40
fix(cua-driver): harden MCP tool reliability (#6968)
* fix(cua-driver): harden MCP tool reliability

* fix(cua-driver): address reliability review findings

* fix(cua-driver): keep config snapshots coherent

* fix(cua-driver): reject empty AX container trees

* chore(cua-driver): prepare v0.7.2 release
2026-07-15 15:40:31 +00:00
BaboBen
f5bdba724e
fix(wecom): prevent requireMention from disabling group chat (#6948)
* fix(wecom): trust group callback mention scope

Fixes #6939

* docs(wecom): clarify mention-scoped behavior
2026-07-15 15:38:21 +00:00
jinye
7a1b182cd1
feat(cli): Add archived session export (#6911)
* feat(cli): add archived session export

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

* codex: address PR review feedback (#6911)

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

* codex: address PR review feedback (#6911)

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

* codex: address PR review feedback (#6911)

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

* codex: address PR review feedback (#6911)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-15 12:21:07 +00:00
ytahdn
14993b1cf3
feat(daemon): add immutable session source metadata (#6932)
* feat(daemon): add session source metadata

* test(daemon): update baseline capabilities

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-15 07:35:41 +00:00
jinye
9cb09f4e2e
fix(core): Classify shell timeouts as tool errors (#6864)
* fix(core): classify shell timeouts as tool errors

Refs #6863

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

* codex: address PR review feedback (#6864)

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

* fix(core): Report no output for sed timeouts

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-15 05:34:39 +00:00
jinye
ca5019968a
fix(web-shell): harden non-primary archive actions (#6912)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-15 04:57:07 +00:00
morluto
41157205c1
fix(config): reject fractional session and tool-call limits (#6920)
* fix(config): reject fractional session and tool-call limits

* fix(config): validate persisted session turn limits
2026-07-15 04:56:52 +00:00
pomelo
389a1f9ceb
feat(cli): change default approval mode from default to auto (#6899)
* feat(cli): change default approval mode from default to auto

The default approval mode required manual confirmation for every tool
call, producing dozens of confirmation prompts per task. Auto mode uses
a three-layer filter (workspace edits, read-only allowlist, LLM
classifier) to auto-approve safe operations while still guarding risky
ones.

Untrusted folders are still forced to default mode for safety.

Closes #6898

* fix(cli): keep manual approval in safe and bare modes

Restricted modes (safe/bare) strip permissions, allowlists, MCP servers
and hooks to provide a maximally restrictive session. The new AUTO
default fallback was silently downgrading them to the LLM classifier,
contradicting their lockdown intent. Restore DEFAULT (manual approval)
for these modes while keeping AUTO as the default for normal sessions.

Explicit --approval-mode and --yolo flags still take effect, since they
are resolved before the fallback.

* chore(cli): regenerate settings schema for auto default

Regenerate the VS Code settings schema so the tools.approvalMode default
matches the new auto value (fixes the "settings schema is up-to-date" CI
check). Also add coverage for the serve-mode approval fallback when no
approval mode is configured.

* test(cli): update SettingsDialog snapshots for auto approval default

The settings schema now defaults tools.approvalMode to auto, so the
SettingsDialog renders "Auto" instead of "Ask permissions" for the Tool
Approval Mode field. Regenerate the affected snapshots (10 updated).

* test(core): pin DEFAULT baseline in agent-override tests

These tests exercise createApprovalModeOverride isolation and the
DEFAULT→AUTO rule strip/restore transitions, so they implicitly relied
on the Config constructor defaulting to DEFAULT. Now that the default is
AUTO, pin the baseline explicitly so the tests no longer depend on the
constructor default.

---------

Co-authored-by: pomelo.lcw <pomelo.lcw@alibaba-inc.com>
2026-07-15 04:55:32 +00:00
jinye
4f4387cf57
feat(core): add PDF vision bridge fallback (#6846)
* feat(core): add PDF vision bridge fallback

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

* codex: address PR review feedback (#6846)

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

* codex: address PR review feedback (#6846)

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

* codex: fix CI failure on PR #6846

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

* codex: address PR review feedback (#6846)

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

* codex: address PR review feedback (#6846)

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

* fix(cli): harden vision bridge output handling

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

* fix(cli): correct export sanitizer test typing

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

* fix(core): disclose selected vision endpoint before egress

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-15 03:42:14 +00:00
BaboBen
4b802ca5f9
feat(channels): support DingTalk webhook delivery to direct messages (#6891)
* docs(channels): design DingTalk webhook DM delivery

* docs(channels): translate DingTalk webhook DM design

* feat(channels): support DingTalk webhook direct messages

* fix(channels): isolate DingTalk webhook DM targets

* fix(channels): handle DingTalk direct delivery failures

* fix(channels): reject malformed DingTalk responses
2026-07-15 03:07:30 +00:00
callmeYe
441006b0e1
feat(scripts): add local PR verification gate (#6873)
* feat(scripts): add settings schema check mode

* feat(scripts): add local PR verification runner

* fix(scripts): harden local PR verification

* docs: document local PR verification gate

* fix(scripts): isolate local verification tools

* fix(scripts): scope PR formatting checks

* fix(scripts): skip symlinked PR paths

* fix(scripts): preserve verification gate integrity

* fix(scripts): canonicalize verification temp paths

* fix(scripts): stabilize local PR verification

* fix(scripts): clear built-in test credentials

* fix(scripts): enforce isolated test environment

* fix(scripts): serialize local verification tests

* fix(scripts): address PR verification review

* fix(scripts): preserve review git wrapper environment

* refactor(scripts): avoid step helper shadowing

* fix(scripts): distinguish forwarded child signals

* fix(scripts): preserve relayed signal exit codes
2026-07-15 00:58:17 +00:00
qqqys
fb0239eab4
feat(channels): add structured channel memory management (#6860)
* feat(core): add structured channel memory document

* fix(core): preserve legacy channel memory whitespace

* feat(core): structure channel memory storage

* fix(core): close channel memory races

* test(core): cover channel memory read failures

* feat(channels): parse channel memory item intents

* test(channels): cover memory intent precedence

* feat(channels): manage structured channel memory

* fix(channels): address structured memory review

* feat(cli): wire structured channel memory

* docs(channels): document structured channel memory

* fix(core): harden channel memory persistence

* fix(core): preserve channel memory uniqueness

* fix(channels): prioritize channel memory item updates
2026-07-15 00:44:15 +00:00
ranzhenyu
cf42ab6b7e
feat(acp): expose tool-call preparation lifecycle (#6819)
* feat(acp): expose tool-call preparation lifecycle

Why:
ACP clients receive no signal while providers stream tool arguments, making long calls appear stalled and delaying tool-identity policy decisions.

What:
- attach transient preparation metadata for Anthropic and OpenAI-compatible streams
- emit correlated ACP pending, execution, and discarded lifecycle updates
- preserve normalized call IDs across partial chunks and provider ID reuse
- clear abandoned retry calls and keep cleanup failures from terminating healthy retry/fallback streams
- deduplicate suppressed preparations and protect completed remapped parser buffers
- cover multi-tool Anthropic streams, ID reservation, TodoWrite suppression, retry cleanup, cancellation, and stream failure

Impact:
The metadata is additive and consumed only by ACP. It exposes no partial arguments, is not persisted to conversation history, and does not move permissions, hooks, scheduling, or execution ahead of complete function calls.

Tests:
- Core provider and stream suites: 649 passed
- ACP lifecycle suites: 316 passed
- npm run build
- npm run typecheck
- npm run lint:ci
- changed-file Prettier and git diff checks

Refs: #6775

* fix(acp): stabilize tool preparation lifecycle updates

Why:
- ACP cleanup failures must not convert a successful model stream into a failed prompt.
- A prepared tool call must be updated in place when execution starts instead of creating a second card.

What:
- Preserve the primary stream outcome when preparation cleanup fails and remove duplicate message display finalization.
- Track prepared call IDs so execution starts use tool_call_update, guard empty preparation metadata, and cover late stable IDs.

Impact:
- Ordinary tool calls keep their existing tool_call start frame.
- Streaming parser production behavior is unchanged.

* Update packages/cli/src/acp-integration/session/Session.test.ts

overrides参数在createPreparationResponse中被声明但从未使用——所有11个调用点仅传递callId且toolName. 该as GenerateContentResponse强制类型转换会绕过对始终为空对象的结构化类型检查。

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

* fix(acp): harden preparation lifecycle handling

Why:
- A malformed test helper prevented the preparation lifecycle suite from compiling.
- Duplicate preparing frames and state cleanup need direct regression coverage.

What:
- Repair the preparation response helper and isolate cleanup warning assertions.
- Suppress duplicate preparing frames and cover terminal cleanup plus missing tool call IDs.

Impact:
- Normal preparation and execution transitions remain unchanged.
- Repeated preparation frames for the same call ID are now ignored.

---------

Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
2026-07-15 00:40:02 +00:00
易良
d7e2892a7c
fix(cli): avoid updating active CLI processes (#6874)
* fix(cli): avoid updating active processes

* fix(cli): close update relaunch gaps

* test(cli): fix standalone update source path

* fix(cli): reset deferred update per relaunch
2026-07-15 00:33:17 +00:00
jinye
c538bd70d2
feat(core): emit liveness heartbeats for silent foreground shell commands (#6876)
* feat(core): emit liveness heartbeats for silent foreground shell commands

Silent foreground commands previously produced no events between spawn
and settle, so ACP gateways and stream-json consumers could not tell a
long-running command from a dead session. The shell tool now emits a
structured ShellProgressData through the existing updateOutput channel
whenever no display update has fired for tools.shell.heartbeatIntervalMs
(default 10s, 0 disables). Heartbeats carry liveness stats only - never
command output - and never enter model context.

Consumers: the ACP session forwards heartbeats as meta-only
tool_call_update frames (gated so a tick racing the settle path cannot
regress status after completion) and records heartbeat span attributes;
stream-json forwards them as tool_progress events behind
includePartialMessages; the TUI scheduler, React hook, and subagent
runtime ignore them so live output views are not replaced by stats
objects.

* docs(design): add silent command heartbeat design doc

* fix(acp): keep tool_call_update heartbeats from breaking in-repo consumers

Codex review of the heartbeat change found that in-repo ACP consumers
did not tolerate the new meta-only in_progress frames. A full sweep of
tool_call_update consumers found three that mishandled them, each now
guarded with a regression test:

- The desktop agent converted every tool_call_update into a terminal
  tool_result, so the first heartbeat would prematurely complete the
  command with an empty result. It now skips in_progress updates.
- DaemonChannelBridge requires kind on tool_call_update and flagged the
  kind-less heartbeat as a malformed-protocol error every interval. It
  now drops kind-less in_progress frames silently.
- The web-shell daemon UI normalizer derived the tool block title from
  _meta.toolName, overwriting the human-readable title on every
  heartbeat. It now drops heartbeat frames outright.

The remaining consumers (VS Code companion, acp-bridge compaction,
session export, daemon TUI adapter) merge updates conditionally and are
heartbeat-safe without changes.

* fix(core): address PR review — heartbeat monotonic gate, guard scope, telemetry

Review round 1 on #6876 (yiliang114, wenshao, chiga0, qwen3.7-max):

- shell.ts: the silent-idle gate now uses the monotonic performance.now()
  clock (via lastOutputPerfTime, falling back to spawn time) instead of the
  Date.now()-based lastUpdateTime, so an NTP step can neither skew the
  payload nor misfire a heartbeat — matching the design doc's monotonic
  commitment. It also keys off actual output arrival rather than the
  throttled display update.
- session-tracing.ts: endToolExecutionSpan now applies caller-supplied
  attributes BEFORE the canonical keys (duration_ms, success, error) so a
  passthrough attribute can never mask the span's own outcome fields.
- desktop qwen-agent.ts: the in_progress drop guard is now scoped to frames
  carrying _meta.shellProgress, matching the daemon bridge and web-shell
  normalizer guards, so a future non-heartbeat in_progress frame is not
  silently swallowed.
- Tests: the desktop regression test now pins result==='done' (previously
  it stayed green even with the guard removed); added a Session.test
  assertion that heartbeat counts reach the tool-execution span attributes.

* fix(acp): align desktop heartbeat guard with normalizer; test kind pass-through

Review round 2 on #6876 (qwen3.7-max via ci-bot):

- The desktop qwen-agent in_progress drop guard was broader than the
  web-shell normalizer's: it dropped any in_progress + shellProgress frame
  regardless of kind, while the normalizer only drops kind-less ones. The
  comment claimed they matched. Added the kind-absent check so the desktop
  guard matches the normalizer exactly — a kind-bearing frame now passes
  through on both platforms (heartbeats emitted by the ACP session never
  carry a kind, so real behavior is unchanged).
- Added pass-through tests on both sides (daemonUi + desktop) asserting an
  in_progress frame WITH a kind normalizes to a tool.update / tool_result
  rather than being dropped, so the load-bearing kind-absent condition is
  no longer only exercised on the drop path.

* fix(channels): scope daemon bridge heartbeat drop to shellProgress frames

Review round 3 on #6876 (qwen3.7-max via ci-bot): the DaemonChannelBridge
heartbeat guard lived in the shared tool_call / tool_call_update case and
dropped ANY kind-less in_progress frame, so a genuinely malformed kind-less
tool_call (status in_progress, no shellProgress) was silently swallowed
instead of reaching emitProtocolError. Gate the drop on _meta.shellProgress
— matching the qwen-agent and web-shell normalizer guards — so real
heartbeats are still dropped while malformed frames are flagged. Added a
regression test for the malformed path.
2026-07-15 00:07:26 +00:00
ytahdn
b59b341a0a
feat(web-shell): add extension management page (#6815)
* feat(daemon): support interactive extension installs

* feat(web-shell): add extension management page

* fix(web-shell): align extension update behavior

* fix(web-shell): polish extension management UI

* fix(extensions): harden interactive operations

* fix(web-shell): address extension review suggestions

* fix(web-shell): refine extension interaction handling

* fix(web-shell): resolve extension operation races

* fix(web-shell): harden extension action admission

* fix(web-shell): surface extension recovery failures

* fix(web-shell): preserve extension card titles

* fix(web-shell): refine extension card layout

* fix(extensions): address operation review findings

* test(extensions): close remaining review gaps

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: ytahdn <ytahdn@gmail.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-14 08:31:13 +00:00
jifeng
079ba35207
feat(web-shell): add selection statistics to markdown tables (#6838)
* feat(web-shell): add selection statistics

* fix(web-shell): clear stale table selections

* fix(web-shell): address selection statistics review
2026-07-14 03:54:33 +00:00