- Added optional `AgentTool.matcherDigest(args)` hook so tools can expose plain source text instead of wire-encoded arguments to TTSR rule matchers.
- Implemented `matcherDigest` on edit (all modes: hashline, patch, apply_patch, replace) and write tools, stripping patch prefixes and JSON escaping.
- Added `TtsrManager.checkSnapshot()` to replace the scoped buffer with a tool digest rather than appending raw deltas.
- Fixed TTSR conditions never matching streamed edit/write calls whose wire format obscured real content.
Surface the hidden discoverable built-in tool names (write, find, search, lsp, task, ...) in the search_tool_bm25 description when tools.discoveryMode is "all", so a model can form a targeted BM25 query by name instead of guessing or falling back to shell. mcp-only mode is unchanged (no built-ins advertised) and the total-tools count still includes them.
- Expanded path parsing to split top-level comma, semicolon, and whitespace entries.
- Updated find/search and scope resolution to apply delimiter expansion before path-spec validation.
- Updated read tool fallback to try split path parts before raising missing-path errors.
- Coerced bare string arguments into singleton arrays for array-typed schemas.
- Changed `AgentOutputManager` to use requested names verbatim, adding `-2`/`-3` suffixes only on repeats (e.g. `Anna`, `Anna-2`).
- Renamed main agent id from `0-Main` to `Main`; nested ids now use dot notation without numeric prefix (e.g. `Parent.Child`).
- Updated task widget to render dotted hierarchy as `Parent>Child` breadcrumb without leading index.
- Resume scan now tracks seen names instead of a counter to avoid clobbering prior outputs.
- Added ROW_COUNT_PROBE_CAP to limit rows scanned when counting tables, preventing JS thread freezes on large databases.
- Used sqlite_stat1 estimates for tables exceeding the cap; exact counts only for provably small tables.
- Introduced TableRowCount type with exact/estimate/atLeast variants reflected in rendered output.
- Computed screenshot destination extensions from the MIME type of bytes being written.
- Updated auto-generated paths in screenshot and temp directories to use the matching extension.
- Extracted TUI rendering from `eval.ts` into a dependency-light `eval-render.ts` to break the circular initialization chain.
- `renderers.ts` now imports `evalToolRenderer` from `eval-render` directly, avoiding re-entry into the root barrel while `eval.ts` is still initializing.
- `eval.ts` re-exports `evalToolRenderer` and `EVAL_DEFAULT_PREVIEW_LINES` for backward compatibility.
- Increased first-event timeout test budget from 50ms to 5000ms to prevent CI scheduler jitter from tripping the watchdog on success cases.
- Moved EvalBackendsAllowance and related functions to a dedicated eval-backends.ts module.
- Replaced ad-hoc brokenShellSessions tracking with a quarantineShellSession helper that also awaits the abort cleanup promise.
- Applied quarantine on timeout and cancellation paths, not just errors.
- Added `DiagnosticsLedger` to track diagnostics already surfaced per file, suppressing repeats within a session.
- Wired dedup into both edit and write tools via a `transformDiagnostics` hook on the writethrough pipeline.
- Added `lsp.diagnosticsDeduplicate` setting (default: true) to control the behavior.
- Only bridge heartbeats (`agent()`/`llm()`) now re-arm the watchdog; compute, stdout, `log()`/`phase()`, and ordinary tool calls count against the budget.
- Emitted an immediate heartbeat at bridge call start to avoid early abort near budget edge.
- Removed `idle` flag and "of inactivity" suffix from timeout annotation strings.
- Updated docs, prompts, and comments to reflect the new wall-clock semantics.
The per-cell `timeout` is an inactivity budget that only re-arms on status
events, but host-side bridge calls can run long stretches with no
intermediate status (a subagent's time-to-first-token on a reasoning
model, a long quiet nested tool, or an entire oneshot llm() request).
The watchdog mistook that for a stall and aborted working subagents
mid-flight.
Pump a lightweight heartbeat while a bridge call awaits, re-arming the
watchdog through the existing emitStatus -> onStatus channel. The
heartbeat is a pure keepalive: forwarded to bump the timer but never
stored or rendered, so a genuinely stalled cell is still interrupted
once the call settles.
- eval/heartbeat.ts: withBridgeHeartbeat() + EVAL_HEARTBEAT_OP
- agent-bridge/llm-bridge: wrap runSubprocess / completeSimple
- js+py executors: forward heartbeat to onStatus, drop from displayOutputs
- tools/eval.ts: bump on heartbeat, skip persist/render
- Extended ResolveContext / WriteContext with localProtocolOptions so the
internal-URL router can thread the calling session's local-root mapping
through to handlers.
- LocalProtocolHandler.resolveOptions now prefers context.localProtocolOptions
before consulting the process-global override or the first main-kind session
in AgentRegistry, fixing multi-session ACP hosts (cmux) where reads of
local://PLAN.md were routing to a sibling session's artifacts dir even
though plan-mode writes succeeded against the calling session.
- read, find, ast_grep, ast_edit, and search now thread
this.session.localProtocolOptions into the router so local://, memory://,
agent://, and other handlers see the right caller.
- Added regression tests covering the override-vs-context priority and the
ENOENT-against-caller-root path.
Fixes#1608
Guarded find renderer path summaries so raw pre-validation string paths render instead of throwing. Added coverage for pending, fallback, empty, and detailed result render paths.\n\nFixes #1622
Included the reviews field in comments-enabled PR view fetches so pr:// output can show formal review submissions and approvals.
Added protocol coverage that emulates gh --json field selection before asserting rendered approval output.
Fixes#1600
- Changed eval timeout behavior from hard wall-clock deadlines to per-cell inactivity budgets in all executors.
- Added IdleTimeout watchdog support, including bumps on status/tool activity and timer cleanup after execution.
- Updated executor option plumbing to replace deadlineMs with idleTimeoutMs and emit inactivity timeout annotations.
- Added IdleTimeout and shared-executor tests and updated prompt/repl docs for the new timeout contract.
- Added optional `onStatus` callback wiring across eval backends and JS/Python executors for live status streams.
- Added collectDisplay-based forwarding so `emitStatus` and `onDisplay` route status outputs consistently.
- Expanded agent status payloads with preview/model/token-cost context and kept completion updates single-pass.
- Added status upsert and render adjustments in `tools/eval.ts` to coalesce agent events with progress stats.
- Added status/progress test coverage for running/completed agent events, final metric retention, and parallel placement.
- Updated CHANGELOG Unreleased notes to record live progress updates and completion-status metric fixes.
- Added +Nk/+Nm turn-budget parsing with whitespace-boundary matching, multipliers, and hard `!` indicator.
- Added per-turn budget lifecycle plus APIs (`getTurnBudget`, `recordEvalSubagentUsage`) and hard-cap checks in eval runs.
- Added hard budget observability in eval preludes and docs by exposing `budget.hard` and documenting ceiling modes.
- Fixed streaming preview stutter with max-row tracking and padding, with tests for preview height and budget parsing.
- Dropped `args` input from eval tool schema, JS/Python executors, and worker protocol.
- Removed per-call `args` injection from JS runtime and Python kernel/runner.
- Deleted related tests and updated docs to reflect removal.
- Stored mcpManager and localProtocolOptions on ToolSession so nested subagents inherit them without relying on process-global singletons.
- TaskTool now uses the session's localProtocolOptions and mcpManager when spawning sub-tasks, falling back to defaults if absent.
F1 (coding-agent): close the withFileLock mkdir-vs-writeLockInfo race that
let a losing contender wipe the winner's freshly-created lock directory.
Every lock now carries a per-process UUID token; releaseLock verifies the
token before fs.rm, and isLockStale no longer treats an info-less but
fresh dir (or a dir that vanished mid-check) as stale.
F4 (coding-agent): sanitize tabs and truncate oversized error strings in
formatErrorMessage so error renderings that embed file content
(apply_patch, hashline, etc.) cannot break terminal alignment or
overflow the line width.
F7 (ai): support named-tool routing on Google providers. Widens
GoogleSharedStreamOptions.toolChoice and GoogleGeminiCliOptions.toolChoice
to accept { mode: 'ANY'; allowedFunctionNames }. mapGoogleToolChoice
now converts ToolChoice { type: 'tool'|'function', name } to the wire
shape (mirroring mapAnthropicToolChoice). buildGoogleGenerateContentParams
and the gemini-cli request serializer honor the allow-list.
- Expanded search scope handling for virtual multi-file targets and executed grep only when searchable paths existed.
- Merged `searchVirtualResources` results into main output and rendered internal URL matches as accent lines.
- Updated grouped-file output to detect URL-like paths and keep full URL headers for root grouping.
- Documented URL path/range behavior and added tests for doc routing, missing-content errors, and `omp://` expansion.
- Added virtual internal URL path resolution in `SearchTool` via `InternalUrlRouter` for in-memory search.
- Added `omp://` root expansion so `search` resolves and scans each completion target.
- Fixed `SearchTool` handling of internal URLs without `sourcePath` by returning virtual matches instead of `Path not found`.
- Extended `edit-renderer.test.ts` coverage for normalizing raw streamed text in custom text renderers.
- Added clockwise sweeping dark segment animation to output block borders while bash/eval tool calls are pending/running.
- Changed bash renderCall to immediately render a full bordered block instead of a one-liner status preview, so silent commands show the framed block for their entire runtime.
- Added shimmerEnabled() helper and wired animate flag through OutputBlockOptions, CodeCellOptions, and shell/eval renderers.
- Updated read tool prompt to show alternate image description when inspect_image is disabled.
- Passed INSPECT_IMAGE_ENABLED flag into prompt rendering context.
- Added test verifying description omits inspect_image references when disabled.
- Added todo_write strike-frame animation timing and updated execution flow after completion finalizes.
- Added strike animation cancellation in cleanup to clear todo timer and reset frames when spinner is idle.
- Removed todo-closing state and timeout handling from interactive mode and simplified empty todo-list rendering.
- Reworked todo-write to compute completion transitions, track completedTasks, and render strike-through frames.
- Added test coverage for completedTasks, theme setup, and strike-through progression at hold-frame thresholds.
- Added `memory_edit` tool for update, forget, and invalidate operations on Mnemosyne memories by id.
- Added `stats` and `diagnose` methods to `MemoryBackend` interface with Mnemosyne implementations.
- Exposed `/memory stats` and `/memory diagnose` slash commands in TUI and ACP modes.
- Refactored recall output to include memory ids via `formatScopedRecallWithIds`.
- Tagged non-zero bash command completions as error results, capturing `exitCode` and keeping exit notices in returned text.
- Updated the shell renderer to hide duplicate exit notices from output while surfacing failed command status in the footer.
- Added tests for non-zero versus zero-exit bash results and footer rendering of failed commands.
- Added shared helpers and inline TUI renderers for retain, recall, and reflect tool outputs.
- Added tool registry entries for retain, recall, and reflect to use the new inline renderers.
- Updated changelog notes describing new memory inline rendering semantics and output headers.
- Added memory renderer tests for summary, truncation, streaming, and expand/collapse behavior.
- Renamed HindsightRecall/Reflect/RetainTool classes and files to Memory* for backend-neutral naming.
- Fixed Mnemosyne state to resolve separate db paths per bank instead of sharing one file.
- Updated test file and all imports to reflect the new names.
- Added `mnemosyne.scoping` setting: `global`, `per-project`, and `per-project-tagged`.
- `per-project-tagged` writes to a project-local bank while merging global memories on recall.
- Refactored `MnemosyneSessionState` to manage scoped recall/retain targets and deduplication.
- Updated hindsight tools to route recall/retain through scoped methods.
- Extended tool factories to activate on `memory.backend === "mnemosyne"` in addition to `hindsight`.
- Implemented Mnemosyne execution paths in all three tools using `recallEnhanced`, `remember`, and `beam.formatContext`.
- Exposed `getMnemosyneSessionState` on `ToolSession` and wired it through `createAgentSession`.
- Added usage guidance for `recall`, `retain`, and `reflect` to Mnemosyne static instructions.
- Replaced Hindsight-only contract tests with expanded suite covering both backends.
- Dropped local `renderJsonTree` and `formatJsonScalar` in favor of the shared `renderJsonTreeLines` used by tool args, MCP results, and subagent output.
- Removed `Object(N)`/`Array(N)` type labels and per-output `JSON output N` headers; type icons and bare keys are used instead.
- The `display[N]` header is now shown only when a cell emits more than one `display()` value.
- Replaced snapshot internals with full-file records and removed contiguous/sparse snapshot APIs.
- Added file-hash normalization, computed `computeFileHash`, and updated grammar/messages to 4-hex tags.
- Simplified recovery by checking whole-file hashes first, then applying merge-replay fallback after mismatches.
- Updated coding-agent tools to use `record`/`recordFileSnapshot` and skip hash headers for unsnapshotted large files.
- Expanded patcher and snapshot tests to verify 4-hex anchors, hash deduplication, and cache-capped behavior.
Four refinements to the sticky Todos panel on top of the live SessionObserverRegistry linkage:
- Cube animates whenever any visible open todo is "live" (in_progress, or a still-pending todo with a matching in-flight subagent). The previous subagent-only gate left lone in_progress rows on the static '⟳' fallback; ticking on an orphan in_progress row is the correct "still open" signal.
- 'normalizeForTodoMatch' now collapses any non-alphanumeric run to one space, so subagent descriptions with '#', '.', ':' etc. match todo content that omits the punctuation. Fixes the case where 3 subagents were spawned but only 2 of 3 matching todos lit up because the matcher's normalizer collapsed whitespace but left '#' intact.
- New '#reconcileTodosWithSubagents' runs on every observer-registry change and auto-checkmarks any pending/in_progress todo whose content matches a 'status === "completed"' subagent description. Failed/aborted subagents intentionally don't auto-flip - those stay open for the user (or next agent turn) to decide.
- All-done close animation: when every visible task is closed, fold the panel away over ~1.4s. A 900ms celebratory frame holds the bright bold "Todos ✓" header so the user can read the final checkmarks, then a fade through 'muted' / 'dim' with rows progressively dropped from the bottom. '#todoClosingState' state machine plays the animation exactly once per open->all-closed transition and aborts cleanly if a new open task arrives mid-animation.
Verification:
bun test test/tools/todo-write.test.ts → 24 pass / 0 fail (one new case for # punctuation tolerance)
bun run check → biome + tsgo clean
The always-on Todos panel above the editor pinned to the first 5 tasks of the active phase, so each todo_write flip mutated at most one row (color + strikethrough) and the +N more hint only shrank at end-of-phase. Marking task 1 done left tasks 6,7,... invisible until tasks 1-5 were all closed.
Introduce selectStickyTodoWindow(tasks, maxVisible=5) — returns up to 5 open (pending / in_progress) tasks in original phase order plus the count of remaining open tasks for +N more. When every task is closed, falls back to the trailing window (with +N more suppressed) so the panel keeps useful context until getActivePhase walks to the next phase. The collapsed branch of #renderTodoList now uses it; the expanded branch is untouched.
- Column truncation is now applied to a cloned array so `collectedLines` retains on-disk content for snapshot recording.
- Snapshots bound to hashline TAGs now hold the original file text, preventing hash-mismatch failures on subsequent edits to files with long lines.
- Added regression tests covering full-file, range, multi-range reads and a live edit-after-read scenario.
- Prepended `¶path#TAG` hashline header to plain file, ACP-bridge, and conflict resolution write results.
- Bulk conflict resolutions emit a trailing `Snapshots:` block with one header per written file.
- Suppressed when hashline display mode is disabled or for archive/SQLite/internal-URL targets.
- Added tests covering header presence, patcher usability, and disabled-mode suppression.
- Added vault:// URL parsing, typed variants, and path resolution with vault-root validation.
- Added VaultProtocolHandler with fs and Obsidian CLI-backed resolve/read/write/list support plus caching.
- Added vault scheme integration in router, path utils, and plan-mode guard using resolveVaultUrlToPath.
- Documented vault:// read/edit and `?op`-scoped URI formats in system prompts when Obsidian is available.
- Secured vault:// operations by rejecting traversal, absolute, and symlink-escape path cases.
- Fixed response.incomplete recovery by dropping truncated turns and promoting context.
- Added internal tests for vault protocol parsing, caching, CLI behavior, and invalid-path defenses.