Separated the fork prompt result into accepted, declined, and unavailable states.
Interactive declines now return cleanly through runRootCommand, while non-TTY
invocations continue to fail with a diagnostic instead of silently exiting 0.
Updated regression coverage for both branches.
Fixes#1668
createSessionManager threw `Session "X" is in another project (Y).` when
the user answered "n" to the fork prompt, and runRootCommand never caught
it. The throw bubbled up as an Uncaught Exception with a stack trace.
Return undefined from the decline branch instead, and treat
`typeof parsed.resume === "string" && !sessionManager` in runRootCommand
as a user cancellation: print a dimmed "Resume cancelled" message and
return cleanly (exit 0), mirroring how the picker UI handles
"No session selected".
Fixes#1668
- Replaced `Bun.sleep(50)` with `Promise.withResolvers` resolved on first chunk to avoid races.
- Used a filesystem marker file to detect shell startup before aborting in persistent-session test.
- Prevents flaky failures where aborts arrived before shell setup completed.
- 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.
When the autocomplete popup is visible, ESC unconditionally falls through
to the editor base class so it can dismiss the popup. Only an ESC with no
popup visible reaches onEscape and routes to the global interrupt handler.
Removed the shouldBypassAutocompleteOnEscape callback that paved over the
popup-dismissal path whenever the agent was busy (streaming, bash, /btw,
auto-compaction, etc.) — that is precisely the moment the user is most
likely to hit ESC while the popup is open, and dismissing-then-aborting in
one keystroke is a footgun, not a feature. Two-press semantics now match
the standard TUI/IDE pattern: first ESC closes the popup, second ESC
aborts.
Tests cover both branches in custom-editor-keybindings.test.ts and the
input-controller escape suite no longer asserts the dead callback.
Fixes#1655
CombinedAutocompleteProvider.#getFuzzyFileSuggestions sliced fuzzy
matches to 20 entries unconditionally, regardless of how many files
matched. fuzzyFind itself is already capped via maxResults: 100 in
buildAutocompleteFuzzyDiscoveryProfile, so the inner slice was a
redundant truncation that silently hid correct matches in monorepos
or whenever the typed stem (e.g. @controller, @test) matched many
files. Dropping the slice lets the natural upstream ceiling apply,
matching the uncapped behavior of the direct-prefix path
(#getFileSuggestions).
Fixes#1652
- 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.
Fixed the Claude Code slash command discovery to load subdirectory commands recursively and added namespace aliases for colon-namespaced workflows. Updated the timeout behavior for the eval tool to better handle cell execution without premature termination.
- 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
- Tool execution now renders every 16ms and advances spinner glyphs only every 80ms using a tracked last-advance timestamp.
- Output block shimmer ticks were reduced to 16ms so border-frame updates align with the 60fps cadence for smoother animation.
- Added an early `viewportRepaint` path when `nativeViewportAtBottom` is unavailable and `newLines.length <= height`.
- Marked native scrollback dirty before returning that repaint so cleanup is deferred to the next checkpoint.
- Kept the `historyRebuild` fallback for shrinks beyond the padded viewport top to avoid unnecessary repainting.
- Introduced helper `createEmptyWorkspaceTree` to reduce duplication.
- Populated missing `workspaceTree` field in test contexts for `buildSystemPrompt`.
- Added `TokenTaskBudget` type and `taskBudget` option to `StreamOptions`.
- Forwarded `taskBudget` as `output_config.task_budget` with the `task-budgets-2026-03-13` beta header.
- Fixed `disableThinkingIfToolChoiceForced` to preserve `task_budget` when clearing `effort`.
- Accepted `output_config.task_budget` from Anthropic gateway requests.
When omp runs under Windows Terminal on native Windows, ConPTY routes the
console through a pseudo-console whose GetConsoleScreenBufferInfo answer
is always pinned to the buffer tail; it does not reflect the user's
scroll position in the WT pane. The renderer's planRender used that
answer to authorize the shrink-across-viewport historyRebuild intent,
emitting the destructive \x1b[2J\x1b[H\x1b[3J on every full redraw and
yanking a scrolled-up reader to the top of WT's scrollback.
ProcessTerminal.isNativeViewportAtBottom now returns undefined whenever
WT_SESSION is set, matching the POSIX fallback. The renderer's existing
unknown-viewport deferral keeps streaming-time mutations non-destructive
(viewportRepaint / deferredShrink) and reconciles native history at the
next prompt-submit checkpoint via refreshNativeScrollbackIfDirty({
allowUnknownViewport: true }), where the user is provably at the bottom.
The probe gate is factored into a pure shouldTrustNativeViewportProbe
helper so the contract is unit-testable without spying on process state.
Fixes#1635
- 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
The Anthropic OAuth login requested an outdated scope set (`org:create_api_key user:profile user:inference`). Recent Claude Code versions request `user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload`, so omp's consent screen omitted the Claude Code session, connector (MCP), and file-upload grants the current client carries.
omp uses the OAuth access token (sk-ant-oat...) directly for inference and never mints an API key, so `org:create_api_key` was unused. Drop it and align with the current Claude Code scope set.