- Added write-token generation and validation to distinguish writable and read-only guests.
- Added deep-link support using `https://<relay>/#<link>` with 32/48-byte collab secrets.
- Added full-link and key-only semantics where full links grant writes and key-only links are view-only.
- Added /collab view/status/stop command updates with read-only participant status and join hints.
- Moved completion/hint builder functions and BUILTIN_SLASH_COMMANDS materialization into slash-commands/builtin-registry.ts.
- Removed those builder definitions from extensibility/slash-commands and shifted type exports to the types module.
- Updated interactive-mode to import BUILTIN_SLASH_COMMANDS from builtin-registry instead of the extensibility wrapper.
- Recomputed `tools.discoveryMode: "auto"` in the deferred MCP closure in `sdk.ts` once the real tool count is known: a toolset crossing the threshold now flips discovery on, registers and activates `search_tool_bm25`, and skips `activateAll` instead of force-activating every MCP tool.
- Guarded the deferred MCP task against disposed sessions: added `AgentSession.isDisposed` and `enableMCPDiscovery()`, and the late connect now calls `disconnectAll()` instead of refreshing tools onto a dead session.
- Cleared `#fastPathKey`/`#fastPathItems` in `AssistantMessageComponent.invalidate()` so theme/symbol changes rebuild reused Markdown children instead of keeping stale captured themes.
- Memoized unusable read summaries as a `false` sentinel in `read.ts` so the per-session LRU no longer retains full sources of unsummarizable files.
- Broadened `HAS_REF_DEF` in `markdown.ts` to match backslash-escaped reference labels (`[a\]b]: x`) and cleared frozen stream-lex state on blank `setText()`.
- Added regression tests: deferred auto-discovery flip and mid-connect dispose (`sdk-mcp-auto-discovery.test.ts` + `many-tools-mcp.ts` fixture), fast-path child rebuild on invalidate, and escaped-ref-def incremental-lex equivalence.
Reviewer flagged that the bracketed-paste path is untrusted terminal input —
ANSI escapes, control chars, newlines/tabs, or a multi-hundred-char path
would corrupt the status line (per AGENTS.md TUI sanitization rules) and
leak the absolute home-dir path.
The new ENOENT diagnostic now feeds the path through sanitizeText (strip
ANSI/C0/C1 controls), collapses CR/LF/TAB to single spaces, runs it
through shortenPath (collapse home → '~'), and truncateToWidth-clamps it
to TRUNCATE_LENGTHS.CONTENT (80) before interpolating into either the SSH
or local status string. Added a third assertion to the repro test
defending the contract: ANSI/control bytes never reach the status, and
the displayed path is bounded below the input length.
Refs PR #2376
When a local terminal forwards a bracketed-paste containing an image-file
path and the omp process is itself running on the remote end of an SSH
session, the path is on the user's local machine and unreachable from the
remote filesystem. The path-as-text fallback in handleImagePathPaste then
made it look like the image was attached when in fact only a useless
absolute path entered the editor and the bytes never crossed.
Distinguish ENOENT from other read failures: drop the misleading
path-as-text degrade, and surface a clear status that names the file and
— when SSH_CONNECTION/SSH_TTY/SSH_CLIENT indicate the remote end of an
SSH session — points the user at the clipboard image-paste shortcut so
the bytes actually cross. The ImageInputTooLargeError and unknown-error
branches keep their existing fallback so genuine type issues still
yield the user's input back to them.
Fixes#2375
Dynamically assigns segment colors by sweeping across the full HSV hue spectrum based on their track position. This ensures each segment has a distinct, predictable hue and removes the need for explicit `color` assignments.
Pressing Ctrl+T (toggle thinking-block visibility) — or any other path that calls rebuildChatFromMessages, e.g. the theme/preset selector — during the pre-streaming window after a submission cleared the just-submitted user message until the first assistant token arrived.
startPendingSubmission paints the user message optimistically before session.prompt(...) lands it in session entries; rebuildChatFromMessages reads buildTranscriptSessionContext() which has no record of it yet, so the rebuild erased it and the streaming-component re-add block in toggleThinkingBlockVisibility was a no-op (no stream yet).
Centralize the fix in rebuildChatFromMessages: after rendering the transcript, replay the in-flight optimistic user submission. EventController#handleMessageStart already clears optimisticUserMessageSignature once the real user message_start lands, so the replay is a no-op post-streaming and cannot duplicate. cancelPendingSubmission clears the signature and marks the submission cancelled before its own rebuild, so cancellation paths still wipe the message.
Fixes#2372
- Added SGR mouse routing to wizard scenes for hover, click, and wheel interactions.
- Added pointer-based tab selection and panel wheel scrolling in providers tabs.
- Added splash/outro left-click handling to start and complete the wizard flow.
- Added setup-wizard tests for mouse routing, splash click entry, and local coordinates.
Updated thinking visibility toggles to refresh assistant blocks in place instead of rebuilding the transcript, preserving pending user submissions and loaders before streaming starts. Added a regression test for the Ctrl+T pre-stream gap.\n\nFixes #2370
- Updated snapcompact selectors and previews to pass `ShapeTarget` into `resolveShape` so `auto` is model-tuned.
- Applied `providerFrameBudget` in session compaction so generated archives stay within provider image caps.
- Replaced inline hard-coded image limits with `providerImageBudget` and skipped rasterization at cap.
- Added OpenRouter inline-transformer tests for cap exhaustion and existing-image budget exhaustion behavior.
- Added `ToolRenderer.provisionalPendingPreview` in `renderers.ts` and consulted it from `ToolExecutionComponent.isTranscriptBlockCommitStable`, replacing the 15.11.6 blanket gate that marked every collapsed pending preview commit-unstable.
- Marked only the tail-window previews the result render re-anchors as provisional: the edit streamed-diff tail (`edit/renderer.ts`), bash/ssh command caps (`createShellRenderer`, `sshToolRenderer`), and eval cells with interleaved outputs (`evalToolRenderer`).
- Restored mid-stream scrollback commits for every other pending preview, so tool calls taller than the viewport (e.g. a task call's context/assignment markdown) no longer read as cut off until the result lands.
- Added a regression test in `tool-live-region-scrollback.test.ts` scroll-appending a tall collapsed streaming task call into native scrollback mid-stream.
- Added `SnapcompactShapePreview` (`snapcompact-shape-preview.ts`), rendering the highlighted shape variant over the sample text in `snapcompact-shape-preview-doc.md`; `auto` resolves to the active model's winning shape.
- Wired the preview as a footer component below the interactive rows in `settings-selector.ts`.
- Passed `modelApi`, `imageBudget`, and `requestRender` through `SelectorController` so the preview can rasterize against the session model and request repaints.
- Added snapcompact.shape setting with auto and variant options in agent config.
- Implemented resolveShape support for forced variants, auto provider winners, and repricing.
- Threaded resolved shape into compaction and inline-image flows for pricing and rendering.
- Updated fuzzy-search indexing to track compact word starts and required phrase matches to start at word boundaries.
- Adjusted token scoring and compact/phrase matching rules so exact and boundary-aware matches now rank above noisy substring matches.
- Filtered session search results to drop weak pure-fuzzy matches unless they contained literal tokens, and updated ranking tests for the new behavior.
- Added `handleUsageResetCommand` support to list and redeem usage reset credits.
- Refactored `/usage` into `show` and `reset` subcommands and removed `/reset-usage`.
- Handled ACP/TUI `/usage` flows so `show` reports usage and `reset` redeems credits.
- Kept selected theme setting values dirty-colored while selected in the UI list.
- Added `parentToolCallId` and `index` fields to subagent session records and propagated them from task lifecycle and progress events.
- Reworked subagent ordering to sort by parent-group order, spawn index, and stable creation order so out-of-order updates no longer reshuffled active HUD rows.
- Updated task execution to pass spawn indices through sync and async paths, switched the `tool.task` icon to Octicons tasklist, and added a registry test for out-of-order progress ordering.
- Added commit-stability signaling to transcript blocks and marked tool previews as unstable until expanded or finalized.
- Updated transcript scrollback promotion to derive live commit state only for blocks reporting commit-stable rows.
- Added tests ensuring provisional pending edit previews are never committed while durable live rows still promote after the stability window.
- Added AuthStorage.listResetCredits to query each stored Codex account from the reset-credits endpoint and return live availability plus active or error state.
- Exposed the new status fetch through AgentSession and switched reset-usage selectors and commands to consume it via toResetUsageAccounts.
- Updated reset-usage UI and slash-command output to show per-account errors and updated empty-state messaging when resets could not be loaded.
- Added an anchored Subagents HUD renderer that formats active subagent sessions as `Id: description` rows.
- Integrated a new interactive-mode container and observer-driven render path so the HUD updates with session events and clears when no subagents are active.
- Exported `formatTaskId` for shared HUD formatting and added tests covering active-only filtering, fallback task/progress text, and line truncation.
- Replaced global search query mutation logic with a dedicated `Input` instance so typing now supports cursor movement, word deletion, and other editor hotkeys.
- Updated search banner rendering to display the embedded input line with live cursor while preserving match-count formatting and prompt width handling.
- Extended `Input` with a configurable prompt and end-of-value cursor placement, then updated memory-search tests for the new hotkey-driven editor behavior.
- Added fuzzy search preprocessing to normalize case, camelCase, and punctuation.
- Added token and phrase scoring for exact, prefix, substring, acronym, and compact hits.
- Added fuzzyRank to return {item, score}-ranked matches and delegated fuzzyFilter to it.
- Updated settings search tabs to sort by best score, keep original-order ties, and mute unmatched tabs.
- Detached async task progress rows stopped running a redraw driver and task progress rendering switched running/pending rows to static task-icon text.
- Background task snapshots were frozen once blocks left the transcript live region, preventing later partial snapshots from repainting commit-eligible rows.
- Updated task-progress and detached-background-task tests to validate static task rows and the new freeze behavior.
- Extracted `limitMatchesActiveAccount`/`reportMatchesActiveAccount` into `slash-commands/helpers/active-oauth-account.ts` as the single definition of the report-to-account matching rules, including projectId matching against `limit.scope.projectId`/metadata.
- Dropped the duplicated `ActiveAccountIdentity`/`OAuthAccessResolver` shims, `as unknown` session casts, the dead `getOAuthAccountId` fallback, and the email-vs-scope-accountId comparison from `command-controller.ts` and `usage-report.ts`.
- Replaced the async per-provider `resolveActiveAccountsForReports` map with one synchronous typed `authStorage.getOAuthAccountIdentity()` call per render, gated to the session's current provider.
- Re-exported `OAuthAccountIdentity` from `session/auth-storage.ts` and added `active-oauth-account.test.ts` covering the matching rules.
- Ensured flattened chain rows under a `└─` branch are anchored by a vertical line one level right of the suppressed gutter (below the branch head's content), never in the `└─` corner column itself, resolving visual issues #2298 and #2325.
Fixes#2325.
- Stored queued steering/follow-up attachments in `QueuedDisplayEntry` so restore APIs retain image data.
- Changed `AgentSession.clearQueue` and `popLastQueuedMessage` to return `{ text, images }` payloads.
- Restored queued text and images into editor image buffers when steer submission fails or queue items are restored.
- Added optional `hasSteeringMessages` config hook and limited steering checks to boundaries.
- Fixed interrupted tool-batch steering by keeping queued messages until boundary handling.
- Added idle text and image submissions to steer queueing when no input waiter exists.
- Auto-continued resumable sessions after queued steering and preserved submit metadata.
- Added a `personality` enum to `settings-schema.ts` and new `Personality` type alias.
- Replaced inline reply guidelines with a templated `<personality>` block in `system-prompt.md`.
- Added markdown personality specs and wired them into `system-prompt.ts` rendering.
- Updated `sdk.ts` and `selector-controller.ts` to apply personality changes and refresh prompts.
- Set sub-agent sessions to use `personality: none` to suppress personality rendering.
- Added `SettingsList` section-focus state with `sectionFocused`, `hasSectionFocusTargets`, and `toggleSectionFocus()`.
- Implemented section-heading navigation with Tab/Shift+Tab, Up/Down focus jumps, and Enter/Escape exits.
- Updated `/settings` input hints and fallback routing to tab-bar keys when section focus is unavailable.
- Added tests for section-focus navigation, mouse parsing, and tab-bar behavior coverage.
- Added mouse hover, wheel, and click routing for `/settings` rows and tabs.
- Changed `/settings` to open as a fullscreen alternate-screen overlay.
- Added hover, hit-testing, and wheel APIs across TabBar, SelectList, and SettingsList.
- Added SGR mouse parsing plus `routeMouse` dispatch and exported it from the `tui` entrypoint.
- Fixed `/dump` output (`session-dump-format.ts`) and the RPC `get_state` `dumpTools` payload (`rpc-mode.ts`) serializing Zod schema instances — leaking `def`/`shape` internals and stringified methods — by converting parameters through `zodToWireSchema` like providers receive.
- Fixed context-usage token estimation stringifying the Zod `def` tree, which overcounted tool schema tokens in the status line.
- Fixed tool-discovery indexing (`tool-index.ts`) returning empty `schemaKeys` for Zod tools, weakening BM25 ranking; keys are now recovered via wire conversion.
- Fixed the extension inspector panel rendering "(no arguments)" for Zod tools by reading properties off the converted wire schema.
- Added coverage in `tool-index.test.ts` plus new `context-usage.test.ts` and `session-dump-format.test.ts`, and a changelog entry.
- Added a `SettingsSearchHeader` banner to `SettingsSelectorComponent`, permanently mounted under the top border and rendering only while a cross-tab search is active.
- Typing now filters settings across every tab via `getSettingItemFilterText` + `fuzzyFilter`, with per-tab first-match ids so Tab jumps between tabs that have matches; non-matching tabs render muted and the pre-search tab is restored on exit.
- Moved the tab bar below the tab content, disabled `SettingsList`'s own type-to-search in favor of the selector-owned global search, and only advertised PgUp/PgDn in the hint when multiple sections exist.
- Wired the new `mutedTab` style into `getTabBarTheme` in `modes/shared.ts`.
Also normalizes setting labels/descriptions and carries the package changelog entries for this batch (adjacent unreleased bullets are not splittable per commit), restoring section placement disturbed by the two prior changelog hunks.
- Caught and logged npm `PluginManager.list()` rejections in `PluginSettingsComponent`, returning an empty plugin list so the settings tab no longer stays blank when plugin listing fails.
- Added tests covering Escape handling while lists are loading and marketplace rendering when npm listing rejects.
- Added `responsesLite`, `reasoningContext`, `clientMetadata`, and `onModerationMetadata` options.
- Changed Lite request transformation to default `reasoning.context` to `all_turns`.
- Changed request shaping to strip image `detail` fields and force `parallel_tool_calls` off in Lite mode.
- Fixed streaming behavior by excluding `client_metadata` from websocket append diffs and swallowing moderation metadata errors.
Removed the dead settings selector submenu guard so Escape reaches the active settings or plugins child component. Added a regression test for closing an open settings submenu before the parent selector.
Fixes#2331