Harness-initiated session aborts previously cancelled compaction before the handoff reason was recorded. The handoff catch then saw only an aborted signal and replaced the harness reason with "Handoff cancelled".
Abort the handoff first with the session reason, forward caller-signal reasons, and reserve "Handoff cancelled" for direct or unreasoned cancellation. Add a regression test for an in-flight handoff aborted through AgentSession.abort.
Fixes#7993
The #7904 fix stopped masking provider errors as "Handoff cancelled", but
an empty or whitespace-only generation still fell through: whitespace-only
text passed the `!handoffText` guard and produced a bogus handoff, while
empty text returned undefined which the interactive /handoff caller mapped
to "Handoff cancelled" with no detail and no log entry.
Treat empty/whitespace-only output as a real failure: a user-initiated
handoff throws "Handoff generation produced no content" (surfaced as
"Handoff failed: ...") and logs it; auto-handoff keeps returning undefined
so maintenance falls back to context-full compaction. Also log genuine
handoff failures in the command controller so they persist for debugging.
Fixes#7993
- 28 symbols across discovery, mcp header policy, agent-hub projection and
rendering, the agent registry, shell tokenizing and changelog comparison
were exported but referenced only inside their own module; they are now
module-private, shrinking the deep-import surface.
- Kept AGENT_PLUGIN_MANIFEST_SCHEMA, AGENT_PLUGIN_MCP_SCHEMA,
parseAgentPluginManifest, clearAgentPluginRootCache and mergeMCPHeaders
exported: each is a seam for tests that defend real parsing or header
precedence behavior.
- Nothing reachable from an explicit exports entry or public barrel changed.
- src/lsp/index.ts is the explicit ./lsp package entry, yet held 2821 lines of
warmup, config caching, diagnostics, external build-command workspace
diagnostics, the writethrough batching subsystem and the LspTool class.
- Those are now servers, diagnostics, workspace-diagnostics, writethrough and
tool modules; index.ts is 22 lines and re-exports the same public surface.
- configCache and writethroughBatches remain single instances and every tuned
diagnostics timing constant moved verbatim.
- Moved the module-level machinery that sat in front of the ModelRegistry
class into model-config-values, model-patch, custom-models and
model-provider-discovery; model-registry.ts drops 646 lines.
- commandValueCache and its negative-cache TTL stay single instances, so the
execSync storm the cache exists to prevent cannot return.
- The setCodexAttestationProvider import-time side effect stays in
model-registry.ts. The class itself was left alone: its private state is
shared across the methods, so splitting it is not a straight move.
- theme.ts mixed symbol presets, JSON schema, color math, the Theme class,
loading, global state, appearance handling and TUI adapters in 3171 lines.
- Symbols, schema, color, theme-class, loader and tui-adapters are now
siblings; theme.ts keeps global state, the watcher, appearance handling and
HTML export at 745 lines, with all 44 exports intact.
- Left appearance and export-colors in place: both read private mutable
auto-theme state, so extracting them would have required new exported
internals or DI rather than a straight move.
- Separated deterministic replacement generation, placeholder derivation,
placeholder-range scanning and message-tree transforms out of the 2647-line
module; obfuscator.ts now holds the types and SecretObfuscator.
- ephemeralPlaceholderKey stays a single instance and both global regexes stay
beside the code that resets their lastIndex, so placeholder stability and
the security argument in the moved comments are preserved verbatim.
- Repointed every importer at the real modules rather than leaving a re-export
shim; the public ./secrets barrel exports the same 15 names as before.
- gh.ts held wire types, search, Actions run-watch, PR checkout/push/create,
PR diff parsing and view fetch/format in 3958 lines.
- Split into gh-types, gh-search, gh-run-watch, gh-pr-checkout, gh-pr-diff,
gh-view and a gh-common module holding the shared primitives and the single
process-lifetime default-repo memo pair; gh.ts is now 246 lines.
- All 22 exports stay on gh.ts because tools/index.ts star-exports ./gh, so
the issue:// and pr:// protocol handlers needed no edits.
- ReadTool mixed plain-file reading with archive, sqlite, pdf-image, summary,
selector, formatting and renderer concerns in one 3763-line module.
- Each now owns a sibling module; read.ts drops to 2020 lines and keeps its
public exports, including the readToolRenderer re-export required because
tools/index.ts star-exports ./read through the explicit ./tools entry.
- The pdfImageExtractions map and summaryParseCaches WeakMap stay single
instances; execute() was deliberately left intact.
- builtin-registry.ts held a 2341-line array of every command spec with its
handler inlined, plus the autocomplete builders and the TUI dispatcher.
- Specs moved verbatim into modes, collaboration, session, lifecycle,
marketplace and control modules; completions moved to builtin-completions.
- builtin-registry.ts is now a 174-line composition/dispatch module and keeps
all 16 exports. Command order is unchanged, which matters because it drives
autocomplete ordering and BUILTIN_SLASH_COMMAND_DEFS.
- Python, Ruby and Julia each carried their own copy of the same session
maps, acquire/reset/replace/dispose lifecycle and executeOnSession; one
generic registry now owns it, parameterized by a per-language descriptor.
- Julia additionally re-implemented seven executor-base helpers locally; those
copies are gone and executor-base gained sparse managed-env and timeout
resolver hooks so Julia's differing behavior survives unchanged.
- All twelve exported entry points keep their names and signatures.
- A provider-supplied retry-after now bypasses the transient rate/concurrency
heuristic window instead of being overridden by it (regression from the
subscription-cap retry change).
- Updated event-controller/ui-helpers test doubles for provenance-gated
renderer selection (hasBuiltInTool), aggregated retryErrors on
auto_retry_end, and Bedrock override compat gaining streamIdleTimeoutMs.
Preserved zero-width readiness and wait matches across the daemon wire protocol, and isolated malformed completion events from unrelated pending RPCs.
Fixes#7908
Added the upstream unregisterProvider lifecycle to queued and initialized extension runtimes. Provider removal now clears runtime model/auth state before replacement, while failed factories restore the prior registration queue.
Fixes#7914
Published per-cwd discovery snapshots to existing task tools and refreshed them from TUI, ACP, and Agent Control Center reload paths.
Added regressions for existing and future task tools across TUI and ACP reloads.
Fixes#7940
A cooldown-expiry model revert runs at a turn boundary. The user-prompt
path reverts then re-checks accumulated context against the restored
model via runPrePromptCompactionIfNeeded, but the automatic
agent.continue() path (#scheduleAgentContinue) reverted and issued the
next request with no such check. When a transient failure had fallen
back to a larger-window model and the conversation then grew past the
original model's window, restoring the primary once its cooldown expired
sent a predictably oversized request to the smaller model.
maybeRestoreRetryFallbackPrimary now reports whether it actually
switched, and the auto-continue path runs the same post-revert
context-fit maintenance (compaction/promotion) the prompt path already
runs, but only when a revert occurred.
Fixes#7952
- Runtime error now just says to download vscode-js-debug from its GitHub repo;
tarball recipe, extract path, env var, and Mason detail stay in docs/tools/debug.md.
The handoff catch in session-handoff.ts and the /handoff handler in
command-controller.ts mapped any error named AbortError to "Handoff
cancelled" regardless of whether the handoff signal was actually
aborted. Providers throw name-AbortError errors on non-user conditions
(stalls, idle timeouts, nested resolution failures), so a genuine
generation failure surfaced as a user cancellation and hid the cause.
Only report "Handoff cancelled" when handoffSignal.aborted is set;
re-throw the real error otherwise. The controller now trusts the
normalized "Handoff cancelled" message and drops its own AbortError
check so re-thrown provider failures render as "Handoff failed: ...".
Fixes#7903
The `cd <path> && ...` extractor matched everything up to the first `&&`
with a greedy regex, so a redirect or extra argument before the `&&` was
swallowed into the structured cwd. `cd /tmp 2>/dev/null && echo ok` became
cwd `/tmp 2>/dev/null`, which failed fs.stat and killed the command before
the shell ran.
Replace the regex with `extractLeadingCdTarget`, a quote/escape-aware
scanner in shell-tokenize.ts that captures exactly one path token and
bails (leaving the command for the shell) when anything else — a redirect,
extra argument, shell expansion, or a non-`&&` separator — precedes the
top-level `&&`.
Fixes#7883
Address review feedback: the segment previously read the setting from ctx.session.settings, a second source of truth that could disagree with the component's effectiveSettings.sessionAccent and crashed lightweight test fixtures lacking a settings manager. Resolve the value once in #buildSegmentContext from the effective settings and pass it through SegmentContext.sessionAccent so the name segment and the gap-fill divider consume the same value. Add regression assertions for the enabled and disabled branches and a changelog entry.
The session_name segment rendered the session name text with getSessionAccentHex unconditionally, ignoring the statusLine.sessionAccent setting. The adjacent gap-fill divider (component.ts) already gated on sessionAccent !== false, so disabling the setting only removed the accent-colored divider line while the session name itself stayed hash-colored - an inconsistent half-off state.
Read the setting via ctx.session.settings.get (same pattern already used by the goal segment in this file at line 206) and fall back to the theme accent color when disabled, matching the divider behavior.