- Make over-context models selectable in the model picker by graying them instead of disabling them.
- Trigger automatic session compaction with the current model prior to switching when an over-context model is chosen.
The TUI's CommandController special-cased backend.id === "off" for
/memory stats|diagnose, but the ACP/RPC slash-command handler in
builtin-registry.ts still fell back to the generic "not available for
the off backend" template — non-TUI users with memory.backend=off saw
the self-contradictory wording this PR was meant to remove.
Extract the shared fallback into memoryStatsUnavailableMessage()
(memory-backend/messages.ts) and use it from both CommandController
and the ACP builtin-registry handler, so the two surfaces can't drift
again.
Addresses review comment:
https://github.com/can1357/oh-my-pi/pull/7251#discussion_r3695383090
/memory stats and /memory diagnose fall back to a generic
'Memory <action> is not available for the <backend.id> backend.'
message whenever the active backend's stats/diagnose hook is
undefined. For every real backend (hindsight, mnemopi, local) this
reads fine, but the off backend isn't a backend a user picked among
several stats-capable options - it's the no-op state memory falls
back to by default - so the same template renders as 'Memory stats
is not available for the off backend.', which reads as an odd,
almost self-contradictory warning.
Special-case backend.id === "off" with wording that matches the
phrasing offBackend.status() already uses elsewhere ('Memory backend
is off.'), and add a unit test covering both the off-backend wording
and the unchanged generic fallback for a real backend (local) that
simply has no stats hook.
The regression test only asserts on a mocked showWarning call and
never renders Markdown, so it doesn't need a real theme instance;
drop the global dark-theme setup/teardown to avoid leaving the
process-wide theme singleton mutated for later suites in the same
Bun process.
The Agent Hub kill path called AgentLifecycleManager.release(), which
disposes the session and then unregisters the ref while leaving the
on-disk <id>.jsonl intact. On the next hub open, registerPersistedSubagents
rescans the transcript tree and its `if (!registry.get(id))` guard cannot
distinguish an explicit kill from a normally-parked agent, so it re-adopts
the killed id as a fresh `parked` row.
Add a `tombstone` option to release() that mirrors finalizeSubagentLifecycle's
genuine-kill path: dispose and detach the session but keep the ref registered
as terminal `aborted` instead of removing it. The kept-registered id makes the
rescan guard skip it, and the transcript stays on disk (still reachable via
history://<id>, per #5261). The hub kill button now passes tombstone: true.
Fixes#7250
The live AskDialog trusted question.question while its render helpers
(replaceTabs, renderQuestionTitle, questionTabLabel) assume a string. A
question reaching AskDialogComponent without a string question field threw
an uncaught TypeError that escaped the TUI render loop and killed the
session. The transcript renderer already normalizes the same malformed
data via normalizeRenderQuestions; the live path did not.
Normalize the questions array at dialog entry (new normalizeDialogQuestions),
coercing question/id/label to strings and options to a well-formed array,
matching the transcript path.
Fixes#7211
Track entry into tool.execute separately from tool event emission. Never-started skips retain SyntheticToolResultDetails with executed:false; in-flight aborts now use distinct interrupted metadata with execution:started so consumers do not assume no partial work occurred.
Keep both interrupt states neutral in the TUI and cover the agent metadata boundary plus rendering behavior.
Fixes#7199
A tool call aborted mid-batch to service queued steering/peer input emits a synthetic placeholder result with isError:true so the model retries it. The TUI keyed all error styling (red ✘, red frame/text) off that flag, so a normal steering skip rendered identically to a real tool failure.
Mark the skip placeholder with the existing SyntheticToolResultDetails discriminator (source: "interrupt_skipped", executed:false) and render benign skips through the neutral generic card (info glyph, dim text, neutral background), bypassing any bespoke error frame. Genuine failures keep their error styling.
Fixes#7199
MCPManager.disconnectAll clears connections without notifying the session's
prompt-command consumer, so removed or disabled prompt servers left stale
/server:prompt commands after /reload-plugins and /mcp reload.
Clear the session MCP prompt-command registry immediately after disconnect and
before asynchronous rediscovery. Newly loaded prompts repopulate it through
the existing manager callback. Extend the reload regression coverage.
Fixes#7189
reloadServers() rediscovered MCP with no options, so loadAllMCPConfigs
defaulted enableProjectConfig to true — /reload-plugins (and /mcp reload)
could start project .mcp.json servers a user opted out of.
Derive discovery filters (enableProjectConfig, filterExa, filterBrowser)
from ctx.settings before reconnecting, matching startup discovery. Added a
regression test asserting the opt-out is forwarded.
Fixes#7189
/reload-plugins documents MCP in its reload scope but the TUI handler only
reset skill/command/capability caches and never reconnected MCP servers or
refreshed the session MCP tool registry, so .mcp.json edits stayed inactive
until process restart.
Route the TUI reload pipeline through a shared reloadTuiPluginState() helper
that also runs the disconnect/rediscover/refreshMCPTools path used by
/mcp reload, exposed as MCPCommandController.reloadServers().
Fixes#7189
Moved automatic title eligibility and persistence into AgentSession so editor and CLI bootstrap submissions share one path.
Added a PTY regression probe covering the positional-message launch flow.
Fixes#7166
- Centralized PNG conversion behind an async boundary so constructor and encoder throws become promise rejections.
- Kept live and restored Kitty image rendering interactive by omitting failed conversions.
- Added regressions for both tool-result render paths.
Fixes#7160
macOS Terminal.app consumes Option for character composition, so Alt+Up
never reaches the app and the dequeue is unreachable there. Bind Shift+Up
alongside it -- Shift is not intercepted, and the key was unbound in the
input path.
The three overlay handlers that already use shift+up for fast scroll
(scroll-view, model-hub, log-viewer) match keys directly rather than
through the manager, so they never see this binding.
Both default tables move together: the registry in config/keybindings.ts
and DEFAULT_ACTION_KEYS in custom-editor.ts, which silently shadows the
registry when they disagree.
- Wrap status line path segment labels and worktree names in file hyperlinks.
- Apply hyperlink generation using the project directory and rendered path text.
- Add the `app.live.toggle` keybinding defaulted to `Ctrl+L` to start or stop live voice mode.
- Remap the default display-reset action (`app.display.reset`) from `Ctrl+L` to `Alt+L`.
- Update the live visualizer to listen for stop keys so the toggle chord terminates active sessions.
Address Codex review on #6881. Retraction of never-run tool cards no longer runs eagerly at message_end: only a TTSR rewind (known via isTtsrAbortPending) retracts there. A terminal error/abort lets agent-loop's synthetic tool_execution_end settle each card in place so the failure stays visible, and an auto-retry removes those synthetic-settled cards only when auto_retry_start actually supersedes the turn.
Also settle a held server-resolved (Cursor/todo) completion after a mid-stream tool-call id re-key, so the migrated card is not stranded pending.
Fixes#6879
editor's prefill is the actual document being edited, not a placeholder
like input's — the interactive (hook-editor.ts) and RPC implementations
set it verbatim on any truthy value. Trimming before the presence check
silently dropped whitespace/blank-line prefill content from the ACP
elicitation schema, so a client-side form opened empty and accepting it
could not reproduce the extension's supplied indentation.
Now only a genuinely empty string omits `default`; any other prefill,
including whitespace-only, passes through unchanged.
The factory-level doc comment still listed editor among the non-elicitation
surface that 'remains stubbed', contradicting the elicitation bridge added
in ec3144860. Reflows the sentence without changing its meaning otherwise.
createAcpExtensionUiContext stubbed editor as a hardcoded no-op
(async () => undefined), so free-text elicitation requests from
/review's custom-instructions branch and the ask tool's custom-input
path never reached the client and silently resolved to undefined.
Wire editor through the existing elicitFromAcpClient bridge used by
select/confirm/input, using a {type: "string"} schema with default
set to the prefill text when non-blank.
Verified against a real stdio JSON-RPC transport via acp-probe: the
elicitation/create request now fires with the expected schema and
round-trips the accepted value back to the prompt without hanging.
Adds matching unit test coverage in acp-agent.test.ts mirroring the
existing select/confirm/input bridge tests (prefill->default mapping,
whitespace-prefill omits default, decline/cancel->undefined, no-form
fallback).
- Implemented clipboard register management, parsing, and execution rules for CUT, COPY, and PASTE operations in the hashline engine.
- Added session-persistent clipboard state and integration across agent session execution, diff previews, and streaming tools.
- Added comprehensive validation, error messages, recovery handling, and test coverage for clipboard and block operations.
- Updated task tool execution to pin live regions and drop partial snapshots once rows commit.
- Tracked background task frozen styled rows and render timestamps to prevent clock drift on committed history.
- Added tests verifying detached and blocking task progress do not duplicate rows in scrollback.