Main removed the floating todoReminderContainer in 112317bc8 (todo
reminders are now anchored inside the scrollback transcript and reset
by renderInitialMessages({clearTerminalHistory: true})), so the added
this.todoReminderContainer.clear() references a property that no longer
exists post-merge, failing typecheck and throwing on every /btw branch.
Revert the interactive-mode hunk and its test, and reword the changelog
entry to cover only the goal-mode todo context fixes.
The github renderer materializes plain Text per display rebuild, so its
animatedPendingPreview opt-in requested 30fps repaints with a frozen
glyph for the whole run_watch wait; drop the flag. Custom tools with
only one of renderCall/renderResult never route to the animated generic
fallback, so gate the unregistered-renderer spinner on both being
absent. Regression tests for both no-tick contracts.
`registerPersistedSubagentsFromDir` in `packages/coding-agent/src/modes/components/agent-hub.ts` used `fs.readdirSync` recursively to walk persisted subagent directories, blocking the event loop with unbounded synchronous I/O when the Agent Hub opened. Converted `registerPersistedSubagents` and `registerPersistedSubagentsFromDir` to async functions using `fs.promises.readdir`, and changed `AgentHubOverlayComponent`'s constructor to start registration fire-and-forget, exposing `persistedSubagentsReady` so callers can observe completion. Failures are logged with `logger.warn`, rows are refreshed on success, and a final render is requested in `finally`. Verified with `bun --check packages/coding-agent/src/modes/components/agent-hub.ts` and `packages/coding-agent/test/agent-hub-activate.test.ts`.
Closes#4239
Every keystroke or arrow-key navigation in the copy selector re-rendered the preview by syntax-highlighting the entire `target.preview`, replacing tabs, and wrapping it to width. `CopySelectorComponent` now keeps instance-private memo fields for the last target and its generated source; `invalidate()` clears them, and rendering reuses the cached source while the selected target is unchanged. Verified with `bun test packages/coding-agent/test/modes/components/copy-selector.test.ts` (5 pass, 0 fail).
Closes#4238
main independently absorbed batch-1 (incremental grapheme slice 718c7cea2, markdown
stream-prefix cache 705426548 + 3822a83b4) and the pathTo/patch.ts items; restore
main's refined versions wholesale. Port the model-resolver optimization onto main's
resolver shape: hoist per-candidate case folds in matchModel and build the
preference context once per role resolution (matchPatternWithContext) instead of
per fallback pattern. Rewrite changelog entries to the surviving items only.
- Added an enhanced speech pipeline that utilizes small models to rewrite text for natural language synthesis.
- Implemented `SpeechEnhancer` and `BlockAccumulator` to manage fence-aware text streaming and paragraph splitting.
- Configured a new `speech.enhanced` setting to toggle between mechanical and enhanced vocalization modes.
- Resolved `EPIPE` rejections during speech playback by ensuring stream flushes and suppressing stop-related errors.
- Replaced `grep`, `glob`, and `ast_grep` `paths` inputs with optional single `path` strings while preserving default workspace-root behavior.
- Added shared `toPathList` normalization for legacy arrays and JSON-encoded arrays across tool execution and TUI renderers.
- Updated prompts, fixtures, shims, transcript summaries, and tests to send and display the new `path` argument.
- Updated collab-web search tool cards to read `path` while falling back to legacy `paths` for historical transcripts.
- Recorded the contiguous coding-agent changelog run for the tool-path breaking change and adjacent TTS entries.
Some filesystems (NFS, FUSE, older SMB) return UV_DIRENT_UNKNOWN, making every Dirent.isX() return false. The prior early-return dropped real directories on those mounts. Now only reject when a known non-directory type (file/device/fifo/socket) is reported; symlink and unknown-type entries fall back to fs.statSync.
The overlay's directory cache stored names only, so listChildDirectories/searchDirectories called fs.statSync on every cached entry per keystroke to filter directories — a stat storm scaling with the target directory size and particularly costly on Windows.
Cache fs.Dirent[] via readdirSync({ withFileTypes: true }) instead of names, classify with entry.isDirectory(), and fall back to fs.statSync only for entry.isSymbolicLink() so a symlinked directory still counts as one. Adds a regression test that spies on fs.statSync and asserts an O(1) stat budget per keystroke.
Fixes#4199
- Refactored `renderSubagentHudLines` to use `renderTreeList` with dim connectors and a single-space indentation shift.
- Adjusted budget limits to account for the new layout wrapping and tree-list padding.
- Introduced the `CollabGuestUiResult` type to distinguish between answers and unavailable states during guest UI requests.
- Updated the remote dialog race logic to ignore unavailable guest results and fallback to the local host dialog.
- Centralized the `FakeWebSocket` and `InMemoryRelay` test infrastructure into a shared test helpers file.
- Cleaned up duplicate mock implementations and updated existing test suites to utilize the shared in-memory relay helpers.
- Consolidated duplicated inline thinking level comparisons into a unified `concreteThinkingLevel` helper.
- Enhanced legacy tool shims to respect isolated session settings and support legacy options.
- Cleaned up redundant UI render requests and extra status-line updates.
- Refactored `grep` tool shim to configure context dynamically via isolated settings.
- Disabled platform-incompatible shell shim tests on Windows environments.
- Introduced `RpcShutdownCoordinator` to track background tasks and manage deferred shutdowns safely.
- Guaranteed all background bash task response frames are fully written before the process exits.
- Re-checked shutdown requests automatically as each tracked background task settles.
- Latched the shutdown sequence to prevent concurrent execution from duplicate triggers.
- Updated `mock-rpc-agent` to consume stdin via an async iterator to match standard behavior.
- Added comprehensive unit tests in `rpc-input-frame.test.ts` covering background task coordination.
- Introduced JSON depth tracking to ensure string keys are only extracted at the top level.
- Prevented nested keys matching designated streaming keys from being prematurely or incorrectly captured.
- Added comprehensive unit tests validating nested key exclusion and correct top-level extraction order.
- Introduces `sanitizeErrorLine` to collapse newlines, replace tabs, and shorten absolute paths.
- Truncates remote error and notice text to the available terminal width to prevent layout breaking.
- Corrects a potential runtime exception in status-line by safely accessing JSON stringified length.
- Ensures in-memory overlay edits are durably written to the plan file before proceeding with approval.
- Avoids asynchronous write races by awaiting the final plan file serialization.
- Aligns synthetic approved-plan prompts with reference-only expectations.
- Thread the postmortem reason through the session teardown pipeline to the session dispose process.
- Prevent generic "dispose" logs from overwriting real triggers like SIGTERM, SIGHUP, or uncaught exceptions.
- Ensure the first teardown trigger's reason is preserved when concurrent disposal calls occur.
- Add comprehensive test coverage verifying signal-specific reason mapping inside exit diagnostics.
- Fix a minor unhandled-exception test utility expectation in input controller tests.
- Extracted decodeStreamedToolArgs into tool-args-reveal.ts and used it from both the live event path and transcript rebuilds, so mid-write theme/settings/focus replays no longer show stale streamed write/edit/eval content.
- Fixed the smoothing-off live path returning stale provider-parsed args.
- Documented the mandatory shared decode in the AGENTS.md streaming-preview hazard note; added changelog entries for this batch.
Ports only the thinking double-format fix: resolveThinkingDisplay reuses block.thinking when rawThinking is set (buildDisplayMessage already formatted it), plus a single-entry memo in formatThinkingForDisplay and a rawThinking regression test. The PR's incremental reveal slicing is superseded by the already-merged #3848 (memoized grapheme slicing).
/quit and /exit hung for many seconds because AgentSession.dispose()
awaited MnemopiSessionState.dispose() unconditionally, and that path
runs consolidate() (state.ts:421) which fires a fresh LLM fact
extraction for the just-retained transcript and then awaits
flushExtractions() per owned bank. One LLM round-trip per shutdown,
no upper bound, no visible status.
- Add a timeoutMs option to MnemopiSessionState.dispose. When the cap
fires the in-flight consolidate is detached to the background and the
SQLite handles close once it settles, so writes never race a closed
handle.
- AgentSession.dispose passes SHUTDOWN_CONSOLIDATE_BUDGET_MS = 1_500 on
the user-visible shutdown path. Per-turn maybeRetainOnAgentEnd has
already retained earlier turns, so the worst case is losing episodic
promotion for the last few turns. State-replacement disposes
(mnemopiBackend.start) stay unbounded.
- InteractiveMode.shutdown surfaces a 'Closing session…' status before
dispose runs so the brief pause is explained rather than mysterious.
Two regression tests in memory-tools.test.ts cover (1) dispose returns
within the budget when flushExtractions stalls and the deferred close
still runs once consolidate settles, and (2) unbounded dispose still
runs the full #2320 consolidate-then-close pipeline.
Fixes#3641