In /vibe mode the director is often idle while workers stream, so the
status-line tok/s badge showed a stale/zero rate even while parallel
workers were actively generating tokens. The badge now aggregates the
main session's live tok/s with every live vibe worker's tok/s, and
falls back to the main session's own cached rate when no workers are
streaming.
- Extract calculateTokensPerSecond to utils/token-rate.ts (neutral
location) so vibe/runtime.ts can depend on it without the render
layer depending on the heavy vibe/task graph.
- Add aggregateVibeWorkerTokensPerSecond to vibe/runtime.ts: sums
each live worker's rate via the shared calculator, returns null
when no workers are streaming so the main rate shines through.
- StatusLineComponent takes the aggregator via an injected
setVibeWorkerTokenRateProvider callback (wired in interactive-mode)
keeping the render layer off the vibe/task dependency graph.
- #getTokensPerSecond splits into #getMainSessionTokensPerSecond
(preserves the sticky per-assistant-message cache) plus the
worker-aggregation path, so the director-idle case no longer
short-circuits to null.
Installed the normal plan proposal handler in print mode, persisted the resolved plan artifact, and silently stopped the completed planning turn for later review.
Shared plan proposal validation with interactive mode and added regression coverage.
Fixes#6017
Kept full-root rendering as the default after input and introduced an explicit host opt-in for stable-focus subtree repainting. The coding-agent default composer opts in, while extension-provided editors and other TUI consumers retain callback-safe full composition.
Bounded aborted post-prompt drains and ran independent subsystem cleanup under one barrier while preserving writers-before-close ordering.
Kept long interactive shutdowns visible with a delayed status refresh.
Fixes#5932
The first pass anchored a slice on the active task, which still showed completed rows, kept the active item mid-window, and gave the two views divergent selection logic. Per reviewer, replace it with one shared policy both collapsed views run.
selectCollapsedTodos (todo.ts) omits completed/abandoned, pulls every active task (in_progress or subagent-matched pending) to the head in todo order, fills remaining rows with following pending tasks, and emits '… N more active todos' when active work alone exceeds the cap; it falls back to closed tasks for a settled phase so HUD persistence still renders. renderTreeList gains a trailingSummary primitive so item selection lives in the todo domain. The transient tool result reaches live subagent matches via setActiveTodoDescriptionsProvider, wired from interactive mode's observer registry, so both views share the active set.
Fixes#5873
Both collapsed todo renderers took fixed edge slices: the tool result kept the tail eight (truncateFrom start) and the HUD kept the head five (base.slice), so a mid-phase in_progress task fell in the omitted middle of both.
Add an anchorIndex option to renderTreeList that slides the collapsed window over the anchored item with two-sided '… N more' summaries, and anchor both call sites on the in_progress task (HUD falls back to the first subagent-matched pending task).
Fixes#5873
Resolved plan-mode exit overlap with #5662 (kept restore/rollback
structure, routed pending-switch clearing through
clearPendingPlanModelSwitch) and unioned additive test blocks with
#5672/#5662.
Decoupled fullscreen alternate-screen rendering from terminal mouse capture.
Disabled pointer tracking for Plan Review so terminals retain native selection.
Fixes#5711
Moved #hidePlanReview from after the model restore to immediately before the synthetic execution dispatch, past the awaited sessionManager.setSessionName. Hiding earlier restored editor focus while the async title write was in flight, so operator keystrokes could submit a normal turn ahead of the approved execution turn and reorder it.
Fixes#5688
The stale-buffer flicker fix (68f84d7c20, #5319) moved #hidePlanReview out of the picker's synchronous finish() into closePlanReview(), reached only after #approvePlan returns. #approvePlan awaits session.prompt of the synthetic plan-approved turn, which blocks for the whole run, so the fullscreen plan-review overlay stayed mounted while work proceeded underneath.
Hide the overlay inside #approvePlan after the async transcript rebuild (exitPlanMode/compaction, tool and model restore) completes but before the blocking dispatch. #hidePlanReview is idempotent, so the caller's trailing closePlanReview() stays a safe no-op, and #5319's stale-buffer guard is preserved.
Fixes#5688
In plan mode the active session model is the plan-role model, but
reassigning that role through the model hub only wrote settings and
never moved the live session onto the new model — planning continued on
the model plan mode was entered with until the next entry.
Subscribe InteractiveMode to onModelRolesChanged and, while plan mode is
active, re-resolve the plan role and switch onto it (deferring to the
next turn boundary when a turn is streaming). Extract the transition
decision into a pure resolvePlanModelTransition() helper with tests.
Fixes#5657
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
- Restored the compact two-row `Editor` layout by default and gated the dedicated IME-safe bottom border behind `setImeSafeCursorLayout()`.
- Added `tui.imeSafeCursor` as an opt-in appearance setting and applied it to initial and replacement editors.
- Added regression coverage for compact default rendering while retaining terminal-local IME preedit protection.
- Updated the TUI changelog for the opt-in compatibility layout.
- Minted the guided-goal Codex side session id once per interview in handleGuidedGoalCommand and threaded it through every turn via GuidedGoalTurnOptions.sideSessionId, so a multi-question interview shares a single websocket-only Codex socket instead of opening a fresh one each turn (which could trip websocket_connection_limit_reached and fall back to the rejected SSE path).
- Exported newGuidedGoalSessionId; runGuidedGoalTurn mints its own id only when no side session id is supplied (one-shot callers, tests).
- Added regression coverage asserting the supplied side session id is reused across turns.
Fixes#5304
The empty-editor left-left gesture opens the Agent Hub whenever persisted
or parked subagents exist (intended since f3e372e7b), but the hub's own
close detector starts fresh at 0 with no handoff from the editor's
double-tap detector. The two taps that opened the hub were consumed by the
editor, so a single subsequent left did nothing and the user had to press
left-left again to escape while input and hotkeys stayed disabled.
Thread an armCloseTap option from the gesture through showAgentHub to the
new AgentHubOverlayComponent.armCloseTap(), which seeds the table's
#lastLeftTap so one more left (within the tap window) dismisses the hub.
Fixes#4780
- Added `tui.scrollbackRebuild` configuration with interactive startup/controller wiring to apply `setScrollbackRebuild`.
- Exposed prewalk session state in `SegmentContext` and rendered a dedicated prewalk segment/icon in the status line.
- Added divergence-aware TUI full-paint logic that enables scrollback erase-and-replay rebuilds for non-multiplexer divergence cases.
- Updated rendering and streaming tests to verify rebuild behavior (`3J`) and eliminate stale marker expectations under drift scenarios.
- Introduced conditional scrollback clearing during UI renders when transcript compaction is enabled.
- Updated `CommandController` and `EventController` to respect the `display.collapseCompacted` setting.
- Configured `SelectorController` to trigger a chat rebuild and UI reset when the compaction setting changes.
- Updated `InteractiveMode` to dynamically toggle between collapsed and full inline history based on user settings.
- Implemented `/queue` command and `->`/`=>` shorthands to support deferred, sequential message processing.
- Added a robust parsing utility to handle various list-based queue inputs and automate yield management.
- Integrated visual decorations and state tracking to provide real-time feedback on queueing status.
- Enabled non-cursor line text decoration in the TUI to support dynamic queue header rendering and list numbering.