* feat(skills): add overridable default-disabled state
* fix(skills): address review feedback on default-disabled PR (#7357)
- Fix disabledChanged comparison in SkillsManagerDialog to use
previousDisabled (locked names filtered) instead of workspaceDisabled,
preventing spurious settings writes when a skill is disabled at both
workspace and higher scope
- Import SettingScope as a value instead of string-casting literals in
skill-settings.ts for compile-time safety
- Add dual-key change test: enabling a workspace-hard-disabled
default-disabled skill produces both skills.disabled and
skills.enabled changes in one operation
- Add legacy inactive-extension branch tests: reject when
disabledReason is undefined and skill is not in settings
disablements; allow when it is disabled by settings
* fix(cli): address skills picker review feedback (#7357)
Extract the skills picker's workspace persistence computation into a tested pure function so orphaned workspace disables (skills not currently loaded) are explicitly preserved and pinned by a regression test. Also add an integration test asserting a workspace-scope hard disable surfaces disabledReason 'hard' through the full loadSettings -> resolveSkillSettings -> mapSkillConfigToStatus pipeline.
* fix(cli): resolve skill disablements in safe mode for status API (#7357)
* fix(cli): dynamically import skill-settings in serve to keep fast-path closure clean (#7357)
---------
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix[bot]@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
The live journal (DAEMON-009) caps were too conservative for real-world
agent turns: 2000 events / 2 MiB caused 79% event loss on a typical
long turn (9647 events). Raise defaults to 10 000 events / 8 MiB and
expose them as --max-journal-events / --max-journal-bytes CLI flags,
following the same config path as --compacted-replay-max-bytes.
Also fix stale docs that described the liveJournal as uncapped.
* feat(serve): hot-reload workspace trust changes
Rebuild workspace runtime generations when trust policy changes, fail closed across daemon routes, and expose reconciliation status to SDK and Web Shell clients.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* codex: address PR review feedback (#7268)
Document the trust hot-reload capability and reuse the daemon environment fallback so the serve process environment guard remains satisfied.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): cache workspace trust status snapshots
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix: address trust reload race regressions
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): avoid repeated runtime containment
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): harden workspace generation boundaries
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): restore stale session owner fallback
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): preserve workspace metadata across trust reloads
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): align hot-reload trust semantics
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): stop git-state watcher on dispose only, fix git chip test (#7268)
beginDrain stopped the git-state watcher but cancelDrain had no way to
restart it, leaving the watcher disposed until the next lazy poll.
disposeRuntime already stops git-state when the drain is committed, so
the beginDrain stop was redundant — remove it.
Also fix the WorkspaceSection git chip test that broke when the trigger
changed from <button> to <span role="button"> inside DropdownMenuTrigger:
use closest('[role="button"]') and interact with the dropdown menu item.
* fix(serve): address review feedback on trust polling and setValue assertion (#7268)
* fix(cli): correct daemon trust policy settings precedence and drain continuation (#7268)
* fix(serve): address review feedback on fork cleanup, persist simplification, sync guard, and a11y (#7268)
* fix(serve): assert before mutate in setValue, add pre-mutation guard, trust-before-generation ordering (#7268)
* fix(serve): honor system defaults in trust policy
Apply the documented settings precedence to daemon folder trust evaluation and keep workspaces outside configured trust rules fail-closed.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): preserve managed scratch trust during reloads
Keep daemon-created scratch workspaces trusted across policy reloads while retaining controlled-root validation, and reject trust mutations that cannot apply to these fixed-trust runtimes.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): guard auth provider persistence by generation
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* refactor(serve): remove Web Shell trust UI
Keep this PR focused on daemon and SDK trust reconciliation; the Web Shell integration can follow separately.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk): restore workspace trust bundle budget
Preserve the merge-only browser bundle allowance required by the additive workspace trust v2 SDK surface after rebasing.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): handle trusted folder write failures
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): keep capabilities available during trust reload
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): address review feedback for workspace trust hot reload (#7268)
Drop the closed generation guard before retrying dynamic workspace
runtime creation so the retried runtime starts with a fresh, open guard
instead of inheriting the one closed during the abandoned attempt. Make
the /workspace/reload trust reconcile fire-and-forget with a swallowed
rejection (failures are reported separately), reuse sendGenerationClosedError
for the memory write error path, and assert the subagent deletion commit
boundary once before unlinking so a closed generation fails atomically.
Add coverage for the blocked-entry deep health probe and the /session/:id/cd
generation-close-during-flight path.
* fix(serve): close trust reload cleanup gaps
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): use fire-and-forget for trust reconcile in workspace-qualified reload (#7268)
* fix(serve): address review feedback on generation guard and trust reconciler (#7268)
* fix(serve): use shared helpers for untrusted/generation-closed responses (#7268)
* fix(serve): continue cleanup after drain commit errors
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): retry transient trust policy disappearance
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): align status provider trust default with route-level check (#7268)
* fix(serve): clean up worktree on generation guard abort (#7268)
* fix(cli): guard tool and skill settings commits
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(cli): add discriminating persistent-ENOENT test for trust policy read (#7268)
* fix(serve): close runtime generation gaps
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): preserve scheduled task cap errors
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): address review feedback on trust reconciler, settings guard, and route simplification (#7268)
* fix(serve): preserve containment retry semantics
Restore the last verified trust-reconciliation and generation-guard behavior after the automated review fix marked an unconfirmed disposal as contained and removed per-scope commit checks. Defer the remaining late-round suggestions to avoid expanding the PR.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Autofix <qwen-autofix@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
* feat(web-shell): add managed workspace selector
Let Web Shell create and select daemon-managed workspaces without
changing ownership of existing sessions.
- Add capability-gated existing and scratch workspace registration
- Validate scratch roots, trust provenance, capacity, and shutdown races
- Serialize workspace mutations, session switching, and refresh results
- Add SDK/WebUI wiring and focused cross-package regression coverage
# Conflicts:
# packages/web-shell/client/App.tsx
# packages/web-shell/client/components/sidebar/WebShellSidebar.tsx
# Conflicts:
# packages/cli/src/serve/capabilities.ts
# packages/cli/src/serve/routes/workspace-management.ts
# packages/cli/src/serve/server.test.ts
# packages/sdk-typescript/src/daemon/DaemonClient.ts
# packages/web-shell/client/App.tsx
# packages/web-shell/client/components/dialogs/AddWorkspaceDialog.tsx
# packages/web-shell/client/components/sidebar/WebShellSidebar.tsx
* fix(web-shell): revalidate workspace before session creation
Prevent a stale workspace selection from bypassing the latest trusted
capability snapshot during lazy session creation.
- Validate the selected workspace before passing it to the daemon
- Fall back to the primary workspace when trust has been revoked
- Add a regression test for the pre-effect race window
- Remove stale branch state and clarify add-workspace ownership
* fix(web-shell): improve workspace removal feedback
Keep workspace removal controls legible and make blocked force removals
visibly inactive.
- Size the action menu independently from its narrow icon trigger
- Add a disabled affordance and suppress destructive hover styling
- Cover the removal menu width override with a regression test
* fix(web-shell): centralize existing workspace registration
Route sidebar and composer entry points through the App-owned dialog so
capability gating and workspace reconciliation remain consistent.
- Forward display names only when the daemon advertises support
- Hide and suppress persistence when registration is runtime-only
- Mark directory registrations with existing-workspace provenance
- Cover both entry points and capability combinations with tests
* fix(web-shell): address review feedback on workspace dialogs and capability docs (#7390)
- Document dynamic_workspace_registration and scratch_workspace_registration
in the conditional serve-features table so the capabilities-docs-contract
test passes.
- Gate DialogShell backdrop-click and Escape dismissal on the dismissible
prop so non-dismissible dialogs ignore both gestures.
- Surface an inline error when an added folder registers but the capability
refresh fails, mirroring the scratch recovery path.
- Add coverage for the active-session workspace switch and the add-folder
refresh-failure paths.
* fix(web-shell): address review feedback on workspace dialogs and capability docs (#7390)
---------
Co-authored-by: heyang.why <heyang.why@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Expose persisted active/archived/total (plus live) via a dedicated aggregate
endpoint so clients do not need to page the full session list. Counts reuse the
existing chats-dir disk scan pattern from session title search; responses mark
expensive/disk_scan so callers know not to poll.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(cli): group daemon channel workers by workspace (phase 4b)
Multi-workspace `qwen serve --channel` now runs one channel worker per owning workspace instead of a single primary-bound worker. Each worker binds to its workspace's directory, daemon-workspace env marker, and effective env overlay. Channels are grouped implicitly by their configured working directory: a channel belongs to the registered workspace its resolved cwd matches, mirroring the worker's own workspace validation. Unknown, ambiguous, or untrusted targets fail fast at startup.
The pidfile and daemon status grow an additive per-workspace worker list while keeping the existing single-worker fields for older readers; single-workspace daemons stay byte-identical to before. `--channel all` stays primary-only.
Refs #6378
* fix(cli): harden multi-workspace channel workers
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): close listener after channel worker startup failure
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): restore grouped channel webhooks
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): mount runtime before channel workers start
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* codex: address PR review feedback (#6635)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(cli): strengthen channel worker edge coverage
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* chore(cli): address channel review suggestions
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-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
* feat(serve): Add cursor-paged transcript replay endpoint
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): Bound transcript replay indexing
Limit transcript index builds to bounded snapshots and surface oversized transcript errors as 413 responses. Give transcript status calls a dedicated timeout and update the capabilities integration baseline.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): Validate transcript cursors
Sign transcript cursors so forged snapshot sizes cannot bypass the index cache, and keep hasMore tied to persisted record availability when replay conversion returns a partial page.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): Lazy-init transcript cursor secret
Avoid generating the transcript cursor HMAC key while importing the core barrel so unrelated tests with narrow crypto mocks can load core without requiring randomBytes. Keep the VS Code companion crypto mock partial so it only replaces the auth-token UUID behavior it asserts on.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): Address transcript replay review suggestions
Mark bounded replay truncation frames as having a transcript endpoint, sanitize paged transcript replay conversion errors, and remove the core reader's incomplete pre-encoded cursor field so cursors are only emitted after replay continuation state is merged.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): Stabilize transcript replay pagination
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): Avoid quadratic transcript line scanning
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): Mark transcript history gaps
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): Address transcript reader review comments
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): Address transcript replay review feedback
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): align transcript cursor preflight errors
Return transcript snapshot conflicts for cursor pagination when the active JSONL can no longer be found during route preflight. Add route-level and integration coverage for full transcript paging, and document the boolean fullTranscriptAvailable SDK contract.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(cli): Cover paged dangling tool call replay
Add a HistoryReplayer.replayPage regression test that carries a dangling tool call through pendingToolCalls and finalizes it on a later page.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): Bound transcript index cache bytes
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix: Address transcript replay review follow-ups
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): Preserve pending tool calls on transcript replay errors
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* codex: address PR review feedback (#6525)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* codex: fix CI failure on PR #6525
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): warm transcript-replay tools leniently
The read-only transcript-replay Config sets skipSkillManager, but Config.initialize() still runs toolRegistry.warmAll({ strict: true }), which constructs SkillTool whose constructor throws when no SkillManager exists. The throw escaped the replay try/catch and surfaced as JSON-RPC -32603, so GET /session/:id/transcript returned HTTP 500 for every persisted session.
Add a lenientToolWarmup initialize option and set it for the replay Config so tools that cannot construct under the deliberately-skipped subsystems are logged and skipped instead of aborting initialize(). Replay only needs optional tool_call metadata and ToolCallEmitter already falls back to the recorded tool name, so buildable tools keep full title/kind. This supersedes the narrower excludeTools:[Skill] guard, which is removed.
* fix(core): invalidate transcript index cache on in-place rewrites
An in-place transcript rewrite that keeps the inode and byte length (e.g. rsync --inplace or a redaction pass) reused a stale cached index, because makeCacheKey() keyed only on path:dev:ino:size. readSegmentRecords then found each recorded offset parsing to a different uuid and dropped it, so GET /session/:id/transcript answered 200 with an empty events array instead of the documented 409.
Include the file mtime in the index cache key so a fresh read after a same-size rewrite rebuilds the index, and raise SessionTranscriptSnapshotUnavailableError (-> 409) on a uuid mismatch or missing fragment instead of silently returning a short/empty transcript. Also make the qwen-serve docs explicit that at the default --channel-idle-timeout-ms 0 each page rebuilds the index (O(snapshotSize)).
* codex: address PR review feedback (#6525)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* qwen: fix CI failure on PR #6525
The Run ESLint step failed on vitest/valid-expect in packages/acp-bridge/src/bridge.test.ts: the getSessionTranscriptPage timeout test stores expect(request).rejects.toBeInstanceOf(BridgeTimeoutError) and awaits it only after advancing the fake timers (a deliberate deferred await so the pending timeout rejection has a handler before it fires). Auto-fixing would add an inline await and deadlock the test, so scope-disable the rule on that assignment with a rationale. lint:ci and the affected test pass.
* qwen: address PR review feedback (#6525)
Withhold nextCursor on a mid-page transcript replay error. When collectHistoryReplayUpdatesPage catches a replayError partway through a page, records after the failed one are dropped and pendingToolCalls reflect partial state; still emitting nextCursor advanced the client past the dropped records and carried corrupted pendingToolCalls forward (phantom in-progress tool calls on later pages). Now nextCursor is withheld whenever replay.replayError is set — the page is already flagged partial + replayError, so the client stops instead of paginating with corrupted cursor state. Update the handler test to assert no cursor is issued on a replay error.
* qwen: address PR review feedback (#6525)
Log when parseTranscriptReplayState drops malformed pending tool calls from a replay cursor. Previously rawPending.filter(isPendingReplayToolCall) silently discarded entries that no longer matched the shape (e.g. a cursor from a newer daemon or corrupted in transit), turning a version-mismatch/corruption into a hard-to-diagnose 'tool never completed' artifact on later pages. Now emit a debug warning with the dropped/total counts; behavior is otherwise unchanged.
* fix(serve): address transcript review feedback
Dispose superseded replay configs, preserve structured resolution errors, sanitize multi-workspace failures, and expand transcript replay coverage across unit and real-daemon integration paths.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* qwen: address transcript review feedback (#6525)
- [Critical] Map a missing transcript session to HTTP 404: the child throws a raw resourceNotFound (ENOENT without a cursor) that fell through sendBridgeError to 500. bridge.getSessionTranscriptPage now translates it to SessionNotFoundError, mirroring the load/resume path, with a bridge test.
- Dedup the untrusted-session-owner 403 onto the shared sendUntrustedWorkspaceResponse so the response format/message stay consistent across session routes (route logging + context preserved).
- Add coverage for parseTranscriptReplayState's non-object replay branch (cursor replay=garbage) -> empty pendingToolCalls + default cumulativeUsage.
- Document that cursorHmacKeys are cached for the daemon lifetime (external key rotation requires a restart).
* qwen: adopt transcript review suggestions (#6525)
- Add a handler test that a mid-page replay error preserves already-emitted events (events>=1) alongside partial+replayError and withholds the cursor.
- Add a two-call handler test for the cross-page cumulativeUsage round-trip: page 1 folds the bumped usage into the encoded cursor; page 2 decodes and propagates it into the replay context.
- Log (not silently drop) a superseded structured error in the multi-workspace transcript resolution fallback.
* qwen: clean up transcript test fixtures to fix no-AK CI flake (#6525)
The transcript-paging integration suite wrote ~6 persisted chats/*.jsonl sessions into the daemon's project dir and never removed them. Because vitest runs a file's suites sequentially, those leftover sessions widened a pre-existing race in the later 'PATCH /session/:id/metadata > updates displayName' test (a freshly-created session can exist on disk but not yet appear in the listWorkspaceSessions page), making it fail deterministically in the no-AK smoke run. Add an afterAll to the transcript suite that removes the project chats/ dir, restoring a clean session list for subsequent suites. Verified: full no-AK suite now passes 43/43 across repeated runs.
* qwen: harden transcript reader test timestamps + assert page fields (#6525)
The record() helper derived the ISO timestamp seconds from text.length, producing invalid values (e.g. 00:00:013) once a record's text reached 10+ chars — harmless today only because no test asserted startTime. Replace it with a monotonic base+offset timestamp (always valid, strictly increasing). Also assert the previously-unchecked required SessionTranscriptRecordPage fields (sessionId, filePath, startTime, lastUpdated); the strict-ISO checks on startTime/lastUpdated guard against the timestamp-helper class of bug.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
* feat(cli): List archived and organized sessions for non-primary workspaces
Trusted non-primary workspaces can now use archiveState=archived, view=organized, and group filters on the workspace session list routes, closing the remaining Phase 2b listing gap for the multi-workspace daemon. The listing engine was already workspace-scoped; a phase guard was the only thing rejecting these queries on non-primary workspaces, and the persisted/live selection is forced to the persisted store for organized and archived views. Untrusted workspaces are still refused, and legacy primary routes are unchanged.
Refs #6378.
* qwen: address PR review feedback (#6631)
Add a test for the view=organized&archiveState=archived combination on a trusted non-primary workspace: a pinned archived session sorts first and no live summary is merged into the archived view.
* qwen: address PR review feedback (#6631)
Log the requested view/archiveState/group in the session-list failure path, add a defensive guard so persisted-only options can never silently reach the live path, and cover the organized opaque-cursor pagination round-trip for a non-primary workspace.
---------
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
* feat(serve): add runtime.activity fields to daemon status API
Add activePrompts, lastActivityAt, and idleSinceMs to the
GET /daemon/status runtime section. These fields already exist on the
bridge (and are exposed via GET /health?deep=1) but were missing from
the richer status endpoint that operators use for troubleshooting.
The idleSinceMs value is computed from a cached lastActivityAt read
(same pattern as the health handler) to ensure consistency within a
single response.
* feat(serve): add MCP server health summary to workspace status
Extract serversConnected, serversErrored, and serversDisabled counts
from the MCP servers array into the workspace.mcp.summary object.
Operators can see MCP fleet health at a glance without expanding the
full JSON.
* fix(serve): guard activity fields against undefined bridge getters
Add ?? null / ?? 0 fallbacks for lastActivityAt and activePromptCount
to prevent RangeError when a test fake bridge omits these properties.
Carry nested-agent lineage (parentAgentId, parentName, depth) through the
daemon tasks snapshot as optional fields and render the web-shell tasks
panel as a tree: children group under their parent with a ↳ marker and
clamped indentation, agents whose parent left the roster are promoted to
root with a "from <parent>" annotation, and the detail view gains a
nesting line. The [blocking] tag and the two-step stop confirmation now
apply only to provably user-blocking chains, mirroring the TUI's
agent-forest semantics from #6191.