- setCwd now updates the saved __omp_session__ stack entry so a deferred
cross-runtime setCwd is visible to the runtime's next run (review should-fix)
- JsRuntime installation asserts realm ownership before mutating globals;
a first init during another runtime's live run fails via init-failed
instead of clobbering the active run's globals
- cmux runCmuxCode marks the armed cancel rejection as handled so a sync
setup throw under an already-aborted signal cannot become an unhandled
rejection (review P2)
- credited #4907 in the changelog entry
- Detected npm-owned global bin paths and Windows npm launcher shims before falling back to binary replacement.
- Added npm install argv construction that pins the registry and native package versions.
- Covered npm shim resolution and npm update arguments in update-cli tests.
Fixes#5053
The token-usage row shown under assistant messages (display.showTokenUsage) now leads with the turn's local wall-clock time down to the second (YYYY-MM-DD HH:mm:ss), sourced from the assistant message's persisted timestamp so live, rebuilt, and restored transcripts all show the turn time rather than the view time.
createUsageRowBlock takes timestamp as an optional trailing argument, preserving its (usage, durationMs, ttftMs) public call contract on the package's ./modes/components/* export surface.
- Added a CLI usage-error type for argument validation failures.
- Reported invalid --max-time values from launch and ACP as clean usage errors with exit code 2.
- Covered the no-stack-trace CLI error path for invalid max-time input.
Fixes#5041
- Treated startup scoped model selection as a prompt-cache shape override before inheriting fork cache keys.
- Covered the --models fork path so a scoped startup model cannot reuse the parent prompt_cache_key.
Fixes#5035
Separated advisor provider session identity from local advisor labels so Codex requests carry stable UUIDv7 values while transcripts keep their advisor-specific names.
Fixes#5040
- Persisted an inherited provider prompt-cache key on full session forks while keeping the child OMP session id independent.
- Added --prompt-cache-key and SDK startup inheritance so explicit cache affinity is separate from provider session routing.
- Cleared automatic inherited keys when model, thinking, system prompt, or tool schema inputs change.
Fixes#5035
- Parsed --max-time values with s, m, and h suffixes into seconds instead of dropping the deadline.
- Raised a visible parse error for invalid or non-positive max-time values.
- Updated help text and regression coverage for the CLI timeout parser.
Fixes#5041
Detected go.work before go.mod for workspace diagnostics and expanded go build package patterns from go.work use entries.
Added regression coverage for go.work-only roots and mixed go.work/go.mod workspaces.
Fixes#5038
Two review findings on the blocked-todo support:
- A blocker `reason` with an embedded newline corrupted the Markdown
round-trip: `phasesToMarkdown` writes the note as a trailing HTML comment
on one checklist line, so a newline split it across two lines — the first
an unclosed `<!-- blocker: …`, the second an unrecognized-syntax error —
losing the reason on `/todo edit` and export/import. Normalize the reason
to a single line (collapse whitespace runs) at the `block` op source, so
the round-trip, HUD, and summary consumers all stay one-line-safe.
- The todo prompt now directs the agent to `block` a task waiting on
another agent, but `#reconcileTodosWithSubagents` only auto-completed
pending/in_progress todos. A todo blocked on a detached subagent would
stay blocked after that subagent completed, and since blocked todos are
excluded from the stop reminder it stranded silently. Include `blocked`
in the reconciliation (a matching subagent completing is the unblock
signal) and drop the now-stale blocker note when completing.
Both paths are revert-proven by new regression tests.
Co-Authored-By: seal <noreply@sealedsecurity.com>
Two gaps a whole-repo review surfaced in the blocked-status support:
- Re-blocking could not refine a blocker note. The block guard skipped any
task not pending/in_progress, so `block task reason:"..."` on an
already-blocked task (the common case: block first, learn the reason
after) was silently dropped. Allow an already-blocked task to be
re-blocked so its note updates, while still refusing to reopen
completed/abandoned tasks.
- The blocker reason was lost across markdown round-trips. `phasesToMarkdown`
emitted only the `[!]` marker and `markdownToPhases` parsed only
content+status, so `/todo edit` or export/import dropped the reason.
Serialize it as a trailing `<!-- blocker: ... -->` HTML comment (invisible
in rendered markdown, unambiguous to parse back) and recover it on parse.
Also adds the missing `## [Unreleased]` CHANGELOG entry for the user-facing
block/unblock ops and blocked status.
Regression tests (revert-proven): re-blocking refines the note; the reason
survives a full markdown round-trip (the pre-existing round-trip test only
asserted status, not the reason). Both fail without the fix.
Co-Authored-By: seal <noreply@sealedsecurity.com>
The throttled jj branch/status caches guarded in-flight results only by
root equality (`#jjRoot === root`). When a HEAD or bookmark move fires the
git watcher's `invalidate()` while a query for the *same* root is still in
flight, `#invalidateGitCaches()` resets `#jjRoot` but the next render
re-resolves it to the identical root string — so the root-only guard
accepts the pre-invalidation result, caches a superseded bookmark/status,
and advances the 5s throttle on it. The stale label then persists for a
full TTL after the move.
Replace the root-equality guard with a generation token bumped on every
cache reset (cwd switch in `#jjRootFor` and HEAD/bookmark move in
`#invalidateGitCaches`). Each query captures the generation at launch and,
on resolve, drops its result and refuses to advance the throttle if the
generation changed. This subsumes the old root check (a root change always
resets, bumping the generation) and additionally catches the same-root
case it structurally could not.
Regression test (revert-proven): a same-root invalidation mid-flight
renders the stale label without the fix, is dropped with it.
Co-Authored-By: seal <noreply@sealedsecurity.com>
Added an explicit timeout presentation capability so interactive queued dialogs defer the fallback while older UI implementations still get an immediate tool-owned timeout.
Refs #4995
Whole-repo `biome check .` (CI `check:tools`) failed on the jj-cache
test with two diagnostics that a changed-files-only local check missed:
- assist/source/organizeImports (error): the named imports in
`import { settings, Settings }` were unsorted. Fixed via biome's safe
autofix -> `{ Settings, settings }`.
- suppressions/unused (warning): a `biome-ignore
noControlCharactersInRegex` sat on the `visible()` helper, but biome
does not flag the `\xNN` escape-sequence form used there, so the rule
never fired and the suppression had no effect. Removed it per biome's
own instruction; the regex is unchanged.
No behavioral change: the jj-cache test still passes (2/2).
Co-Authored-By: seal <noreply@sealedsecurity.com>
Prevented explicit bash timeouts from also aborting the AbortSignal passed to pi-natives while streamed output is still draining. Native timeout_ms now owns cancellation, and the JavaScript timer only reports the fallback timeout result.
Added regression coverage for streamed output before an explicit timeout.
Fixes#5021
- Marked terminal yield state in the synchronous tool-result hook before aborting the loop.
- Ignored the later tool_execution_end event for synchronously terminated yield calls so stale events cannot suppress the next prompt.
Fixes#4963
The run-state `working` spinner arms a periodic setInterval that re-emits
the terminal title as an OSC-0 write each tick. shutdown() restored the
shell title via popTerminalTitle() but never stopped the interval, so a
pending tick could fire after the restore and leave the parent shell tab
reading a stale spinner title post-exit. Wire the existing
disposeTerminalTitleState() into shutdown() before popTerminalTitle().
Co-Authored-By: seal <noreply@sealedsecurity.com>
Applied the timeout auto-selection before multi-question single-choice prompts auto-advance, and replaced pending test promises with Promise.withResolvers().
Refs #4995
Reset the run-state title to idle when focusing an idle session (was inheriting the previous session's stuck spinner); drive the title to attention while a tool blocks on an approval prompt (not just ask), returning to working at its end; let an extension setTitle() own the terminal verbatim so neither the run-state prefix nor the spinner tick clobbers it, cleared when the app sets an authoritative session title; use NodeJS.Timeout for the spinner timer field.
The terminal title (OSC 0) now carries a run-state prefix: an animated spinner while the agent is working and a steady dot when idle, so a backgrounded tab/pane shows which session is busy vs done. `setTerminalTitleState` also exposes an `attention` ([!]) state for callers; rendering is gated by `tui.titleState` (default on), dedups writes, and is TTY-guarded.
Refs can1357/oh-my-pi#3587
Keep assistant yield tool calls pending until YieldTool.execute returns a successful tool result.
Prevent invalid pre-execution yield arguments from bypassing schema retry handling while still suppressing the soft budget abort during validation.
Fixes#5006
- Deferred eval cancellation while Python bridge calls are paused so already-started agent() subagents can finish and persist output.
- Rejected new Python bridge calls after an external abort is pending to prevent post-abort fan-out waves.
- Added regression coverage for the bridge shield and Python parallel agent() interruption path.
Fixes#5005
Interactive sessions defer MCP discovery, so CLI --tools produced an initial built-in-only active set and later MCP refreshes respected that filtered set.
Force-activate deferred MCP tools when MCP discovery mode is disabled, matching the blocking startup path while leaving discovery-mode selection intact.
Fixes#5013
Persist yield tool-call arguments as soon as an assistant turn commits the yield call, before the soft request budget guard can abort the session.
Add a regression covering a yielding turn that crosses the budget threshold without a tool result event.
Fixes#5006
Reset the ask tool fallback timeout whenever the interactive selector resets its UI countdown, preventing late keypresses from falling back to the original recommended option.
Refs #4995
Ensured ask tool timeouts abort stalled UI selectors and return the recommended option instead of hanging. Added regression coverage for selectors that never settle.
Fixes#4995
Switched interactive OAuth login to start model discovery in the background after credentials are saved.
Added a regression test that keeps model refresh pending and asserts the success transcript appears immediately.
Fixes#4989
Left Darwin stdio MCP server launches in the inherited session so macOS TCC can prompt for Apple Events permissions used by xcrun mcpbridge.
Added resolver coverage for Darwin while preserving Linux detach and Windows console behavior.
Fixes#4987
Avoided reattaching snapcompact archive image blocks when rebuilding collapsed transcript contexts so live TUI resumes do not retain archived frames.
Added regression coverage for collapsed transcripts while preserving full transcript and provider context frame reattachment.
Fixes#4979