Commit graph

393 commits

Author SHA1 Message Date
jinye
889f0d8bbd
feat(daemon): Isolate the Conversations runtime boundary (#9181)
* feat(daemon): isolate the Conversations runtime boundary

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

* codex: fix CI failure on PR #9181

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

* codex: fix CI failure on PR #9181

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

* codex: address PR review feedback (#9181)

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

* codex: address PR review feedback (#9181)

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

* codex: address PR review feedback (#9181)

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

* codex: address PR review feedback (#9181)

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

* codex: address PR review feedback (#9181)

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

* codex: address PR review feedback (#9181)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-16 17:32:45 +00:00
易良
8a34d3eee1
test(web-shell): pin silent failure of background artifact refreshes (#7427) (#9227)
* test(web-shell): pin silent failure of background artifact refreshes (#7427)

The toast-spam behavior reported in #7427 no longer exists on main — loadArtifacts carries no notice dispatch and the hook swallows background-refresh failures, keeping the last-good artifacts. What was missing is a regression pin: add one that fails a background refresh and asserts last-good artifacts survive, loading clears, no error surfaces, and the next refresh recovers. Mutation-verified: clearing artifacts in the catch turns it red.

* test(web-shell): cover artifact refresh triggers

* test(web-shell): tighten artifact refresh assertions

* test(web-shell): settle artifact-refresh mocks via deferred awaits (#7427)

The two regression tests added here flushed their mocked refreshes with
a single microtask, so under full-suite parallel load the hook's refresh
continuation intermittently missed the React commit and the last-good
assertions saw artifacts === [] — a signature indistinguishable from a
real #7427 regression. Model every mocked load as a deferred and
resolve/reject + await it inside act, the shape the file's pre-existing
tests already use (review round, 7 fragile flush sites).

Also fold in two review pins while the tests are being rewritten:
- R2-2: the superseded-failure test now rejects the stale load while
  the superseding load is still in flight and asserts loading stays
  true — the requestId guard in the finally cleanup becomes
  load-bearing (mutation-verified: dropping the guard fails the test).
- add a waiting -> idle settling-trigger test so the prompt guard
  cannot be specialized to 'streaming' ('waiting' is a real prompt
  status).

* test(web-shell): pin the version bookkeeping and owner-guard halves (#7427)

- Non-monotonic artifactsVersion sequence (1->2->1 from a non-zero start)
  with exact loadArtifacts call counts: killing the previous-value
  bookkeeping silently skips the refresh that returns to a previously-seen
  version (stale artifacts panel, suite green) — measured mutant.
- Owner-flip supersede variant: the provider flips isCurrent() the instant
  the session switches, before a re-render; an in-flight load resolving in
  that window passes the requestId half and only the !owner.isCurrent()
  half of the guard stops it from painting the previous session's
  artifacts — deleting that half left all prior tests green (measured).

* test(web-shell): pin superseded artifact successes

---------

Co-authored-by: yiliang114 <yiliang114@users.noreply.github.com>
2026-08-16 15:29:58 +00:00
jinye
34cc1c3ede
feat(web-shell): support text file attachments in the composer (#9180)
* feat(web-shell): support text file attachments in the composer

* fix(web-shell): thread file attachments through the retry lineage and reset paths

Review feedback on #9180: the turn-error retry lineage (CancelledRetryState,
failedTurnErrorRetryRef, stash/restore sites) and the session-owner /
identity-mismatch resets managed text/images/inputAnnotations but not files,
which both dropped attachments on restored retries and could leak another
session's attachment into a retry. Also fixes stale enqueuePrompt arity in
the midTurnReconcile tests, chip a11y/truncation, and strips bidi/zero-width
characters from attachment names.

* fix(web-shell): win extension allowlist over conflicting OS MIME bindings

Round-2 review on #9180: .ts/.mts report as video/mp2t (IANA binding) and
.csv/.tsv as application/vnd.ms-excel on Windows+Office, so the non-empty
MIME early-return made the extension allowlist unreachable for flagship
source files. Extension and well-known-name (Dockerfile/Makefile/LICENSE/...)
fallbacks now apply even when a conflicting MIME is present; the downstream
NUL sniff still rejects actually-binary content. Also adds the failed-prompt
retry variant with files, the full-shape file assertion, and the
cancelled-retry no-resubmit pin from the round-2 test suggestions.
2026-08-15 16:34:20 +00:00
Heyang Wang
9f8f65dde0
feat: support fork from any conversation (#8817)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (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
Security Checks / Dependency CVE audit (push) Waiting to run
Security Checks / Secret scan (TruffleHog) (push) Waiting to run
* feat(web-shell): branch from completed assistant responses

Add durable response checkpoints so Web Shell sessions can branch from
eligible completed Assistant turns without mutating the source history.

- Record and validate checkpoints behind serialized topology fences
- Preserve historical anchors through replay, daemon, SDK, and UI layers
- Publish bounded forks with crash-safe ownership and referenced backups
- Serialize prompt, rewind, branch, automatic turn, and close mutations
- Cover stale anchors, replay pagination, cleanup, and pending UI states

Note: Responses recorded before this change remain non-branchable.

# Conflicts:
#	packages/acp-bridge/src/bridge.ts
#	packages/acp-bridge/src/bridgeTypes.ts
#	packages/cli/src/acp-integration/acpAgent.test.ts
#	packages/cli/src/acp-integration/acpAgent.ts
#	packages/cli/src/serve/routes/session.ts
#	packages/cli/src/serve/server.test.ts
#	packages/core/src/services/chatRecordingService.ts
#	packages/core/src/services/sessionService.test.ts
#	packages/core/src/services/sessionService.ts
#	packages/sdk-typescript/src/daemon/DaemonClient.ts
#	packages/web-shell/client/components/MessageItem.tsx
#	packages/web-shell/client/components/MessageList.tsx

* fix(session): preserve historical branch checkpoints

Keep Assistant-response branching intact across the daemon stack after
rebases, including history serialization and persisted-session ownership.

- Forward durable checkpoint IDs through Bridge, SDK, and UI layers
- Serialize live history mutations and retain valid nested branch anchors
- Preserve persisted branches during generation cleanup
- Add cross-layer regression tests for replay and stale checkpoints

* fix(web-shell): harden response session branching

* chore: remove PR comment evaluation artifact

Keep the PR review report as a local ignored backup instead of
shipping it with the feature branch.

- Remove the generated PR comment evaluation from tracked files
- Preserve the report under the ignored analyze directory

* fix(web-shell): guard historical branch mutations

Historical branch requests could outlive the client timeout during an
active turn, and interactive forks lacked the recorder's cross-process
writer-lease barrier.

- Hide Assistant Branch actions while a turn is active
- Run interactive fork creation inside the recorder write barrier
- Use the concrete checkpoint recorder contract in Session
- Document committed-session ownership and implemented design status

* perf(core): index historical branch points during transcript scan

Build branch catalogs during the frozen index scan so the first history
page no longer reopens and materializes the complete active chain.

- Retain a compact projection for shared branch-point resolution
- Correlate live branch anchors with the completed prompt and final reply
- Complete recorder mocks required by the concrete Session contract
- Update the reviewed design with performance and correlation invariants

* fix(core): address review findings — dead code, boundary remap, promptId guard, stale toast (#8274)

* fix(core): address review findings — dead code, boundary remap, promptId guard, stale toast (#8274)

* fix(core): address review findings — archived GC, subtype registration, UUID validation, dead code (#8274)

* test: strengthen branch-point and fork coverage from review (#8274)

Add focused tests requested in PR review:
- branch catalog resolves checkpoints that fall on a later page
- accept a parallel tool batch closed within a single turn
- exercise the linkSync->copyFileSync fork backup fallback success path
- prove a remapped checkpoint stays usable via a nested fork
- isolate each branch-point validation conjunct across bridge and SDK

* fix: address round-4 review feedback for session branching (#8274)

- Make the directory-fsync durability test platform-aware (skip on win32),
  since fsyncDirectoryBestEffort swallows the injected error on Windows and
  the rejection path is non-Windows by design.
- Reject atRecordId on the side-task fork path instead of silently discarding
  it, so the API surface no longer implies acceptance.
- Correct the design doc: name the real promptQueue FIFO (not the nonexistent
  historyMutationQueue) and describe filtered checkpoint boundaries as
  remapped to the nearest retained predecessor, not unconditionally null.
- Add focused tests: branch-point assistantRecordUuid mismatch rejection, and
  insight-block branchRecordId anchoring (insight-only block must not anchor
  onto the previous reply).

* fix: address round-5 review feedback for session branching (#8274)

* fix: address round-6 review feedback for session branching (#8274)

* fix: address round-7 review feedback for session branching (#8274)

* fix(core): harden branch-point resolution against malformed transcript shapes (#8274)

- Filter null/non-object part elements in the shared branch resolver so a
  transcript containing null parts no longer makes forkSession throw a
  TypeError for every checkpoint.
- Tag tool calls carried in from the pre-boundary prefix so a dangling call
  left by a crashed turn no longer permanently disables checkpoint
  recording; only calls issued inside the turn must close.
- Merge duplicate-uuid records first-wins for identity fields in the
  transcript reader, matching the byUuid index and fork aggregation, so the
  reader never advertises a branch marker the fork path must reject.

* fix: address round-8 review feedback for session branching (#8274)

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

* fix: address round-9 review feedback for session branching (#8274)

* test(core): pin branch GC isolation from throwing warning callbacks (#8274)

* fix(acp-bridge): reject rewind at admission while a prompt is active (#8274)

* fix(web-shell): harden session branch publication

Preserve direct ACP prompt preemption while fencing branch and rewind history mutations at the Session boundary. Convert branch publication, backup staging, cleanup, and stale-claim GC to asynchronous filesystem APIs, and surface unsupported hard-link commits as typed ACP and HTTP errors. Expand regression coverage and update the reviewed design contract.

* fix(web-shell): harden historical response branching

Reject branches during prompt admission and keep dispatched mutations
owned until their real outcome is known.

- remove detached timeouts across ACP, SDK, and WebUI
- bound branch cleanup and make title scans asynchronous
- avoid full branch-point scans during transcript pagination
- add regression coverage from Core through the real daemon and browser

* fix: address round-11 review feedback for session branching (#8274)

* fix: address round-12 review feedback for session branching (#8274)

* refactor(branching): remove branch-specific overdesign

Simplify historical session branching around the minimum persistence,
recording, and navigation invariants required by the Web Shell flow.

- Replace branch claims and garbage collection with staged publication
- Validate completed turns incrementally instead of reloading transcripts
- Separate persisted branch creation from live session restoration
- Bound SDK waits and prevent late results from replacing navigation
- Remove unused checkpoint prompt IDs while reading legacy records

Note: A pre-commit crash may leave hidden staging or orphan backups.

* chore(sdk): update browser bundle budget

Account for the combined historical branching and transcript projection APIs after merging main while keeping the browser bundle size guard narrowly bounded.

* fix(branching): address review lifecycle gaps

Harden historical session branching against cancellation, observer,
navigation, and shutdown races found during review.

- Normalize cancellation keys and bound close-time mutation waits
- Preserve anchors after observer completion and load persisted forks
- Report success only when the guarded session switch starts
- Cover recorder cursors, fork cleanup, admission, and rollback
- Align daemon events and branch errors with runtime behavior

* refactor(session): simplify branching safeguards

Reduce the session branching surface after review while preserving the
critical concurrency, durability, and ownership guarantees.

- Remove the unused full-chain resolver and test production entry points
- Copy backups from verified open handles instead of using hard links
- Reuse the bounded title scan instead of maintaining an async mirror
- Deduplicate UI branch requests and fail fast for busy automatic turns
- Consolidate repeated mutation tests and retain critical race coverage
- Document the retained invariants and rejected overdesign explicitly

* test(branching): simplify regression coverage

Reduce duplicated branching tests while retaining regression coverage for
the safety, concurrency, and lifecycle fixes introduced by this feature.

- Consolidate symmetric bridge and agent scenarios with table-driven cases
- Remove repeated cross-layer assertions and brittle implementation spies
- Drop redundant UI permutations and branch-only visual snapshots

* fix(serve): handle branch busy admission

* fix(sdk): preserve v1 branch session contract

Keep existing latest-state branch callers source- and wire-compatible while
retaining the persisted-only behavior for historical checkpoint branches.

- Restore no-anchor branches before returning their live client identity
- Add a separate typed result for persisted historical branch requests
- Clean up restored attachments on stale navigation and disconnect races
- Cover immediate continuation and historical persistence independently

* fix(daemon): guard branching history mutations

Prevent branch creation and automatic Goal turns from racing session
teardown or interactive history mutations.

- Reject branch admission while a conditional close is authorized
- Serialize Goal continuations behind the history mutation gate
- Limit branch checkpoints to interactive prompts
- Add regressions for close and Goal scheduling races

* fix(branching): preserve fork and checkpoint semantics

Keep branch checkpoints and file-history snapshots correct across resumed,
forked, and non-interactive session flows.

- Track the restored active-chain base before the first appended turn
- Preserve backup file modes during fork publication
- Exclude authenticated channel prompts from checkpoint recording
- Add regressions for all three review failures

* fix(branching): harden branch and rewind behavior

Handle the remaining branch and rewind review findings without widening
the feature contract.

- Ignore benign concurrent branch rejections in the Web Shell
- Validate rewind prompt IDs before using string operations
- Pin mutation ordering, cleanup, compaction, and checkpoint invariants
- Align sourced-fork fixtures with the canonical side_task value

---------

Co-authored-by: heyang.why <heyang.why@alibaba-inc.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: 易良 <1204183885@qq.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-Coder <qwen-coder@alibabacloud.com>
2026-08-15 10:01:49 +00:00
samuelhsin
c396fe3d12
fix(web-shell): share at mention providers with split-view panes (#9052)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
Security Checks / Dependency CVE audit (push) Waiting to run
Security Checks / Secret scan (TruffleHog) (push) Waiting to run
* fix(web-shell): share at mention providers with split-view panes

Split panes ignored host atProviders and builtinAtProviders, so custom categories vanished and Extensions came back.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web-shell): share customization with side task panes

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-14 17:45:18 +00:00
ytahdn
a669957f3d
feat(web-shell): fold thinking into the compact-mode tool summary (#9148)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (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
Security Checks / Dependency CVE audit (push) Waiting to run
Security Checks / Secret scan (TruffleHog) (push) Waiting to run
Compact mode used to drop thinking messages entirely, so a running turn
gave no indication of the thinking step. Keep the thoughts and aggregate
them with the adjacent tools into one summary: a streaming thought reads
"Thinking…" with the running shimmer, and a completed thought settles into
a click-to-expand row in its original interleaved position. The translate
action is preserved on both the thinking block and the folded thought
rows, and the merged group gets a synthetic id so its expanded state never
leaks into non-compact mode.

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-14 11:01:09 +00:00
ytahdn
c5bf222474
fix(webui): revert #8882's transactional session switching to the loading-skeleton model (#9129)
The transactional cross-session switching from #8882 staged a handoff and
kept the old attachment live until the target load committed. It added a
large transition state machine (intent staging, same-session capture,
watchdog deadlines, controlled rebind) across the daemon session layer
and the web-shell provider, and left the UI pinned to the previous
session while a switch prepared.

Restore the loading-skeleton model: switching a session clears the
transcript, shows the loading skeleton, and waits for the load result.

- Remove sessionTransition state, onSessionTransitionCommit and the
  transactional target logic from WorkspaceSessionProvider.
- Strip the transition state machine from DaemonSessionProvider and
  restore single-session restores: restore_in_progress retries stay
  bounded by the existing watchdog, and the skeleton UI keys on
  loadingTranscript.
- Move useDaemonSessionOwnerGuard back under the daemon index export.
- Delete the transactional design docs and both daemon integration
  tests; the restored behavior is covered by unit tests.
- Drop the dead desiredSessionTargetPending prop (write gating now keys
  on loadingTranscript alone) and stop a failed switch's target
  workspace from leaking into the next workspace-less load.

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-14 08:00:25 +00:00
qqqys
8517fa9d47
feat(web-shell): redesign Channel policy and workspace management (#8848)
* feat(web-shell): expose channel access policies

* test(cli): cover shared Channel management fields

* feat(web-shell): clarify channel policy controls

* feat(web-shell): select channel workspace

* feat(web-shell): redesign channel management

* fix(web-shell): align channel manager with shell tabs

* fix(web-shell): prioritize conversation settings

* fix(web-shell): preserve legacy channel defaults

* fix(channels): address management review blockers

* fix(channels): address editor review blockers

* fix(channels): preserve workspace action and route state

* fix(web-shell): prevent stale channel editor state

* fix(channels): preserve stored group settings

* fix(channels): preserve group behavior settings

* fix(web-shell): reset channel workspace UI state

* test(web-shell): assert restored channel scope

* fix(web-shell): preserve legacy channel scope

* fix(web-shell): preserve inherited channel defaults

* fix(channels): preserve compatible legacy settings

* fix(web-shell): keep workspace navigation available

* fix(channels): default new channels to pairing

---------

Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com>
2026-08-14 07:41:44 +00:00
carffuca
f2534765b6
fix(web-shell): defer assistant footer during background agent work (#8787)
* test(web-shell): reproduce premature assistant footer

* fix(web-shell): defer assistant footer during agent work

* refactor(web-shell): clarify incomplete turn state

* test(web-shell): cover stale agent footer states

* test(web-shell): cover background agent reconciliation gaps

* fix(web-shell): bound background agent footer state

* fix(web-shell): gate assistant footer on live agent state only

The footer gate keyed off forced-pending background-agent cards that
static transcripts never reconcile, hid completed turns' actions when a
stale card lingered, and polled the daemon every 3s forever. Scope the
active-agent gate to interactive sessions where reconciliation can
classify cards, compute incompleteness per turn, bound the
unmatched-completion hold with a grace timer, and make reconciliation
terminate via backoff, repeated 404 misses, and terminal 4xx handling.
Move the subagent 404 contract into typed SDK guards.

* fix(web-shell): address review feedback on background agent footer gating

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

* fix(web-shell): bound reconciliation retries and re-arm completion grace

Cap the background-agent reconciliation retry chain so a persistently
erroring daemon route cannot be polled indefinitely: once the retry
budget is exhausted, agents still erroring are marked failed so the UI
unblocks, while agents answering non-terminal stay pending and rely on
their completion notification. Key the backoff by session + pending set
so other agents' notifications cannot reset it, clear 404 miss counts
across connection transitions, classify a 404 body with a null
toolCallId as session-level, and reset the unmatched-completion grace
when the grace window reactivates after a catch-up cycle.

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

* fix(web-shell): keep background agent completion queries retryable

Separate the reconciliation backoff counter from the transient-error budget so
healthy `running` responses back off without consuming the failure budget,
keeping the completion notification's final query retryable. Reset the budget
on reconnect and bound the unmatched-completion turn-collapse hold. Add
regression coverage for multi-agent budget exhaustion, miss-counter re-arming,
foreground-agent footer gating, and the reconnect budget reset.

* fix(web-shell): re-arm grace latch per episode and guard round reuse

Key the unmatched-completion grace reset on the hold itself so a benign
matched-completion hold that expires mid-turn cannot consume the latch
before a genuine lost-completion episode begins in the same turn. Track
whether a cached reconciliation round was already processed so an effect
re-run (for example a client identity swap) issues a fresh query instead
of attaching a second handler to the settled promise and counting the
same round twice against the retry budget. Add regression coverage for
both fixes, for the grace timer restart on mid-hold agent notifications,
and for the healthy sibling continuing to poll after budget exhaustion.

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

* fix(web-shell): scope grace to unmatched episodes and per-agent retry budgets

Route session-level 404s through the missing-agent grace instead of
failing the card on first occurrence: multi-workspace daemons answer
that shape while the owning workspace runtime is merely transiently
inactive. Count grace misses only in the active round's handler so a
superseded round's late 404 cannot consume the live round's grace, and
track the transient-error budget per callId so one agent's persistent
errors can no longer fail healthy siblings. Release the
unmatched-completion hold entirely once its grace expires regardless of
notification ordering, key the grace latch on the unmatched set so
monitor and earlier-turn notifications cannot restart or re-arm it, and
pause the grace timer while streaming hides the turn.

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-Coder <qwen-coder@alibabacloud.com>
2026-08-14 06:16:46 +00:00
ytahdn
30134200a9
fix(web-shell): surface loop detection turn errors (#8853)
* fix(web-shell): surface loop detection turn errors

* fix(cli): expect loop-detected turn error in invalid-params stop test (#8853)

* fix(cli): reject loop-detected stops only for foreground ACP turns

Stop-hook continuations are shared with cron and background-notification
turns, which must keep their pre-loop-error graceful end-turn handling;
only the foreground prompt chain now rejects a loop-detected stop.

Also folds in review feedback: drop the unreachable repeated-failure
branch from the continuation, extract the cancellation-precedence
helper, defer and freshness-guard the bounded-refresh turn-error replay,
skip the phantom forward-failed compensation for structured turn errors,
key the structured code gate on structuredness, share the retryability
predicate in Web Shell, and keep the turn_complete error signal alive
for loop-detected turns.

* fix(acp-bridge): harden loop-detected turn errors per review feedback

Address round-3 review findings:

- The bounded-refresh append guard no longer compares the in-memory
  turn_error against the last journaled event of any kind. The published
  event is stored on the entry at broadcast time; any newer turn terminal
  clears it, and only turn-content events journaled after it block the
  append (queue/config bookkeeping no longer hides the error on refresh).
  The staleness check reads the in-flight journal via a new
  liveJournalSnapshot() accessor instead of flattening the replay window.
- Channel turns keep the graceful end-turn handling like cron and
  background-notification turns, so their collected text is still
  delivered when loop protection stops them.
- Loop-detected rejections drain the cron/notification queues in
  prompt()'s finally, preserving the pre-rejection drain invariant for
  queued automatic work.
- Tests pin each behavior: queued-bookkeeping refresh append, stale-error
  no-append, prompt_cancelled absence, foreground stop-hook rejection,
  background-notification graceful default, and the user-facing message
  constant.

* fix(cli): keep channel-prompt turns graceful on loop-detected stops

Channel tasks prompted through CHANNEL_PROMPT_META_KEY (DaemonChannelBridge /
AcpBridge) carry no channelDelivery meta, so the loop-protection exemption
keyed on channelDelivery missed them: a per-turn tool-call cap trip rejected
the turn with LOOP_DETECTED, the channel bridge never emitted promptComplete,
and the collected response text was lost as a failed task. Extend the
graceful end-turn exemption to channel-prompt-meta turns, mirroring the
repeated-failure guard forcing those turns already receive.

* fix(acp-bridge): keep loop turn error on refresh after idle bookkeeping (#8853)

* fix(acp-bridge): harden loop-protection turn state per review feedback (#8853)

* fix(acp): gate channel-turn classification and harden loop-error refresh replay (#8853)

Close two trust-gate gaps in the channel-turn classification introduced
for loop-detected turn errors: the `qwen.daemon.channelDelivery` sibling
key was not gated like `qwen.channel.prompt` at the standalone ACP
boundary, and on the daemon-hosted path a client-forged
`qwen.channel.prompt` survived the serve route and bridge admission strip
to be re-injected for trusted parents. Both keys are now stripped from
untrusted callers and honored only from trusted context (private parent
state, or the channel-worker prompt authorization validated by the daemon
prompt route).

Also harden the refresh-append guard for pending turn errors: the
synthetic `history_truncated` journal marker and idle latest-wins
`session_update` snapshots no longer defeat the append, and a queued
terminal that folds newer turn content supersedes the stale error before
the fold erases the evidence. Web Shell now derives turn_complete's error
from the same backward walk as the retry decision.

* fix(acp): close loop-protection bypasses in delivery classification and retry re-arm (#8853)

* fix(acp): cover idle workspace fan-out events in the refresh-append allowlist (#8853)

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

---------

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-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-14 06:14:06 +00:00
ytahdn
933a5203cb
fix(web-shell): soften tool execution failure hints (#9053)
* fix(web-shell): soften tool execution failure hints

Tool failures no longer advertise themselves as text in the collapsed
tool-group summaries: the "Failed"/"执行失败" label is replaced with a
small error icon, the collapsed summary (single tool or aggregated)
drops the error marker entirely, and parallel agent summaries append a
plain-text failed count after the done counter. A failed single tool
shows the error icon in its expanded card title.

The failure is still discoverable inside the expanded view via the icon
and the tool output itself.

* test(web-shell): lock error-icon rendering and harden card title overflow

* fix(web-shell): keep failure evidence visible in icon-only error display

Address review feedback on the weakened tool error display: swap the
hand-rolled circle-X SVG for lucide's CircleXIcon, move the parallel
agents failed count ahead of the done counter so it survives the
summary tail truncation, and restore the error icon for shapes the
label-to-icon conversion left without any failure indicator (single
read tools and failed tools without result text). Lock each behavior,
including the cancelled-agent count, with focused tests.

* test(web-shell): pin failure icon accessible name and completed-card icon absence (#9053)

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

---------

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-Coder <qwen-coder@alibabacloud.com>
2026-08-14 02:15:08 +00:00
易良
6d18c8265f
fix(desktop): open remaining external links through the shell opener (#9111)
* fix(desktop): open remaining external links through the shell opener

The desktop webview can silently drop target=_blank requests. #9069 routed
Markdown and external_url artifact links through the capability-scoped
opener; the remaining surfaces still relied on the unreliable implicit
new-window path. Add a shared useExternalLinkOpener hook and route the MCP
OAuth authorization link, the Git dialog PR link, code review evidence
links, and the auth-screen documentation/terms links through it, with
error toasts on failure. Plain browsers keep native anchor behavior.

Also collapse the two duplicated click handlers from #9069 into the same
hook.

Fixes #9108

* fix(web-shell): reuse auth terms URL

* fix(web-shell): route PR rows through opener

* fix(web-shell): keep PR rows as native links
2026-08-14 02:14:01 +00:00
易良
8e0033d64d
fix(ci): reduce ENOSPC and load-sensitive test flakes (#8982)
Some checks failed
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (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
npm cache producer / Save npm cache (push) Has been cancelled
* fix(ci): deflake the idle-watchdog env-parse script test

The test spawned three full agent subprocesses (~10s of wall time) to
pin a parse guard that is read once at module load. Under load spikes
on the shared self-hosted runner pool, one of those spawns failed or
stalled, failing CI at random (e.g. run 31556596385); the assertion
also discarded the script's failure.md, hiding the cause.

Collapse it to one run with the nastiest value (-1) — any armed
instant-true window kills the healthy stub agent at the first idle
tick — and assert on {status, failure} so a future flake names its
cause. Add retry: 2 to the script-test vitest config for the
remaining load-sensitive spawn tests; a real regression fails every
attempt.

* fix(ci): size test thread pools to the machine and retry load flakes

test:ci runs every workspace in parallel, and the cli/core suites each
pinned a fixed 8-16 thread pool regardless of the machine — on a 4-core
hosted runner that is an 8x oversubscription before any neighbor job
exists, and the shared self-hosted hosts run several registrations at
once. The contention is what blows the 15s ceilings those configs
already complain about: tests that pass locally in milliseconds time
out, and vitest workers lose their RPC under the pile.

Size the pools to os.cpus() (capped at the old fixed values so large
machines lose nothing) and add retry: 2 for the residual load spikes a
real regression still fails through every attempt of.

* fix(ci): restore the 0-boundary probe and right-size the deflake comments

Review feedback: the single -1 run could not catch a > 0 → >= 0
boundary edit (0 is the operator's documented disable sentinel and
would arm a zero-length window), and the comments overstated what the
run and the retry guarantee. Probe-verified: a >= 0 mutant now fails
the idleMs: 0 arm with the value named in the assertion diff. Two
short runs still halve the old three-run spawn volume. Reword the
retry comments to claim only deterministic regressions fail every
attempt.

* fix(ci): remove dead pool-resizing config and pin idle-timeout guard

The poolOptions.threads changes had no effect because vitest 3 defaults
to pool: 'forks', making minThreads/maxThreads inert. Revert to the
original fixed 8-16. The script-test deflake (idle-watchdog improvements,
retry: 2) is kept. Add a source-text pin for the Number.isFinite guard
in run-agent.mjs, covering the non-numeric class that subprocess-based
tests cannot exercise.

* fix(ci): capture the transient ENOSPC and shrink the manifest suite's inode hold

ENOSPC failed the Test step mid-suite on two different self-hosted
machines (actions-runner-test-22, actions-runner-test-11) in ~20s
bursts — 132 of 147 errors were mkdtemp failures — while the hosts
look healthy afterwards, so a post-mortem df finds nothing. Two
changes:

1. Sample /tmp space and inodes every 10s during the test step and
   dump the full df state when it fails, so the next occurrence
   records whether inodes or a tmpfs cap is what exhausts.
2. The manifest-repository-context suite held every 16k-file fixture
   tree until afterAll (~164k live inodes for the whole file); tear
   down per test instead so at most one tree is live at a time,
   removing the suite's own spike contribution either way.

* test(ci): pin the idle-timeout parse guard's source text for the NaN class

A healthy-agent run can never pin the non-numeric rejection class: a
NaN window never satisfies the >= kill comparison, so no run shape
fails on it. Pin the guard expression itself in the runner source
instead (this file's existing source-text pin style), and rename the
test to claim only the non-positive classes the runs actually pin.

* fix(ci): sample available memory alongside the ENOSPC diagnostics

The hosts' disks are verifiably not full, so byte exhaustion is out.
ENOSPC on a healthy disk points at a memory-backed limit instead: a
tmpfs /tmp or a job cgroup ceiling fails tmpfs writes with ENOSPC
while host memory is spiked by concurrent jobs, and clears within
seconds once they finish — matching the ~20s failure bursts. Sample
MemAvailable every 10s and dump /proc/meminfo on failure so the next
occurrence separates memory from inodes.

* fix(ci): limit retries to script tests

* fix(ci): route test temp files to the runner's disk-backed temp area

The ENOSPC bursts hit a host whose disk is verifiably not full, which
points at a memory-backed limit on /tmp (tmpfs mount or cgroup ceiling)
under concurrent-job memory spikes. Export TMPDIR=$RUNNER_TEMP for the
test step so mkdtemp traffic lands on the per-registration disk area
instead of the shared /tmp — curing the tmpfs case outright and also
stoping temp state from mixing across the several runner registrations
on one host. The sampler now reports the effective TMPDIR's filesystem.

* test(core): support long temporary workspace paths

* fix(ci): keep routed temp paths socket-safe

* fix(ci): use real short Linux temp paths

* test(ci): remove remaining teardown races

* test(ci): harden temp routing regression

* test(ci): stop leaked server reconcilers

* fix(ci): clean up test sampler reliably

* fix(review): keep skill context within manifest bounds

* test(web-shell): wait for image ingestion completion

* test(cli): avoid timed status line module import

* test(ci): remove remaining load-sensitive waits

* fix(ci): cap test forks on shared runners

* fix(ci): keep temp cleanup from failing tests

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-08-13 16:44:39 +00:00
易良
5c1d77a357
fix(desktop): open external URL artifacts and markdown links (#9069)
* fix(desktop): open external URL artifacts and markdown links

The Web Shell relied on the webview's implicit target="_blank" /
window.open handling for every external link. In the packaged desktop
shell that path silently drops failed new-window requests, so link
artifacts (type: link, storage: external_url) and markdown links in
assistant messages appeared styled but dead, with no error feedback.

Add an explicit open_external_url command to the Tauri shell (validated
against http/https/mailto, opened via the OS default browser) and route
external clicks through it when the Web Shell detects the desktop
bridge. The artifact details panel gains an "Open link" action next to
the Location URL, and failures surface as error toasts instead of
silent no-ops. Plain browsers keep native anchor behavior.

Fixes #9060; follows up on #8593 for the Tauri shell.

* test(web-shell): keep real ToastHost exports in App mock

The App test suite replaces ToastHost with a stub; after adding
TOAST_REQUEST_EVENT/requestToast to the module, the partial mock broke
every App test. Spread importActual so new exports stay available.

* fix(desktop): declare external URL permission

* fix(desktop): authorize remote external URL opens

* fix(desktop): normalize external opener URLs

* test(web-shell): pin desktop link click handling

* fix(desktop): route modified URL clicks
2026-08-13 15:11:44 +00:00
易良
71b45e3259
fix(web-shell): render a single archive action in the session toolbar (#9066)
* fix(web-shell): render a single archive action in the session toolbar

Read-only session rows render a dedicated archive control, but the shared action block kept contributing its own archive action whenever the row also showed pin (restricted secondary workspaces with the qualified REST core and session organization enabled). Both blocks render as stacked overlays, so the row ended up with two visually identical archive buttons after the pin action.

Make the read-only block the single owner of the archive action for those rows: suppress the archive entry (inline button and dropdown item) in the shared action block whenever the read-only block renders it. Pin and all other actions are unaffected.

* fix(web-shell): centralize archive action ownership

* fix(web-shell): keep archive actions pointer-accessible
2026-08-13 15:11:34 +00:00
Shaojin Wen
fe6d2ac36a
feat(review): require an executed witness on every confirmed Critical (#9065)
* feat(review): require an executed witness on every confirmed Critical

A confirmed Critical now carries a witness — the observed output that
settled the verdict (a probe's two sides, an A/B's quoted pair, an
extract-step run, a repo-wide sweep count) — or one line saying why no
run could settle the claim. A confirmed Critical carrying neither is
mechanically sorted to low confidence: terminal-only, never posted.

Mining the maintainer dogfood corpus (356 review sessions plus 182
real-environment verification sessions) measured what the optional
probe/A-B capabilities produce when left to verifier discretion: in the
rounds that held up, every posted hard finding quoted executed output,
and the one claim written from a reading alone was publicly retracted a
round later when its first measurement returned zero (PR 8225).

- SKILL.md: the witness rule and the impact sweep in Step 4; witness in
  the finding format, the findings artifact contract, the Step 7 inline
  comment bodies, and the Guidelines
- DESIGN.md: the decision narrative and two measured entries (the
  retracted read-only claim; the mirrored oracle's false positives)
- agent-briefs.ts: the verify brief demands the witness line (or its
  'not run' reason) with every confirmed Critical, and gains the
  impact-sweep capability with its external-authority guard
- findings.ts: optional witness field, round-tripped like outcomeNote so
  the report and comment bodies quote one recorded string

* feat(review): give the witness rule its machine half, everywhere the finding travels

Three findings from this PR's own dogfood review round:

- The demotion was promised as mechanical but no code read witness, and
  validateFindings defaults an omitted confidence to high — the
  fail-open direction. qwen review findings now demotes any
  high-confidence [review]-source Critical that arrives without the
  field to low confidence at canonicalization, naming each on stderr —
  the same place and shape as the test-delta holdback. Deterministic
  sources are exempt: a [build]/[test]/[probe] finding IS a run's
  output. Idempotent by construction.

- The pattern-aggregated format had no witness slot, so the executed
  evidence would vanish (or be improvised) exactly when one sweep
  confirms a whole Critical pattern. The Step 4 aggregate template and
  Step 6's enumeration gain the Witness line.

- The Web Shell renderer parsed every other optional evidence field
  and silently dropped witness from display. parseFinding carries it
  and the finding card renders it, with en/zh labels.

* test(review): seed the witness into the code-review visual scenario

The visual preview reported no screenshot change for the renderer edit
because no scenario reached the new UI: the code-review artifact
fixture carried no witness, so the row never rendered. The Critical now
carries one and the shot is gated on its visibility, so the scenario is
a coverage witness for the field, not just for the card.

* test(review): pin the witness rule's handler wiring end to end

The unit tests pin holdUnwitnessedCriticals in isolation; this pins the
wiring — an unwitnessed Critical fed through the findings command comes
out at low confidence with the stderr disclosure, and a witnessed
sibling stays high. Removing the call from the handler, or moving it
past buildReport, now fails a test instead of silently disarming the
rule.
2026-08-13 13:09:09 +00:00
ytahdn
a8bcaefea7
feat(web-shell): support workspace file uploads (#8874)
* feat: add web shell workspace file uploads

* fix(serve): accept plain string targets in shared atomic publisher (#8874)

* fix(review): bound web shell related paths

* fix(review): address web shell file upload review findings (#8874)

* test(serve): include upload capability in baseline

* fix(review): pin workspace_file_upload in the serve capabilities integration baseline (#8874)

* fix(review): address round-2 web shell file upload review findings (#8874)

* fix(review): address round-3 web shell file upload review findings (#8874)

* fix(review): address round-4 web shell file upload review findings (#8874)

* fix(review): address round-5 web shell file upload review findings (#8874)

* fix(review): address remaining file upload findings (#8874)

* fix(review): address round-6 web shell file upload review findings (#8874)

---------

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>
2026-08-13 06:42:07 +00:00
ytahdn
3fd40fd065
fix(web-shell): preserve standalone session target (#9038)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-13 05:53:35 +00:00
callmeYe
d912f4c6a8
feat(web-shell): configure Qwen 3.8 reasoning (#8974)
* feat(web-shell): configure Qwen 3.8 reasoning

* test(serve): update telemetry route audit counts

* fix(webui): serialize reasoning mutations with refresh

* refactor(sdk): reuse JSON request for config options

* fix(webui): discard stale session config snapshots

* fix(cli): hide controls for mandatory thinking

* test(cli): assert generic reasoning options
2026-08-13 05:01:03 +00:00
ytahdn
baab57c510
feat(web-shell): localize background task notifications with structured data (#8989)
* feat(web-shell): localize background task notifications with structured data

Background task completion notifications in the web shell were rendered as
hard-coded English strings, so they could not be localized. This change ships
structured task metadata (kind, status, description/command label, event count)
alongside each notification so the frontend can render it through the i18n
layer, and restyles the notification as a chat-style bubble. The metadata is
also persisted to the session transcript so localized text survives a page
refresh. Falls back to the original English text when structured data is absent.

* test(cli): repair Session mocks for notification registry lookups (#8989)

* fix(web-shell): review fixes for background notification i18n (#8989)

* fix(web-shell): review fixes for background notification i18n (#8989)

* test: pin zh-CN dropped-lines clause and shell/agent label sanitization (#8989)

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

---------

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-Coder <qwen-coder@alibabacloud.com>
2026-08-13 04:48:02 +00:00
Edenman
01ef9bc8b5
feat(web-shell): expose channel sessions in sidebar and settings (#8457)
* feat(web-shell): show channel sessions in sidebar

* feat(web-shell): configure channel session scope

* fix(web-shell): refresh channel session transcripts

* feat(web-shell): group channel sessions by platform

* fix(channels): address session review feedback

* test(web-shell): harden channel session coverage

* test: pin remaining channel session review findings

Close the round-1 review gaps the previous fixes left unpinned: the
channel-base/acp-bridge display-text wire key now has a cross-package
equality assertion, the secondary-workspace catalog test covers pinned
channel sessions, the collect-coalescing test pins the raw display text
when buffered messages carry model-only metadata, the editor descriptor
labels diverge from the i18n values so missing keys surface, and the
channels e2e asserts the legacy fixture is absent from the Tasks tab.

* fix: harden channel session sidebar and display projections (#8457)

Round-2 review fixes:

- Guard the sidebar channel-instance lookup with Object.hasOwn so a
  sourceId like 'constructor' cannot crash the Channels view through
  Object.prototype (R2-1).
- Drop the {text:''} part synthesis for empty displayText replays so
  image-only channel prompts stop emitting a spurious
  unknown_record_or_part diagnostic and complete:false (R2-2).
- Route the webhook display projection through the same
  truncate+sanitize treatment as the model prompt via a shared helper
  (R2-3).
- Refresh the per-workspace channel catalog on the session poll tick
  and render the channel list flat — never under organization groups —
  while the catalog is unavailable (R2-4).
- Remove the dead prompt re-truncation in sessionService (R2-5).
- Extract getChannelPromptDisplayText as the single source of truth for
  the echo, pending-entry, and re-arm display-text reads (R2-7).
- Add workspaceCwd to the channel e2e session fixtures (R2-8).
- Pin the archived source switch, the deleteSessionData validation
  contract, and the stale-response ordering guard with tests
  (R2-10, R2-11, R2-13).

* fix(channels): address session review feedback

* fix(channels): address channel session review feedback

* fix(channels): harden channel session review round-7 criticals (#8457)

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

* fix(web-shell): harden first-visit session section latches (#8457)

* fix(channels): address review round-8 findings (#8457)

* test(web-shell): pin round-8 sidebar behavior fixes (#8457)

* fix(channels): address review round-9 findings (#8457)

* fix(web-shell): pin Other channels group after platform sections (#8457)

---------

Co-authored-by: 克竟 <dingbingzhi.dbz@alibaba-inc.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.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: 丁炳智 <dingbingzhi@Edenmans-Office-Mac.local>
Co-authored-by: qwen-code-autofix[bot] <qwen-code-autofix[bot]@users.noreply.github.com>
2026-08-12 17:11:07 +00:00
qqqys
05079297d2
feat(cli): adopt Goal v3 in ACP sessions (#8732)
* feat(cli): adopt Goal v3 in ACP sessions

* test(cli): give the ACP Session fakes a Goal runtime

The Goal v3 adoption made the Session constructor bind the canonical Goal
runtime, and Session.prompt reserve a turn on it. Both call sites tolerate
GoalPersistenceUnavailableError and nothing else, so the two Session test
files that were not part of this change — Session.worktree.test.ts and
Session.review-lease.test.ts — died in the constructor with
"this.config.getGoalRuntime is not a function", failing all 12 of their
tests on Test (ubuntu-latest, Node 22.x).

Teach both config fakes to answer getGoalRuntime/getGoalRuntimeReady the
way a real Config does when Goal persistence is off: throw (reject with)
GoalPersistenceUnavailableError. That exercises the intended fall-through
and leaves what the tests actually assert — worktree notices and review
lease sweeps — untouched.

* fix(cli): settle Goal turns that fail, and answer goal RPCs without persistence

Addresses the three [Critical] findings from review 4888864998.

- R1-1 `#drainGoalQueue`: settle the turn in the catch. `prompt()` can
  reject before reaching the try whose finally settles it -- most easily
  via `assertCanStartTurn` throwing 'Session is closing' when
  `beginClose()` lands mid-await. The turn is already off `goalQueue` at
  that point, so the runtime kept `currentPermit` and `activity:
  'running'` forever: no further continuations were scheduled and every
  later prompt with an active goal hung in `claimGoalTurn` behind the
  leaked permit. `#settleGoalTurn` no-ops once the permit is no longer
  current and swallows its own errors, so calling it here is safe to
  repeat.

- R1-2 `sessionGoalGet`/`sessionGoalClear`: catch
  `GoalPersistenceUnavailableError` and fall back to the empty answers.
  `getGoalRuntimeReady()` rejects when `general.chatRecording` is off,
  and rejects permanently once `restore()` has set a sticky
  `recoveryError`; `extMethod` only converts `SessionWriterError`. That
  made `GET /goals` drop the session on every poll with a permanent
  non-zero `droppedCount` -- rendered as "couldn't probe N sessions",
  misreading a config choice as a wedged child -- and broke goal
  get/clear for a session with a malformed trailing goal record forever.
  Any other error still propagates.

- R1-3 `#settleGoalTurn`: a turn preempted by a newly arrived user prompt
  now settles via `finishTurn`, not pause. A goal turn's controller is
  `this.pendingPrompt`, so a new prompt aborts it with
  `NEW_PROMPT_ABORT_REASON`; whether that surfaced as a clean `cancelled`
  stop reason or as a throw from the model network await was pure timing,
  so the same user action persisted the goal as either active-with-handoff
  or paused. The paused branch also cleared the incoming prompt's queued
  reservation and silently stopped the autonomous loop. Scoped to the
  settle path rather than widening `isControlledCancellation`, which is
  shared with non-goal turns.

Tests: `releases the permit when the prompt rejects before the model
starts` (dropping the settle call fails it); two acpAgent cases pinning
the empty goal get/clear answers plus one pinning that a non-persistence
error still propagates (rethrowing in either handler fails the matching
case); `hands off a preempted Goal turn whose stream throws on abort`,
the throwing-stream twin of the shipped priority test (dropping the
superseded check fails it). `mockGoalRuntime` gains `dispatch` so pause
is assertable at all.

* fix(cli): stop Goal turns leaking permits, and show a paused goal as paused

Addresses four of the six Critical findings from review round 2 on #8732.
R2-2 (the `claimGoalTurn` / `#drainGoalQueue` deadlock) is not in this
commit.

R2-1: `#settleGoalTurn` awaited the recording-service `flush()` inside the
outer try, so a latched write failure — a taken-over transcript lease, for
one — skipped finishTurn/pause/releaseTurn entirely and stranded the
runtime's current permit. Isolates the flush, as the headless path's
`failClosedActiveGoalTurn` already does.

R2-4: `claimGoalTurn`'s immediate path never consulted `signal.aborted`, so
a prompt aborted while its preempted turn settled as a handoff claimed the
permit that handoff had just promoted to it, then took `prompt()`'s aborted
early-exit — which releases only when no goal turn was claimed. Checks the
signal before the immediate path.

R2-5: goal-persistence unavailability hard-failed `/goal` and `/goal clear`,
and in ACP an error return throws, failing the user's whole prompt request
for the rest of the session — while `sessionGoalGet`/`sessionGoalClear`
answer the same question fine. Those two operations now degrade to an empty
snapshot; set/edit/resume still fail, since they need persistence.
`emptyGoalSnapshot()` moves to core so both paths share one definition.

R2-3: the pause this PR introduces projects as `goalStatus {kind:'paused'}`,
which neither webui's `normalizeGoalStatus` nor web-shell's
`VALID_GOAL_KINDS` accepted. The card never rendered and the active-goal
derivation fell through to the previous `set` card, so every surface kept
showing a paused goal as actively running. Teaches both consumers the state
and renders it, rather than projecting `pause` to `aborted` — the CLI's own
GoalStatusMessage already renders `paused`, so this makes the web surfaces
match instead of inventing a third answer.

R2-6: a UserPromptSubmit hook that blocks the deterministic goal
continuation trapped an active goal in an unbounded
release -> requeue -> continuation loop, persisting a transcript record per
lap with no model call and no state change. A runtime continuation is
machine-generated, so it is now exempt from the hook for the same reason
`isContinue` already is.

Tests: goal turns settle when the transcript flush rejects; `/goal` and
`/goal clear` answer with an empty snapshot when persistence is
unavailable, while set/edit/resume still fail.

* fix(cli): unblock deadlocked Goal turns and stop a capped goal loop

Addresses four Critical findings from the round-3 review on #8732.

R2-2 — a prompt arriving while a goal-activating prompt is still
unwinding blocked forever in `claimGoalTurn`. Two entrances, both fixed:

- `#drainGoalQueue` is gated on `pendingPrompt`, so a continuation the
  runtime queued mid-prompt could not start until the waiting prompt
  finished, while the waiting prompt could not start until that
  continuation released the permit. An arriving prompt now drops
  un-started continuations, the way it already drops queued cron and
  notification work.
- `GoalRuntime.releaseTurn` minted a fresh continuation instead of
  promoting a waiting reservation, so a turn preempted before the model
  started handed the permit to a turn nobody could drain. It now
  promotes `queuedTurnKey` exactly as `finishTurn` does.

R3-2 — `#settleGoalTurn` isolated `flush()` from a latched recording
write failure but not the `pause` dispatch or `finishTurn` that follow,
both of which persist through `appendRecordStrict` and re-throw it. The
escaping error stranded `currentPermit`, the very state the flush
isolation exists to prevent. Both now fall back to the in-memory
`releaseTurn`.

R3-6 — `legacyStatusKind` projected cause `migrated` as `set`.
`createMigratedGoalState` only ever persists `paused`, so resuming a
pre-v2 transcript re-asserted an active goal to every client that
derives the live goal from the newest card.

R3-7 — the Stop-hook blocking cap called `abortGoalForStopHookCap`,
which reads only the legacy `activeGoalStore`; that store has no writer
for daemon sessions, so the cap stopped nothing and a blocking Stop hook
looped the goal forever. ACP now pauses the canonical runtime when the
legacy abort reports it did nothing.

Verified: npm run build, npm run typecheck, eslint on the six changed
files, vitest packages/core/src/goals + client-goal (316 passed),
packages/cli/src/acp-integration/session (898 passed), acp-bridge
transcript-replay (26 passed). Each new test mutation-probed: reverting
its fix turns it red.

* fix(cli): keep Goal degradation working headless and re-subscribe after /clear

Round-3 review findings R3-1 and R3-3.

R3-1: `goalCommand` degrades a persistence-unavailable `/goal status` and
`/goal clear` into a successful empty snapshot, but the headless
`goal_control` consumer immediately re-requested the very runtime that had
just failed, so `qwen -p "/goal status"` with `general.chatRecording: false`
(or a sticky `recoveryError`) exited 1 through the run-level crash path
instead of answering "No Goal is set.". Interactive and ACP already
degraded correctly; only the third mode crashed. The consumer now swallows
`GoalPersistenceUnavailableError` when the snapshot has no goal to drive,
and still rethrows when a worker is required.

R3-3: the ACP session subscribed to the Goal runtime once in its
constructor. `/clear` makes `Config.startNewSession()` dispose that runtime
and build a new one under the same long-lived `Session`, leaving the
subscription — the only path to `MessageEmitter.emitGoalState` — registered
on the abandoned instance, so no `_meta.goalState` update was ever delivered
again. `handleSlashCommand` now accepts session hooks, the ACP session
passes a `startNewSession` hook the way `clearCommand` expects, and the
hook unsubscribes, resets the publication de-duplication state and rebinds.

Both are pinned by tests that fail without the change.

* fix(cli): repair Goal recovery on ACP resume

Three Criticals from review round 4, all on the resume path.

R4-2: with `experimental.sessionWriterLease` on, the recorder starts
`inactive` and rejects every write until `activateChatRecording()` hands
it the lease — but the Config constructor kicks `runtime.restore()` off
immediately. The legacy-migration journal write lands in that guard,
`restore()` latches the failure as `recoveryError` for the life of the
runtime, the migrated goal is dropped, and every later dispatch/
finishTurn/releaseTurn rethrows. Probe-confirmed before fixing:
`getGoalRuntimeReady()` rejected with `GoalPersistenceUnavailableError:
Session write ownership could not be verified.` The restore is now
deferred while the writer cannot accept writes and run from
`activateChatRecording()` once the lease is in hand — against the
authoritative transcript activation just loaded, which is fresher than
what the constructor had. Paths where the writer never arrives
(activation failure, shutdown, a superseding session) settle the deferred
restore with that error rather than leaving awaiters pending forever.

R4-1: Goal recovery's correction broadcast fires from the Config
constructor, before `Session.#bindGoalRuntime` exists to subscribe, and
replay streams the pre-migration records — so the newest goal card the
client sees is the legacy `set` one and card-derivation clients showed a
phantom running goal until a second reload. `GoalRuntime` now retains the
cause its restore broadcast carried, and `createAndStoreSession`
republishes the recovered state after `replayHistory`, which puts the
`migrated -> paused` projection after the replayed card.
`#publishGoalState` already de-duplicates on `(cause, snapshot)`, so this
is a no-op when the subscription did deliver it.

R3-6 (second trigger): when `recoverGoalFromRecords` returns
`'unsupported'`, there is no state to publish and no in-session command
corrects the stream — a degraded `/goal` answers without a cause, which
no client card-derivation reads. That case now emits the same trailing
`cleared` card the removed `supersedeUnrestorableGoal` did, emitted and
not recorded so a later resume can still restore the goal.

Six new tests, each mutation-verified against the regression it names.

* fix(acp-bridge): replay paused goal cards instead of dropping them

R5-20: `TRANSCRIPT_GOAL_STATUS_KINDS` omitted `paused`, so a legacy
`goal_status` card with that kind was parsed away during transcript
replay. Dropping it is not neutral: the replay stream is what feeds the
goal renderer, so the older `set` card stayed newest and every surface
kept claiming autonomous work was under way.

This closes the same gap this PR already closed one layer up, in
web-shell's `VALID_GOAL_KINDS` — the renderer learned to draw a paused
card, but the replay machine ahead of it still discarded the record, so
that fix never took effect on the replay path. The set now matches
`GOAL_STATUS_KINDS`, which the daemon-side reader (`parseGoalStatusItem`)
validates the same on-disk cards against.

Regression test added and mutation-checked: removing `paused` again
fails the new case with the paused card projecting to no update at all.

* fix(core): report a lost session writer as a Goal persistence failure

`dispatch` awaited `journal.recordGoalState` unguarded, so a lost session
writer escaped as `SessionWriterUnavailableError` or as the raw latched
write failure — the two errors `appendRecordStrict` actually throws.
`restore` already converts the same call's failures, so callers reasonably
key the "no persistence, so no goal" degradation off
`GoalPersistenceUnavailableError` alone.

The gap is user-visible on the ACP path: `goalCommand` degrades `status`
and `clear` to the empty snapshot only for that class, so a writer that
fails mid-session made `/goal clear` return an error instead. In ACP an
error return throws out of `#processSlashCommandResult`, failing the
user's whole prompt request and continuing to do so for the rest of the
session — exactly the sticky failure that degradation exists to prevent.

Convert at the runtime boundary, preserving the message and chaining the
original as `cause`, so `set`/`edit`/`resume` still fail with the same
text they did before.

Addresses review comment 3745472951.

* fix(cli): deliver the recovered Goal card on the bulk load and resume paths

Both paths run `createAndStoreSession` with `replayHistory: false`, which
skips the `publishRecoveredGoalState` call added with the recovery fix — so
the web-shell's primary load path still showed the phantom running goal, and
a resumed session was never told the recovered state at all.

Streaming the card from the bulk path would not fix it. That path does not
stream its replay: `loadSession` collects the page into the `LOAD_REPLAY`
envelope and the bridge seeds those updates onto the session's event bus
only after `session/load` returns, so a card sent from inside the call sorts
*before* the replayed pre-migration `set` card instead of after it. Split a
render path out of `MessageEmitter` and append the card to the envelope,
after the page. Appending after a truncated page is correct too: paging
drops the oldest records, so the authoritative state belongs last regardless
of `hasMore`.

Resume replays nothing, so there is no envelope for the card to sort against
and it can be published normally.

The rendered card is marked delivered so the runtime subscription cannot
re-emit the same `(cause, snapshot)` once the session goes live.

* fix(cli): stop Goal permits leaking on turns that never reached the model

Two permit-lifecycle defects from review round 5, plus the regression test
the round-1 drain fix never got.

R5-16 — `modelStarted` was set at the top of the turn, before the abort
check and the whole prompt-assembly path. `#settleGoalTurn` reads it to
choose between handing the permit back and recording an iteration, so a
prompt cancelled anywhere in that window paused the Goal and charged it a
turn that never contacted the model. It is now set where the model request
is actually issued.

R5-2 — the cancelled-during-admission path released the reservation only
when the claim had not yet produced a `goalTurn`. `claimGoalTurn` refuses
an already-aborted signal, but an abort landing in the microtask gap after
it resolves left the permit held by a turn that returns `cancelled`
without running, so the runtime stayed `running` and every later Goal turn
blocked behind it. The release no longer looks at `goalTurn`; releasing an
unclaimed reservation is a no-op.

R1-1 — the settle in `#drainGoalQueue`'s catch was already in place but
nothing pinned it: removing it left the suite green. Covered now.

Each of the three tests was run against the mutation it exists for and
confirmed to fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(goals): surface failed clear persistence

* fix(goal): surface persistence recovery failures

* fix(goal): clean up failed permit claims

* test(cli): align degraded Goal CI setup

* fix(cli): stop Goal continuations after cancel

* test(webui): cover paused Goal status normalization

---------

Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-12 14:58:11 +00:00
ytahdn
f2de42dec4
feat(web-shell): improve compact tool activity (#8973)
* feat(web-shell): improve compact tool activity

* fix(web-shell): preserve tool timing metadata

* fix(web-shell): address compact activity review

* fix(web-shell): preserve customized tool metadata

* test(web-shell): cover completed agent tokens

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-12 12:48:08 +00:00
jinye
675dd45880
fix(web-shell): Harden prompt admission ownership (#8955)
Some checks are pending
E2E Tests / web-shell Browser Regression (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (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): Harden prompt admission ownership

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

* fix(web-shell): Address prompt retry review feedback (#8955)

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-12 09:33:21 +00:00
ytahdn
6195895d27
fix(web-shell): keep workspace picker suggestions closed (#8844)
* fix(web-shell): close workspace suggestions on blur

* fix(web-shell): read suggestion focus gate from the input root (#8844)

* fix(web-shell): reset suggestion suppress flag after a Browse pick (#8844)

* fix(web-shell): resolve picker blur-timer races in suggestion gating (#8844)

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

* test(web-shell): cover re-blur timer cancellation in AddWorkspaceDialog (#8844)

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

* fix(web-shell): clear blur timer on focus and unmount in AddWorkspaceDialog (#8844)

* fix(web-shell): invalidate blurred lookups via sequence counter in AddWorkspaceDialog (#8844)

* fix(web-shell): clear stale suggestions on blur dismiss in AddWorkspaceDialog (#8844)

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-12 06:52:58 +00:00
carffuca
2ca29c6aeb
feat(web-shell): improve subagent activity rows (#8780)
* feat(web-shell): improve subagent activity rows

* test(web-shell): cover collapsing inline agent details

* test(web-shell): harden subagent row coverage

* fix(web-shell): highlight interactive subagent rows

* test(web-shell): stabilize subagent duration assertion

* fix(web-shell): suppress untyped subagent type badge in activity rows (#8780)

getAgentType falls back to a raw 'task' sentinel for task agents that
carry no type argument, and the subagent row rendered it as an
unlocalized 'task:' prefix. Add isDefaultAgentType next to that
fallback so the row suppresses both untyped sentinels, and cap the
type label at 50 characters like its sibling row fields.

Also pin the live duration tick and the panel-mode chevron in the row
tests.

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-08-12 03:28:12 +00:00
carffuca
0e8a361b37
fix(web-shell): improve ask user question keyboard interactions (#8876)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
npm cache producer / Save npm cache (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (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 / 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
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
* test(web-shell): cover question keyboard workflow

* fix(web-shell): improve question keyboard flow

* test(web-shell): harden question keyboard coverage

* fix(web-shell): suppress inactive submit shortcut

* test(web-shell): cover direct Enter submission

* fix(web-shell): submit final question with Enter

* test(web-shell): cover compact shortcut hints

* fix(web-shell): compact question shortcut hints

* fix(web-shell): prevent narrow question footer overflow

* test(web-shell): cover custom-row Enter hint

* fix(web-shell): clarify custom-row Enter hint

* test(web-shell): cover shorter question replacement

* fix(web-shell): guard transient question replacement

* test(web-shell): reproduce rapid multi-select clicks

* fix(web-shell): preserve rapid multi-select updates

* fix(web-shell): avoid default multi-select answer

* fix(web-shell): refine ask question keyboard controls

* fix(web-shell): address ask question review findings
2026-08-11 17:50:15 +00:00
易良
28ab8bae56
fix(desktop): consolidate 0.1.1 regressions (#8896)
* fix(webui): retry session load while closing

* fix(desktop): support enterprise LAN addresses

* fix(desktop): reject unbounded LAN masks

* fix(webui): close desktop session and voice regressions

* fix(desktop): refresh signed runtime checksums

* fix(desktop): close 0.1.1 regression gaps

* fix(webui): make quick voice presses start recording

* fix(webui): make quick voice presses start recording

* fix(web-shell): keep voice clicks responsive

* fix(webui): settle timed-out session loads cleanly

* fix(web-shell): keep voice clicks responsive

* fix(desktop): finalize interaction regressions

* fix(web-shell): preserve hold click semantics

* fix(desktop): reject stale packaged runtimes

* fix(serve): avoid cancelling closed sessions

* fix(web-shell): preserve hold click suppression

* fix(web-shell): preserve hold click suppression

* fix(desktop): center and localize local control

* test(desktop): pin interaction regressions

* fix: close network and session race gaps

* fix(desktop): remove duplicate network.contains check in spawn_proxy

* fix(desktop): clear stale click suppression and exclude virtual interfaces

- Reset ignoreNextClickRef on pointerdown when no active hold to fix
  release-outside click suppression leak
- Add regression test for release-outside stop click
- Add abort assertion to quick-hold-as-tap test
- Exclude virtual interfaces (utun, docker, vEthernet, etc.) from
  Local Control LAN selection to prevent VPN adapters bypassing the
  physical-LAN boundary
- Add regression test for virtual interface exclusion

* test(desktop): cover cross-platform close fallbacks
2026-08-11 15:41:14 +00:00
jinye
74cfbccf49
fix(web-shell): Enforce prompt-safe session navigation (#8931)
* fix(web-shell): Enforce prompt-safe session navigation

Refs #8923

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

* test(webui): Harden session navigation cleanup

Refs #8923

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

* fix(web-shell): Preserve admission state across navigation

Refs #8923

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-11 14:33:35 +00:00
ytahdn
32812e9dd7
test(web-shell): prevent nested session render loop (#8934)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-11 12:42:40 +00:00
ytahdn
86a474ba62
feat(web-shell): preview uploaded images in the right panel (#8930)
Click an image in a user message or a pasted image in the composer to
open it in the right-hand artifact panel as an image tab. Each distinct
image gets its own tab (re-clicking focuses the existing one), the tab
shows a hover-revealed download button like workspace image artifacts,
and the composer remove button is now a small round icon that appears
on hover instead of an always-visible heavy cross.

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-11 11:17:23 +00:00
ytahdn
6c330c17bb
fix(web-shell): show line-change stats for large edited files (#8924)
The line-count computation used an exact LCS with a 1M-comparison
cap, so any full-content diff over ~1000 lines silently dropped the
+N/-M stats and large edited files showed no change counts. Replaced
the exact LCS with a linear-time multiset comparison — stats are now
always computed; only identical lines moved between positions
miscount, which is acceptable for display stats.

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-11 09:57:47 +00:00
jinye
00248b1a53
fix(webui): Make cross-session switching transactional (#8882)
* fix(webui): make cross-session restores transactional

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

* fix(web-shell): preserve sessions during navigation

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

* codex: address PR review feedback (#8882)

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

* fix(webui): address transactional switch review feedback

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

* fix(web-shell): preserve catalog updates across session switches

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-11 09:38:36 +00:00
jinye
096bb0e3b9
feat(web-shell): Share session catalog scheduling (#8891)
* feat(web-shell): Share session catalog scheduling

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

* fix(web-shell): Harden session catalog reconciliation

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

* fix(web-shell): Restore session catalog CI coverage

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-11 09:13:14 +00:00
ytahdn
7ebd137edb
fix(web-shell): stabilize transcript history pagination (#8914)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-11 08:30:13 +00:00
ytahdn
1a2c5026b2
fix(web-shell): reconcile mid-turn messages with daemon state (#8798)
* fix(web-shell): reconcile mid-turn messages with daemon state

* test(serve): update mid-turn capability expectation

* test(mid-turn): cover reconciliation mutants and restore serve protocol docs (#8798)

* fix(serve): close mid-turn promotion admission and delivery gaps (#8798)

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

* fix(serve): keep anonymous mid-turn enqueues off the shared queue surface (#8798)

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

* fix(sdk): account for mid-turn APIs in bundle budget

* test(acp-bridge): use vi.waitFor for async prompt-drain assertions (#8798)

* fix(serve): reconcile mid-turn steering safely

* fix: reconcile mid-turn messages safely

---------

Co-authored-by: ytahdn <ytahdn@users.noreply.github.com>
Co-authored-by: 钉萁 <dingqi.jww@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>
2026-08-11 07:24:56 +00:00
ytahdn
ca31bf2a75
fix(web-shell): improve subagent panel updates (#8915)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-08-11 07:02:53 +00:00
Heyang Wang
e46586782c
feat: support drag and drop img in web-shell (#8696)
* feat(web-shell): support image drag and drop

Allow Web Shell composers to ingest image files reliably while
preserving the existing multimodal prompt protocol.

- Share ordered image ingestion across desktop and mobile editors
- Support image-only prompts and BMP preview and provider-safe handling
- Preserve queued payloads across retries and uncertain outcomes
- Add lifecycle guards, user feedback, unit coverage, and browser tests

* fix(web-shell): harden image prompt admission recovery

Preserve complete prompt payloads and prevent duplicate or uncertain
delivery states when admission responses race with queue lifecycle
events.

- Correlate admission, queue, and terminal events by prompt ID
- Restore images and input annotations across retry and edit flows
- Bound image reader concurrency and encoded attachment memory
- Reconcile confirmed removals and explain ambiguous queue entries

* docs(web-shell): align image drag design with review fixes

Document the reviewed admission, recovery, and resource invariants.
Keep the design aligned with the hardened Web Shell implementation.

- Record bounded image ingestion and encoded-data budgeting
- Clarify prompt lifecycle correlation and confirmed removal behavior
- Describe annotation restoration and internal action boundaries
- Update focused validation evidence and acceptance criteria

* fix(web-shell): avoid duplicate restored attachments

Skip payload attachments when restoring text is a no-op because the
same prompt text already exists in the composer.

- Restore images and annotations only when their text is inserted
- Preserve image-only restoration regardless of the current draft
- Add regression coverage for duplicate text with attachments

---------

Co-authored-by: heyang.why <heyang.why@alibaba-inc.com>
2026-08-10 05:48:17 +00:00
易良
57e6c31030
fix(web-shell): gate the floating todo entry behind the session workflow setting (#8828) 2026-08-10 05:39:07 +00:00
Shaojin Wen
27216eb4ca
feat(web-shell): show context usage as a mini progress pill in the status bar (#8794)
* feat(web-shell): show context usage as a mini progress pill in the status bar

Replace the plain "X% context used" text in the status bar with a compact
pill: a 52px progress bar plus the bare percentage. The fill follows the
same thresholds as the /context panel (>60% warning, >80% error), the fill
width caps at 100% while the number keeps reporting overflow, and the full
wording moves to aria-label so the accessible name is unchanged. Clicking
still opens the /context breakdown.

* fix(sdk): stop rendering usage_update frames as debug transcript text

The ui normalizer had no case for the usage_update session update, so the
frame fell through to the debug default and every model round appended a
raw-JSON bullet to the assistant turn in the web UI. Context occupancy is
surfaced by the status bar pill; the transcript drops the frame like
current_mode_update.

* feat(web-shell): move the context indicator into the composer toolbar as a ring

Review rework: replace the status-bar pill with a compact circular
progress ring in the composer toolbar's right cluster, immediately left
of the voice actions. The ring keeps the /context thresholds (>60%
warning, >80% error) and the visual 100% cap, hovers a Tooltip with the
full used/total detail (e.g. 53.6k / 1.0M tokens (5.4%)), keeps the full
wording on aria-label, and still opens /context on click. It ships as a
new contextUsage entry in composerToolbarActions so embedders can hide
it, hides while usage or the window is unknown, and follows the
toolbar's mobile-voice hiding. The StatusBar changes are reverted so the
indicator lives in exactly one place.

* fix(web-shell): let Radix position the shared tooltip arrow

The shared TooltipContent drew its arrow with a ::before pinned at the
content's horizontal center. Near a viewport edge Radix collision
avoidance shifts the content, so the arrow stopped pointing at the
trigger (about 35-40px off for the composer's context ring, which sits
at the far right). Replace the pseudo-element with TooltipPrimitive.Arrow,
which computes the offset from the trigger and the collision-shifted
content, keeping the tip on target for every tooltip and side.

* refactor(web-shell): share context-usage thresholds and token formatting (review)

Review round 3 suggestions:
- The 60/80 severity thresholds now live in one shared helper used by
  both the composer ring and the /context panel, so the two surfaces
  cannot drift.
- The ring tooltip's token formatter moves into the shared token-count
  utils and the /context panel uses it too, giving both surfaces the
  same k/M rendering (the panel previously showed a 1M window as
  1000.0k).
- The ring arc's transition is disabled under prefers-reduced-motion,
  matching the file's other decorative motion.
- New tests: exactly-80% stays warning (pins the strict threshold), the
  App wiring from connection usage to the ring props, click-through
  reaching the context-usage request, and the 0 fallbacks before any
  usage arrives.

* fix(sdk): resolve usage_update overlap with main

The same normalizer fix landed on main via #8790 while this PR was in
review; the merge auto-combined both edits into a duplicate case and a
duplicate test. Keep main's version — this branch now carries no
sdk-typescript delta.

* refactor(web-shell): consolidate the remaining token-count formatter copies (review)

Review round 4: the task-status panel's local formatter was
byte-identical to the shared one, and the collapsed-turn footer's copy
lacked the M branch — a collapsed turn with a >=1M-token input rendered
1048.6k while the ring tooltip and /context panel said 1.0M for the same
session. Both now import the shared formatter. Also pin the tooltip
arrow's positioning classes in the test, so a shadcn regeneration that
drops them fails instead of passing on a bare existence check.

* fix(web-shell): restore tooltip spacing and finish formatter consolidation (review)

Review round 5:
- With a Radix Arrow child, the offset middleware computes
  sideOffset + arrowHeight, so keeping the pseudo-element-era default of
  8 pushed every tooltip ~10px farther from its trigger. Default now 0;
  measured in a real browser the content edge sits 10px from the trigger
  (8px before the arrow change) with the tip 6px away.
- Drop the formatContextTokens-as-formatTokenCount aliases: the alias
  reused the exact name of the module's other, differently-behaving
  export, inviting wrong-import drift. Call sites use the real name.
- Colocate the pure-logic tests: utils/contextUsage.test.ts pins the
  strict-> boundaries, utils/formatTokenCount.test.ts owns the formatter
  cases (moved from ChatEditor.test.tsx), and ContextUsageMessage gains
  progress-bar color cases at 60/61/80/81 so the panel half of the
  shared-threshold contract is pinned too.
2026-08-10 03:48:06 +00:00
Shaojin Wen
b314d01f2d
fix(web-shell): stop rendering unrecognized daemon events in transcripts (#8812)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (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(web-shell): stop rendering unrecognized daemon events in transcripts

The daemon UI normalizer projects any frame it has no case for into a
`debug` event carrying a raw JSON dump. webui's ChatViewer drops those
blocks, but Web Shell renders `status` and `debug` together as system
info, so every event kind the daemon ships ahead of the UI surfaces as
unreadable JSON in the middle of the conversation. This has been patched
per-symptom three times now: two string-prefix suppressions inside
`isIgnoredWebShellStatus`, plus #8790 for `usage_update`.

Give the normalizer's debug events a structured `debugReason` and let
Web Shell branch on it instead of pattern-matching text:

- `unrecognized_event` / `unrecognized_session_update` — the daemon runs
  ahead of this client; developer diagnostics, not conversation content.
  Web Shell no longer renders them.
- `malformed_payload` — a frame the client does know arrived unusable.
  That is a real defect signal, so it stays visible.

Debug events dispatched by clients themselves, such as Web Shell's own
model-switch summary, carry no `debugReason` and keep rendering.

The two `(unrecognized daemon event)` prefix checks are now covered by
`debugReason` and are removed; the `Model switched: ` check stays, since
`model.changed` projects to a `status` block rather than a debug one.

* fix(sdk): classify a discriminator-less session_update as malformed

Review of #8812 caught a hole in the new classification: `session_update`
payloads such as `{}` or `{ sessionUpdate: 42 }` reach the default branch
with `kind === undefined`, and stamping them `unrecognized_session_update`
made Web Shell hide the only diagnostic a malformed frame produces.
Reserve the unrecognized reason for a real unknown string kind.

Also update the top-level default-case comment, which still pointed
adapters at the debug text prefix, and add a reducer-level test proving
`debugReason` survives the UI-event → transcript-block boundary: the
normalizer tests inspect events and the Web Shell tests build blocks by
hand, so dropping the spread in transcript.ts would leave both green.

* fix(web-shell): keep filtering legacy debug blocks, tighten the reason split

Four review findings from #8812:

- `WebShellTranscript` is a public entry point taking already-projected
  blocks, so blocks from an SDK predating `debugReason` still arrive with
  no reason and started rendering again when the prefix checks were
  removed. Fall back to the stable ` (unrecognized daemon event): ` marker
  when no reason is present — which covers every unrecognized event type,
  not just the two previously suppressed by name. The old-shape fixture is
  restored (adding `debugReason` to it had hidden this path) and a
  dedicated legacy test now pins it.
- A whitespace-only discriminator is truthy, so `sessionUpdate: ' '` was
  classified unrecognized and hidden. Gate on `trim()`, matching the
  convention `getFirstString` already uses.
- Add the mirror invariant for the reducer: a client-dispatched debug
  event must produce a block with no `debugReason`. Defaulting the field
  in `appendStatusBlock` otherwise passes every other test while tagging
  the model-switch summary unrecognized.
- Guard the outermost public re-export. A type-only guard would not hold —
  vitest erases `export type` through esbuild and this package's tsconfig
  excludes `test/` — so ship the union as `DAEMON_UI_DEBUG_REASONS`,
  matching `DAEMON_ERROR_KINDS`, and assert it at runtime.

* fix(web-shell): suppress legacy usage_update/a2ui blocks with no debugReason

Follow-up verification on #8812 pointed out the marker fallback does not
close the original report. #8790 stopped the SDK inserting new
`usage_update` blocks, but `WebShellTranscript` renders whatever blocks its
caller passes, so a transcript persisted or projected before that still
holds them and the spam returns after upgrade.

The legacy `session_update` projection is `<kind>: <json>` with no marker to
key on, so match those by kind name instead. The list is closed on purpose —
`usage_update` and `a2ui`, the two known to have leaked — and requires the
`: {` shape, because a generic `<word>: {` rule would swallow legitimate
diagnostics. Blocks the normalizer classified still win on `debugReason`,
so `malformed_payload` and client-dispatched debug blocks stay visible.

Mutation-checked in both directions: dropping the fallback fails the legacy
test, and loosening the prefix to bare `usage_update:` fails the test that
pins prose and classified blocks staying visible.

* fix(web-shell): match the legacy projection shape, not a quoted marker

The legacy fallback was too broad in two ways, both reachable. It ran for
`status` blocks as well as `debug` ones, because this helper is called from
the shared `case 'status': case 'debug':` arm, and it matched the marker as
a substring anywhere in the text.

Probed at df0b757c3c: all four of these were dropped — a status line
quoting the marker, a legacy malformed payload relaying an upstream peer's
message that contains it, a client-dispatched summary quoting it, and a
status block whose text starts with `usage_update: {`. Exactly the
diagnostics this PR promises to keep.

Scope the text match to `debug` blocks, and anchor it to the whole legacy
projection (`<event-type> (unrecognized daemon event): <json>`) instead of
the bare marker. Classified blocks still win on `debugReason` before any of
this runs.

Mutation-checked: dropping the `kind === 'debug'` guard and restoring the
substring match each fail the new negative test.

* fix(web-shell): match legacy projections with non-object payloads

The anchored legacy pattern required the payload to start with `[`, `{` or
`"`, which only holds for objects and arrays. `DaemonEvent.data` is
`unknown`, and `stringifyJson` returns strings verbatim, serializes
primitives as `42` / `true` / `null`, and yields `''` for `undefined` — so
every non-object payload bypassed the compatibility fallback and rendered.

Drop the leading-character constraint. The event-type prefix plus the fixed
phrase, anchored at the start, is specific enough on its own, and the
negative cases for quoted markers and status blocks still pass.

Regression test covers object, array, string, number, boolean, null and
empty payloads. Mutation-checked: restoring the character class fails it.

* fix(web-shell): hide debug blocks by the unrecognized_ reason category

The debugReason filter enumerated the two current `unrecognized_*` values,
but the SDK contract this PR adds names reasons by category: `unrecognized_*`
is forward-compat noise to hide, `malformed_*` a defect signal to keep
visible. A reason a newer SDK adds would compile silently against the
two-literal comparison and render raw JSON again with both suites green.

Match the category prefix instead. Also drop the now-dead marker branch in
MessageList's mid-turn hide check: every block carrying that prefix is
filtered upstream in the adapter (reason-stamped via `debugReason`, legacy
via the anchored pattern), and the dedicated normalizer case emits a status
event keyed by `source`. Document `DaemonUiDebugReason` beside the sibling
closed enums in the daemon-ui docs, whose forward-compat bullet still
described the unstamped projection.

Regression test pins both directions of the category contract with reasons
outside the current enum.

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-10 00:51:57 +00:00
Shaojin Wen
e39781d858
feat(web-shell): add fullscreen view for the right artifact panel (#8614)
* feat(web-shell): add fullscreen view for the right artifact panel

The right panel (artifacts / subagents / review) is narrow, so long
previews and transcripts are hard to read. Add a fullscreen toggle to
the panel header that expands the panel to cover the viewport; pressing
Escape or the toggle again shrinks it back to its dock or drawer.

* test(web-shell): capture fullscreen artifact panel in visual previews

The fullscreen toggle and surface are only reachable with the artifact
panel open, so no visual scenario rendered them and the before/after
preview could not see this feature. Extend the code review artifact
scenario to expand the panel fullscreen, capture it, and assert the
Escape restore path.

* fix(web-shell): keep artifact panel mounted across fullscreen toggle (#8614)

* fix(web-shell): harden artifact panel fullscreen per review feedback (#8614)

* fix(web-shell): guard artifact drawer Escape for IME composition (#8614)

* fix(web-shell): scope toast z-index, reset dock animation flag, guard IME keyCode (#8614)

Round-4 review fixes for the artifact panel fullscreen:

- Elevate ToastHost above dialog-backdrop-tier surfaces only while the
  fullscreen surface is up (new `elevated` prop); otherwise it stays at its
  original z-index 30 so DialogShell modals keep painting above toasts. The
  old comment rested on DialogShell.module.css's dead `.backdrop` class —
  the live modal path resolves the same host variable with fallback 50.
- Reset suppressArtifactDockOpenAnimation when the dock unmounts (panel
  close or floating drawer taking over) and only set it while docked, so a
  floating<->docked flip after a fullscreen round-trip no longer mounts the
  dock without its slide-in animation.
- Extend the window Escape handler's IME guard to keyCode 229, matching the
  paired guard used everywhere else in the package: a WebKit-shaped IME
  Escape (isComposing false, keyCode 229) previously shrank a fullscreen
  panel and swallowed the native IME cancel.

Adds the suggested coverage: keyCode-229 drawer variant, docked-fullscreen
IME Escape, ask-user shrink keyboardActive history, streaming+fullscreen
Escape ordering, and the floating-interlude dock animation regression.

* fix(web-shell): portal docked fullscreen surface, gate chat shortcuts, clamp z-index (#8614)

Round-5 review fixes for the artifact panel fullscreen:

- Clamp the fullscreen surface z-index floor to max(1, backdrop - 10): a
  host setting --web-shell-dialog-backdrop-z-index below 10 gave the
  surface a negative z-index, painting the opaque panel behind the app
  background and blanking the shell.
- Add artifactPanelFullscreen to interactionBlocked: chat-only global
  shortcuts (Ctrl+L/O/Y, Shift+Tab, the btw hotkey) kept mutating the
  hidden chat behind the surface, and the btw capture-phase Escape handler
  dismissed hidden content and swallowed the Escape that shrinks the panel.
- Pad the floating drawer fullscreen content with env(safe-area-inset-*):
  the portaled drawer sits outside the padded app root, so on
  viewport-fit=cover devices the toolbar and Exit control could sit under
  the notch/status bar and bottom content behind the home indicator.
- Move the docked fullscreen surface into the top-level portal root and
  give it document-level modal semantics: a transformed, paint-contained,
  or lower-stacking host ancestor could bound the fixed panel or paint
  over it, and Tab could escape into covered host controls. The panel
  wrapper portals into a display:contents slot that the fullscreen effect
  parks in the portal root, so the SAME node survives the move (panel
  state preserved, React event delegation intact); FocusScope provides the
  Tab containment and the effect hides every outside tree from AT and
  captures stray focus — matching what the floating variant gets from
  vaul's Radix dialog. Declares @radix-ui/react-focus-scope (already in
  the tree via radix-ui) as a direct dependency.
- Portal the elevated ToastHost into the portal root: in shadow-DOM portal
  mode the fullscreen drawer surface is sealed inside the portal host's
  stacking context, so an in-tree toast painted beneath it for its whole
  auto-dismiss lifetime.
- Keep the dock animation suppression flag across dock<->floating
  hand-overs performed mid-fullscreen in both directions, so shrinking
  back to the dock never replays the slide-in on the already-open panel.

Tests: pin both hand-over suppression directions (mutation-verified), the
portal placement, the interaction gate, and toast elevation in the main
fullscreen test; add a colocated ToastHost.test.tsx for the elevated
class; fix the dead 0-measurement step in the docked-width round-trip
test (the 0 is now seeded before entering fullscreen, where the clamp
effect can actually observe it). Adds a drawer-fullscreen visual scenario
at a narrow viewport in both themes, with Escape restoring the drawer.

* fix(web-shell): repair docked fullscreen panel modal semantics (#8614)

* fix(web-shell): reset fullscreen state in the panel close commit (#8614)

Closing the artifact panel while fullscreen reset the fullscreen flag
only in the passive management effect, so one render committed with the
panel unmounted while the covered shells stayed display:none — one
painted frame of an empty shell before the chat reappeared. Batch the
fullscreen and dock-animation-flag resets into closeArtifactPanel and
the last-tab close so the recovery happens in the same commit.

Adds a regression test asserting the shells are revealed in the close's
committed frame (fails without the batched reset), and pairing coverage
for the drawer Escape pass-through: a plain Escape still closes the
floating drawer when the panel was never fullscreen.

* fix(web-shell): pull escaped focus back into the docked fullscreen surface (#8614)

* build(external-context): restore the node-only types override from main

Cherry-picks the tsconfig guard from 3037744602 (#8693), which postdates
this branch's merge base. With @types/jsdom installed, the inherited
vitest/globals types drag the DOM lib into this program and break the
for-await over response.body in http-client.ts, failing npm run build
and npm run typecheck.

* fix(web-shell): keep docked fullscreen usable in shadow DOM (#8614)

Resolve two Critical review findings on the docked fullscreen surface:

- focusin is composed, so in shadow-DOM portal mode the document-level
  pull handler and the Tab-wrap handler saw the shadow host retargeted
  as the target and snapped every focus change back onto the surface.
  Resolve the real node via composedPath() and read the active element
  from the surface's own root.
- The aria-hidden sweep recorded values still owned by a live
  hideOthers lock when the floating drawer unmounted in the same commit
  the docked surface mounted; the deferred restore then re-applied the
  lock's value and permanently hid the shell from assistive tech.
  Record null for lock-owned siblings and let the lock's unlock restore
  the original value.

Adds regression tests for both paths; both fail without their fix.

---------

Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-09 12:41:48 +00:00
qqqys
88a325bce9
feat(workflows): add cooperative pause and resume (#8320)
* feat(workflows): add cooperative pause and resume

* fix(workflows): restrict pause to background runs

* fix(cli): clarify foreground workflow pause errors

* fix(core): preserve dispatch errors across cancellation

* test(core): cover late workflow state callbacks

* fix(workflows): address review suggestions (#8320)

- Rename misleading `terminal` local to `presentation` in BackgroundTasksDialog
- Fix vacuous `toContain('p')` assertion to `toContain('Background tasks + p')`
- Fix vacuous gate assertion with macrotask yield in scheduler test
- Add over-count cap test for `onAgentCompleted` past dispatched count
- Add pausing-state approval parking test
- Remove dead `concurrencyLimiter` module (no production consumers)

* test(workflows): pin review-flagged mutation-surviving branches (#8320)

* test(cli): use valid agent status in detail-view reset test (#8320)

* test(workflows): harden pause-gate settle probes with a full flush (#8320)

* fix(workflows): address round-5 review findings (#8320)

* test(ci): sync review timeout assertions with repository variables (#8320)

* fix(workflows): address round-6 review findings (#8320)

* fix(workflows): address round-7 review findings (#8320)

* fix(workflows): address round-8 review findings (#8320)

* fix(workflows): address round-9 review findings (#8320)

* fix(workflows): address round-10 review findings (#8320)

* fix(workflows): address round-11 review findings (#8320)

* fix(workflows): address round-12 review findings (#8320)

* fix(workflows): address round-13 review findings (#8320)

* fix(workflows): address round-14 review findings (#8320)

* fix(workflows): address round-15 review findings (#8320)

---------

Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com>
Co-authored-by: qwen-code-bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-08 04:21:21 +00:00
BaboBen
d3164572f3
feat(channels): add Feishu ask-user question cards (#8578)
* feat(channels): add Feishu ask-user question cards

* fix(channels): harden Feishu question-card handoff and feedback paths

* fix(channels): anchor Feishu card-creation timeout at creation start (#8578)

* fix(channels): skip settled question-card delivery, retry input-request finalization

- present() returns early when the request settled before listener
  registration (stop/cancel landing in the pre-presentation await):
  the card is no longer delivered just to be patched terminal, which
  left a spurious actionable-looking card when the patch failed.
- endOutputCardBeforeInputRequest now retries the final patch with
  stripTables before deleting the card and re-sending plain text,
  mirroring onResponseComplete and the throttled update path.
- truncateCardText budgets the 4-char fence prepend so rebalanced
  content stays within MAX_CARD_CHARS, matching onResponseComplete.

* test(channels): cover Feishu question-card review findings

- stop real network leaks: mock addReaction/removeReaction in the two
  handoff tests that drove onPromptStart with the real implementation
  (each run hit Feishu's tenant-token endpoint).
- assert the OnIt reaction add/remove lifecycle positively.
- pin settled-before-registration presentation to zero card delivery.
- regression tests: input-request table-stripped retry, finalizing
  race (throttled timer cleared before the final patch), late card
  deletion when the input request lands mid-creation, abandoned
  creation-timer guard.
- routing coverage for toast-only handled callbacks (no execute).
- parse rejections: empty/malformed multi-select values; cancel-side
  name<->operation_id mismatch; visible submit/cancel button labels;
  cancelRun terminal label; submitted answers in patch-failure
  fallback; truncation tail-keeping and fence-rebalance cap.
- harden subset toMatchObject assertions to strict toEqual.

* fix(channels): type Feishu card-delivery errors; cover controller wiring seam

sendInteractiveCard now throws FeishuCardDeliveryError (with the HTTP
status when available) so createStreamingCard classifies delivery
failures by error type instead of string-matching three message
literals that could drift under rewording.

Add an adapter test that keeps the real FeishuQuestionCardController
with fetch mocked, asserting the POSTed body carries the question-card
JSON (form name, question text, request id) — the constructor wiring
seam every routing test previously mocked away.

* fix(channels): cap Feishu input-request card retry; harden question-card tests

* fix(channels): drain in-flight Feishu card PATCHes before final patch (#8578)

Also carry a concurrently-written terminal status into the released
card entry, report card-delivery failures from a typed error detail
instead of slicing the message, and document the silent
empty-completed-turn tradeoff. Adds round-5 review test pins: wiring
seams (sendFallback, patchCard, timeoutMs), spy hygiene, claim-time
card content, fallback suppression, expiry-timer survival, and
non-vacuous release-time timestamp anchoring.

* fix(channels): coordinate Feishu card stop races and throttle bursts (#8578)

- endOutputCardBeforeInputRequest now defers to Stop (entry guard plus
  post-await re-checks mirroring onResponseComplete) and releaseOutputCard
  carries settled stop state, so a stopped run is never labelled 已完成 nor
  followed by a contradictory terminal message
- coalesce throttled card updates queued behind a stalled PATCH into one
  trailing run instead of a burst
- log every FeishuCardDeliveryError from createStreamingCard
- consolidate onResponseComplete truncation through truncateCardText
- question controller: a not-accepted in-flight response no longer flips a
  projected 已取消 card to 已过期, and a cancel claim no longer re-patches
  the terminal card already delivered in the callback response
- test hygiene: hermetic fetch mocks for token-failure tests, restored
  fetch spies, required lifecycle fixture fields, bracket index access

* test(web-shell): wait for history search focus before Escape in smoke (#8578)

* fix(channels): resolve Feishu card finalization races from review (#8578)

* fix(channels): recover Feishu cancel callbacks missing button value (#8578)

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@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@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-08-08 04:20:17 +00:00
callmeYe
52f4fbe0b3
feat(web-shell): install Extensions from archives (#8621)
* feat(web-shell): install extensions from archives

* fix(web-shell): harden extension archive uploads

* test(cli): align archive failure bridge assertion

* fix(extensions): address archive upload review feedback

* fix(webui): stagger extension archive upload timeout

* fix(extensions): address archive upload round-4 review feedback

* fix(extensions): address archive upload round-5 review feedback

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-08 02:08:52 +00:00
dreamWB
cb401036e3
fix(web-shell): keep mobile composer at chat pane bottom (#8601)
* fix(web-shell): keep mobile composer at chat pane bottom

* test(web-shell): strengthen mobile composer layout coverage

* fix(web-shell): harden mobile composer layout

* fix(web-shell): center footerless mobile welcome

* test(web-shell): type mobile dot field element

* fix(web-shell): harden empty mobile footer layout

* test(web-shell): strengthen mobile welcome overflow coverage

* refactor(web-shell): narrow mobile composer fix scope

* fix(web-shell): keep bottom panels anchored in custom-footer mobile welcome

* test(web-shell): reject custom footer variant in composer layout helper

* test(web-shell): share mobile welcome chrome checks and pin custom footer branch

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

* docs(web-shell): mark custom footer class as load-bearing for CSS exclusion

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-07 16:57:00 +00:00
carffuca
4b45f96a08
feat(web-shell): improve parallel agent activity feedback (#8559)
* feat(web-shell): improve parallel agent activity feedback

* test(web-shell): cover parallel agents group in visual previews

* fix(web-shell): Harden parallel agents group per review feedback (#8559)

* fix(web-shell): repair parallel agents deferral and ownership per review (#8559)

* fix(web-shell): skip parallel agents exit sequence on collapsed group (#8559)

* fix(web-shell): do not await rejected background agent launches (#8559)

* fix(web-shell): harden parallel agents collapse and turn pinning per review (#8559)

* fix(web-shell): guard parallel agents collapse finalization against stale deferral (#8559)

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-07 16:47:48 +00:00
BaboBen
edb420393e
fix(channels): manage DingTalk interactive card config (#8517)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (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(channels): manage DingTalk interactive card config

* test(cli): cover nested channel object validation

* fix(channels): harden nested management metadata

* fix(channels): isolate invalid management descriptors

* fix(channels): isolate invalid management metadata from channel runtime

* fix(channels): reject reserved unknown keys in management config upserts

* fix(channels): harden channel management validation and editor checks

Reject management descriptors that lack a fields array at registration so
broken plugins are stripped to unmanageable instead of being advertised as
manageable and failing every upsert with an unmapped TypeError. Reserve the
top-level "type" field key and require enum fields to declare at least one
option, both of which the settings store could never accept. Treat
whitespace-only number drafts as empty in the channel editor, consistent
with the module's other emptiness checks.

Also give the SDK descriptor mirror test a runtime wire-shape walk over the
built-in catalog, add the parser's timeout rejection boundary, and restore
the exact built-in catalog membership assertion.

* fix(channels): validate management field shapes and editor bounds (#8517)

* fix(channels): align management validation layers and pin gate behavior (#8517)

Read envResolvable by truthiness in the settings store so it matches the
registration gate and the editor, instead of rejecting the advertised
environment references of untyped plugins. Fail closed at registration on
non-finite exclusiveMinimum values, empty object property lists, and async
validateConfig functions, all of which would otherwise advertise a field
or save path that can never succeed. Strip invalid management metadata
over a prototype-preserving copy so class-instance plugins keep their
createChannel implementation.

Move the unchanged-value preservation exemption ahead of the object shape
rejection so a stored non-record value (for example a hand-written null)
no longer locks every unrelated management edit of that channel. Clamp
DingTalk question-card timeouts at the maximum setTimeout delay, since
Node treats larger delays as one millisecond and would expire cards
instantly.

Pin the previously untested load-bearing behaviors: per-key previous
threading in the recursive validation, the preservation exemption's
precedence over nested required enforcement, nested "type" properties,
depth-2 nesting rules, and the nested-only constraints of the daemon
descriptor wire contract.

* fix(channels): close reserved-key preservation gaps and pin gate behavior (#8517)

* test(cli): tolerate IPv6-less hosts in serve ::1 bind tests (#8517)

The self-hosted CI containers can have no IPv6 loopback, where the two
runQwenServe tests that bind ::1 fail with EADDRNOTAVAIL. Probe the
interfaces once and skip only the IPv6-dependent binds there; every
assertion still runs on IPv6-capable hosts.

* fix(channels): align descriptor type contracts with runtime validation (#8517)

The registry already rejects object fields without a non-empty
properties array and enums without unique options, but the descriptor
types still admitted both, so TS-authored plugins only learned about
it when registration stripped their management surface. Make
`properties` required, give enums a dedicated descriptor member with
required `options`, and drop the never-honored `envResolvable` flag
from number descriptors, in both channel-base and the SDK mirror, and
export the descriptor sub-types through the webui barrels. Also map a
throwing `validateConfig` to the usual invalid-config error and pin
the store contracts that had no distinguishing tests: omitting a
parent object drops the stored object without checking its nested
required, writes replace nested values wholesale, unchanged stored
scalars are still re-validated, and valid plugins register by
original reference.

* fix(channels): defuse validateConfig rejection leak and close descriptor gate gaps (#8517)

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

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.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-Coder <qwen-coder@alibabacloud.com>
2026-08-07 15:47:20 +00:00
qqqys
3edecac116
feat(channels): support group pairing (#8440)
* feat(channels): support group pairing

* fix(channels): address group pairing review

* fix(web-shell): show group pairing management

* fix(channels): recheck group pairing before history backfill

* test(channels): verify group approval isolation

* fix(channels): address group pairing review findings and pin behaviors (#8440)

- Grandfather the group allowlist file in PairingStore legacy migration
- Offer the pairing groupPolicy option in github/gitlab descriptors
- Re-export DaemonChannelPairingSubject from the webui barrels
- Refresh the GroupGate doc comment and channel docs rows
- Pin the unpinned group pairing behaviors called out in review:
  subject dedup, trigger matrix, notification content/cap/failure/
  thread routing, DM negative space under groupPolicy pairing,
  stored DM loop authz, pairing-enabled guard negative space,
  approval/revocation HTTP bodies, descriptor-driven gate branch,
  and the web-shell group approval mirrors
- Add a compile-time assertion for the revocation request union

* fix(channels): address group pairing review findings (#8440)

- Accept 'pairing' in the GitLab connect warning, descriptor help text,
  and gitlab.md: todos dispatch after one-time group approval.
- Model group approvals in the web-shell e2e mock daemon (approve by
  subject type, GET returns senderIds+groupIds, DELETE accepts groupId)
  and exercise the group pairing flow in the channels spec.
- Add 'pairing' to the groupPolicy enumerations in the plugins and
  per-channel docs (telegram, feishu, dingtalk, qqbot, wecom).
- Update the channel pairing CLI help to cover group requests.
- Cap pending pairing requests at one per sender so a single member
  cannot occupy every shared pending slot.

* fix(channels): address group pairing review findings round 7 (#8440)

* fix(channels): address group pairing review findings round 8 (#8440)

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

* fix(channels): address group pairing review findings round 9 (#8440)

---------

Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.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: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-08-07 09:20:18 +00:00
Dragon
adec1ea50f
feat(core): share compression cache with Gemini and Vertex AI (#8425)
* feat(core): share compression cache with Google GenAI

* fix(core): preserve restored compression accounting

* fix(core): preserve estimated compression accounting

* fix(core): preserve estimated token provenance on resume

* fix(core): harden compression provenance flow

* fix(core): keep compression counts conservative

* fix: preserve compression token provenance

* fix(web-shell): preserve estimated context usage

* fix(core): require provider-reported anchor for compression cache sharing

An estimate-derived token count misses the ~15-20K system/tools overhead
the shared compression request carries, so a magnitude-only anchor gate
could approve a shared request that overflows the context window. Gate
cache sharing on a provider-reported count, keeping estimate-only
sessions on the cold path until provider usage arrives.

Pin the zero-baseline end-to-end composition (derived baseline reaches
the service, missing anchor routes to the cold side query), repair the
garbled R3.4 test rationale comment, and log estimate-clamp padding.
2026-08-07 08:54:49 +00:00