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(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>
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.
* feat(serve): query a single session's status by id
Add a daemon HTTP endpoint, GET /session/:id/status, that returns the
live status summary for one session by its id — the same per-item shape
that the workspace session list produces (sessionId, workspaceCwd,
createdAt, displayName, clientCount, hasActivePrompt). It answers 200
with the summary when the daemon holds a live session with that id, and
404 when the id is unknown.
Previously the only way to read a session's live state was the full
paginated workspace session list, forcing a caller that already holds a
session id to fetch every page and filter client-side just to answer
"is this session still running?". A by-id lookup is the natural
primitive for polling a single known session's hasActivePrompt /
clientCount — for example, a client UI that disables controls or shows a
"task in progress" hint while a specific session is running.
The data already exists on the bridge, so this adds one accessor
(getSessionSummary) sharing the same summary builder as the list path,
one route, unit tests, and a docs note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(serve): clarify /session/:id/status returns the live bridge view
The session-status docs said the response is "the same item shape that
GET /workspace/:id/sessions lists". That parity only holds at the bridge
layer; the HTTP list endpoint enriches each item with persisted
session-store data, so for the same live session the two routes diverge
on createdAt (persisted first-prompt time vs live spawn time), updatedAt
(present only on the list), and displayName (derived from the stored
title/prompt vs the live session's own, usually unset). Reword to
describe /status as the raw live-session view, spell out those
differences, and fix the 404 note to match the actual { error, sessionId }
body (no code field).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(serve): advertise GET /session/:id/status via session_status capability
The new single-session status route had no entry in the capability
registry, so clients couldn't feature-detect it the way they pre-flight
the sibling read-only session routes (session_context, session_tasks,
session_stats, session_lsp, …). Add an always-on `session_status` tag,
mirror it in the registered-features test, and document it in the
protocol feature list, the capability→route map, and the capability
versioning reference.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(serve): pin that /session/:id/status omits displayName when unset
The docs state the route returns displayName only when the live session
has one, but no test asserted the key is absent from the HTTP body in
that case — it relied implicitly on res.json() dropping the
undefined-valued key. Add a sibling 200 test with a summary that has no
displayName and assert the key is not present, so a future change to the
shared summary builder can't silently break the documented shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(serve): add session_status to the integration capabilities baseline
The capabilities-envelope integration test pins the full caps.features
list returned by a live daemon, so adding the session_status capability
tag to the registry made the live list diverge from the test's hardcoded
baseline (CI: expected 65, received 66). Add session_status to that
baseline in the same position the registry emits it (after session_lsp),
and to the session-lifecycle capability-tag reference for completeness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: 云胧 <yungsen.hys@alibaba-inc.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>