* fix(feishu): keep streaming card snapshots authoritative
Co-authored-by: Jun Ma <hpumajunhappy@163.com>
* refactor(feishu): use current snapshot as retry source
* fix(feishu): validate CardKit response bodies
* fix(feishu): keep close summaries accepted
* test(feishu): simplify close rejection state proof
* test(feishu): match normalized close summary
---------
Co-authored-by: Jun Ma <hpumajunhappy@163.com>
* fix(agents): apply stale-run liveness to aborted subagent orphan recovery
Skip stale unended subagent runs during orphan recovery and registry
restore, even when they carry abortedLastRun. Previously, restart-aborted
runs were exempt from the stale-unended age check, allowing hours-old
aborted child sessions to be resurrected after long downtime.
Fixes#90766
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(agents): finalize stale aborted runs instead of only skipping them
Previously the stale-run check in recoverOrphanedSubagentSessions only
incremented the skipped counter. Stale active runs were left unended
because scheduleOrphanRecovery only retries failedRuns, not skipped runs.
Now stale runs are finalized via finalizeInterruptedSubagentRun so they
don't remain orphaned in the registry.
Ref: #90766 review feedback
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(agents): await stale-run finalization in orphan recovery
Await finalizeInterruptedSubagentRun for stale aborted runs and report
failedRuns when finalization does not update the registry, so the
scheduler retry path can recover from finalization failures.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(agents): faithful restart-path proof for stale orphan recovery
Drive the real recoverOrphanedSubagentSessions against the real subagent
registry, the real isStaleUnendedSubagentRun policy, and a real on-disk
session store, mocking only the outbound gateway transport and transcript
reader. Proves finalizeInterruptedSubagentRun actually ends the stale
aborted run in the registry (endedAt set, outcome error) instead of
resuming it, while a fresh aborted run still resumes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: amend author email
* fix(agents): scope orphan finalization to run generation
* fix(agents): preserve stale restart recovery ownership
* test(agents): isolate restart recovery scheduling
* fix(agents): make stale restart finalization durable
* fix(agents): keep stale retries generation-scoped
* test(agents): await restart recovery scheduling
* fix(agents): verify interrupted finalization
* fix(agents): defer interrupted finalization during restart
* fix(agents): preserve lifecycle type narrowing
* style(agents): use nonmutating recovery ordering
* chore: keep release note in PR body
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Pick-cat <266665499+Pick-cat@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(ui): worktrees page owners and creation, structured snapshot failures, preserved-checkout cleanup
- Worktrees settings page gains an Owner column (manual/Workboard/session
with a link into the owning chat) and a New worktree form with repo
default, optional name, and a worktrees.branches-backed base picker
- non-forced worktrees.remove snapshot failures are a structured
{ removed: false, snapshotError } result (typed WorktreeSnapshotError in
the service) instead of error-string sniffing in the UI
- deleting a session whose dirty/unpushed checkout was preserved now
reports worktreePreserved through the session capability and offers an
explicit force removal instead of silently orphaning the checkout
Part of #103431
* fix(ui): report preserved checkouts from batch session deletes
deleteMany now aggregates worktreePreserved results, and the Sessions
page surfaces one notice pointing at Settings -> Worktrees instead of
silently orphaning dirty checkouts during bulk deletion.
Part of #103431
* fix(ui): reconcile generated locale artifacts after rebase
Open Settings from anywhere in the Control UI with Shift-Command-Comma while preserving browser-owned Command-Comma and existing shortcuts.
Prepared head SHA: 769a4fec5f
Co-authored-by: shakkernerd <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
* feat(ui): sessions sidebar redesign with agent sections, smart groups, and draft sessions
- agents become collapsible top-level sidebar sections; expanding an agent
browses its sessions without navigating, replacing the hidden scope select
- built-in smart groups: one section per channel (rows keep their chat
titles), a Work section for worktree/exec-node sessions with a
repo/branch/node subtitle, custom groups, and Chats
- session names never show raw keys or peer ids; DM fallbacks shorten ids,
dashboard sessions read 'New session', unnamed work sessions read as
their checkout
- one + opens the new-session draft dialog: agent, exec host (paired
system.run nodes), folder, worktree toggle with base-branch picker
(worktrees.branches) and optional name; the first message creates the
session and starts the run in one sessions.create call
- custom group catalog/order moves to the gateway (sessions.groups.*) with
a one-time localStorage migration; rename/delete update members
server-side instead of client-side paging
Part of #103431
* fix(ui): resolve dragged sessions across browsed agent sections
Dropping a row dragged out of a non-active agent section now finds the
session in the per-agent row cache instead of only the active scope, so
the category patch is applied instead of silently doing nothing.
Part of #103431
* fix(ui): propagate group catalog changes to open clients
sessions.groups.put/rename/delete now always broadcast a groups-change
event, and the session capability reloads the gateway-owned catalog when
one arrives, so another browser's group create/reorder/rename/delete no
longer leaves this client on a stale snapshot for the rest of the
connection.
Part of #103431
* docs: restore new session dialog section after rebase
* fix(ui): translate new sidebar/session strings and refresh docs map
Real locale translations for the new-session dialog and sidebar keys
(the fallback gate requires zero recorded English fallbacks), plus the
regenerated docs map for the new Control UI section.
Part of #103431
* fix(ui): repair locale metadata after rebase conflict resolution
* fix(ui): merge mainline locale keys with the sidebar redesign strings
* fix(ui): refresh raw-copy baseline for mainline tool-card strings
* fix(ui): reconcile generated locale artifacts after rebase
* fix(chutes): redact OAuth error response body in token exchange and refresh
Replace readResponseTextLimited + raw body in error message with
extractProviderErrorDetail for bounded, redacted structured error detail.
Ref: #102953
* fix(chutes): update test assertions for extractProviderErrorDetail message format
* fix(chutes): remove unused readResponseTextLimited and CHUTES_OAUTH_ERROR_BODY_LIMIT_BYTES
* fix(chutes): normalize OAuth HTTP failures
* test(chutes): assert redaction without fixed mask
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(grep): stop before ripgrep when aborted during setup
* fix(grep): check cancellation before ripgrep spawn
* fix(grep): make cancellation own process lifecycle
Co-authored-by: qingminlong <qing.minlong@xydigit.com>
* test(grep): use bound lifecycle assertions
Co-authored-by: qingminlong <qing.minlong@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>