Settings.get returns raw merged config without element validation, so a
scalar or non-string tools.xdevInlineDevices entry reached Bun.Glob and
threw while building the system prompt. Normalized the allowlist to
string patterns and compiled globs once per render.
- Added `src/live/` subsystem with WebRTC transport, protocol parser, session controller, and headless Chromium audio injection.
- Added `LiveVisualizer` component with phase states, transcript display, and animated waveform rendering.
- Added `/live` slash command and `LiveCommandController` to toggle live voice sessions.
- Suppressed local TTS via `vocalizer.suspend()` during live mode to prevent audio conflicts.
- Added live-instructions and agent-final-message prompts for agent messaging context.
- Added `protocol.test.ts` covering event parsing, chunking, and context message construction.
- Extracted internal handlers and logic from AgentSession into dedicated runner, guard, and coordinator modules.
- Created standalone modules for bash execution, evaluation runners, IRC bridging, and prewalk coordination.
- Established dedicated session components for tracking stats, todos, streams, and retry fallback chains.
- Preserved existing session behavior while significantly reducing monolithic class size and complexity.
- #6417 moved findUniqueSuffixMatch (the only prior untilAborted user) out of read.ts and removed the import; #6404 added new untilAborted callsites in regions git auto-merged without conflict.
Bash treats \" inside a backtick substitution nested in double quotes as
a quote delimiter for the inner command; the generic backslash-skip made
isInsideShellQuote report such quoted literals as unquoted, wrongly
expanding internal URLs inside them (Codex P2 review finding).
Applied the read-selector misfire check to archive members after loading
the archive entry map and before mutation. Missing empty selector-shaped
members now fail closed, while existing literal members remain writable.
Added regression coverage proving rejected writes leave archives unchanged.
- Convert the hub tool renderer to a lazy getter to prevent initialization-order temporal dead zone issues.
- Add session move support to the fake ACP builtin session runtime.
- Serialized backend transitions across runtime state, tools, and prompts.
- Rehydrated Mnemopi listeners after clear and enqueue maintenance.
- Made memory.backend the sole post-migration local runtime gate.
Fixes#5638
isInsideShellQuote opened an expansion context for $() command
substitution but never tracked legacy backtick substitution, so an
unquoted skill:// (or other supported scheme) nested directly inside a
backtick pair within double quotes kept the outer quote active and was
left literal. Treat an unescaped backtick as an expansion-context
boundary on the same substitution stack, restoring the outer quote when
the pair closes, matching $() behavior including nesting in either
order. Single-quoted and escaped-backtick text stay literal.
Fixes#5645
- Shared unique workspace suffix resolution between read and direct edit modes.
- Preserved create destinations and ambiguous-path failures while resolving existing update targets.
- Added direct replace, patch, and apply_patch regression coverage.
Fixes#6359
The browser tool's open action only passed the requested timeout to acquireTab; acquireBrowser ran under the caller signal alone, so CDP discovery/connect could run through its own fixed 5s/30s waits past the requested deadline. A freshly-created browser also sat in the registry at refCount 0 during worker/surface acquisition: the worker-abort branch released it only on tempHold (never on the fresh refCount-0 case), orphaning the handle, and two different-name opens sharing one refCount-0 browser let a single failure dispose it out from under the survivor.
Compose one open deadline from the caller signal and params.timeout and thread it through both acquireBrowser and acquireTab; caller cancellation stays ToolAbortError, the requested timeout becomes a timeout ToolError. Hold one explicit registry lease across tab acquisition, released exactly once on the mutually-exclusive success/rollback paths, and make the worker-abort browser release mirror the error paths' refCount-0 check.
Fixes#6365
- Replaced single-provider preferences with ordered priority lists for web search and image generation.
- Added a `MultiSelectSubmenu` component supporting toggle and reordering interactions in settings.
- Implemented migration logic to convert legacy single-provider preferences into ordered priority lists.
- Updated setup wizard scenes, image generation fallback logic, and search provider chains to use priority lists.
A read-only step that mis-dispatches read as write passes the full read
expression (src/foo.tsx:1-260:raw) as the target. Because a literal colon
filename is legal on POSIX (#4618), write resolved it to filesystem creation
and reported success, leaving a stray zero-byte file the model could not
recover from - the local analogue of the xd:// near-miss guard (#6123).
assertNotReadSelectorMisfire now fails closed when the tail parses as a
read-tool selector, the literal target is missing, and content is empty,
pointing at the equivalent read(...). Non-empty content stays the escape
hatch and existing literal colon filenames remain writable.
Fixes#6387
Reverted branch-side edits to spawn-policy prompts/tests, settings tab
groups, mermaid cache typing, prewalk todo gating, and packages/ai test
churn back to merge-base content; trimmed their changelog entries. These
repaired stale CI against an older main and are stale or conflicting
against current main.
Gated the read.renderMarkdown opt-in at read time (details tagging) instead
of inside the renderer. The renderer gate silently flipped every
protocol-supplied text/markdown read (skill://, pr://, issue://, history://,
rule://, omp://, agent://, vault://, local://, memory://, ssh://) from the
formatted markdown cell to the raw code cell when the setting was off, which
regressed default TUI behavior. Local file tagging now happens only when the
setting is enabled, so the default render path is byte-identical to the
pre-setting behavior while opt-in previews still work end-to-end.
Also inlined the tautological isMarkdownContentPath wrapper, pinned the
widened prose-summary bypass (.mdx stays verbatim when prose summaries are
off) with a test, and documented it under Changed in the changelog.
Tested the shell-control guard against the raw command: whitespace
normalization collapsed newlines/CR before the guard ran, so
'git status\nrm file.txt' rode a 'git *' allow rule while bash executed
both lines. Honored tool-owned allow/prompt policies in yolo mode so
per-command prompt rules were no longer silently discarded under the
default approvalMode. Added precision regression tests through the real
matcher (separators, subshells, redirects, env prefixes, path/quoting
variants) that fail on the unfixed head.
A budget-aborted keep-alive subagent's job row (job id == agent id) settles
failed and is retained ~5 min; executeCancel short-circuited to
already_completed for that window, leaving the zombie registration
unkillable exactly when the user wants it dead. Fall through to
cancelAgentRegistration for settled rows; keep already_completed when no
lingering registration exists.
Also stop wiring AgentLifecycleManager.global() onto SDK sessions created
with a caller-supplied agentRegistry: the global lifecycle releases through
AgentRegistry.global(), so it would report a cancel while releasing an
unrelated global ref. Without a lifecycle, cancel falls back to
dispose + unregister on the session's own registry.
Addresses both Codex P2 review findings on #6319.
A keep-alive subagent force-stopped for exceeding its soft request budget
is kept resumable (status idle, adopted by AgentLifecycleManager) so its
context can be salvaged, but its async job row settles and is reaped after
~5 min. After that, hub cancel <id> only reported "Background job not
found" because executeCancel consulted AsyncJobManager alone, leaving the
registration unkillable short of a broker restart.
hub cancel now falls through to the agent registration when no live job
matches: for a sub the caller spawned, it aborts any in-flight turn,
disposes the session, and releases it from the lifecycle. Cross-agent
kills stay impossible and Main/advisor refs are never targeted.
Fixes#6315
The model-facing start content reported when a process exited before readiness,
but launchRenderResult rebuilt the interactive result solely from structured
details and dropped that explanation. Mirror the terminal-without-readyAt
condition in the TUI start renderer and add a renderer contract test.
Fixes#6303