Keep chat notifications emitted during session_start visible after the initial transcript render rebuilds the chat container. Add regression coverage for preserving startup notifications during initial render.
Fixes#1316
When session.prompt() returns, idle-flush tasks for async-job result
deliveries are scheduled via #schedulePostPromptTask (1ms delay) and
added to #postPromptTasks immediately. The 800ms loop timer could fire
in that window before isStreaming became true, causing the loop to
submit the next prompt while the delivery turn was still pending. The
delivery then hit AgentBusyError and the job result was silently dropped.
Add AgentSession.hasPostPromptWork (= #postPromptTasks.size > 0) and
include it in #isLoopAutoSubmitBlocked() alongside isStreaming and
isCompacting. Add a regression test that verifies the loop defers when
hasPostPromptWork is true and fires once it becomes false.
Fixes#1294
Allowed /goal set to replace the current active goal instead of rejecting and discarding the command input.
Added goal runtime and interactive-mode regression coverage for active replacements.
Fixes#1293
- Added a shared `interruptHint()` utility in the modes shared module to generate the interrupt suffix with themed bracket glyphs.
- Replaced hardcoded working-message interrupt text in interactive and event controllers with calls to `interruptHint()`.
- Updated working-message rendering to recognize and strip the new themed hint when applying shimmer styling.
- Updated interactive mode to render the loader spinner with the current working message accent when available.
- Added a fallback to theme accent and a reset color code when no working-message accent is provided.
- Loading message rendering now derived session-specific accent colors and applied them to shimmer output when a session name was available.
- Shimmer palettes were updated to accept raw ANSI color values as well as theme color names during compilation.
- A unit test was added to confirm shimmer text rendered with a supplied ANSI crest color.
- Added configurable shimmer palettes by introducing ShimmerPalette and ShimmerSegment types.
- Added a new shimmerSegments helper to render a single sweep across multiple text segments with optional per-segment palettes.
- Updated working-message rendering to style the interrupt hint using a separate borderAccent palette.
- Added a new shimmerText helper that computes a moving accent shimmer band across characters.
- Updated the interactive mode loader and slash-command ASCII bar renderer to use shimmer styling, with interrupt hints kept dim.
- Added tests for shimmer-enabled progress rendering and verified the visible bar output remains correct.
- get op now returns paused goals (was returning null when enabled=false)
- complete op now works on paused goals; previously required enabled=true
which always failed after an interrupt set enabled=false
- create op now allowed after previous goal status is 'complete'; was
incorrectly blocked by the same guard as 'dropped' check
- goal tool is re-added to the active tool set on session reload when a
paused/active goal is persisted to disk; sdk.ts:1599 excludes 'goal'
from initial active tools unconditionally, so restoreModeFromSession
now re-adds it and saves #goalModePreviousTools for later cleanup
- goal_updated event for 'dropped' status now triggers #exitGoalMode
before clearing goalModeEnabled, ensuring the previous tool set is
restored when the agent drops a goal via the tool
- added 'resume' and 'drop' ops to goal tool schema and execute path
- updated goal.md prompt to document new ops and the paused-goal workflow
Fixes#1249
- Added reusable loop auto-submit deferral and readiness helpers for loop mode.
- Updated loop iteration flow to defer next prompts while the session is streaming or compacting.
- Added tests verifying loop submissions wait until compaction/streaming completes before resolving.
Grammar-constrained models (e.g. Qwen3.6-35B-MTP via llama.cpp) emit
`extra: { title: {} }` instead of `extra: { title: "<string>" }` because
the resolve schema declares `extra` as Record<string, unknown> with an
open value schema, leaving the model free to drop in an empty object.
The apply guard then threw 'Plan approval requires extra: { title: ... }'
on every retry, looping the model indefinitely (issue #1179).
Plan approval now uses a layered title resolution:
1. `extra.title` if it is a non-empty string (and sanitizes to non-empty)
2. First `# Heading` in the plan content
3. Filename stem of `planFilePath` (`'/data/workspaces/can1357__oh-my-pi__1179/.omp-session/2026-05-19T03-59-21-254Z_019e3e63-62a6-7000-be63-371f2cd6d67d/local/PLAN.md'` → `PLAN`)
4. Literal `plan` as a final safety net
Each candidate is run through `normalizePlanTitle`; rejected ones fall
through. Extracted as `resolvePlanTitle` in plan-mode/approved-plan.ts
so it's unit-testable.
Prompt language relaxed from MUST to SHOULD for `extra.title` in
plan-mode-active.md and plan-mode-tool-decision-reminder.md, noting the
fallback so models don't waste turns on a now-optional field.
Fixes#1179
- Added `dev.autoqa.consent` setting and single-flight popup handler wired through `InteractiveMode`.
- Added `flushGrievances` to batch-POST unpushed rows to `dev.autoqaPush.endpoint` with cooldown and single-flight deduplication.
- Added `omp grievances push` subcommand with TTY progress bar for manual draining.
- Migrated shared DB logic to `openAutoQaDb` (with `pushed` column migration) exported from `report-tool-issue`.
- Relocated compaction, branch-summarization, pruning, and utils from coding-agent to packages/agent/src/compaction.
- Moved OpenAI remote compaction helpers from packages/ai to the new compaction module.
- Added handoff.ts with extractHandoffDocument, createHandoffContext, and renderHandoffPrompt helpers.
- Exposed new entries.ts with standalone SessionEntry types so coding-agent no longer owns them.
- Added GoalRuntime with wall-clock and token accounting, budget steering, and lifecycle operations (create, pause, resume, drop, complete).
- Exposed goal tool as a hidden agent tool, activated only when goal mode is enabled.
- Integrated goal continuation loop in InteractiveMode with auto-submit between turns.
- Added status line segment and theme icons for goal mode state.
- Removed ExitPlanModeTool and deleted exit-plan-mode docs/tests, dropping the old approval contract outputs.
- Replaced plan-mode approval flow from exit_plan_mode to resolve across session, SDK, controllers, and discovery.
- Added standing resolve handler accessors and updated resolve routing for queued or standing approval handlers.
- Added PlanApprovalDetails and enforced normalized, validated approval titles with readable plan-file requirements.
- Extended resolve schema and invocation signatures with optional extra metadata and reason trimming behavior updates.
- Updated plan and resolve prompts and changelog guidance to require resolve action, reason, and extra.title for apply/discard.
- Pinned final plan path before handleCompactCommand so queued messages use approved plan, not draft.
- Added regression coverage for setPlanReferencePath timing before compaction queue flush.
A fifth ExitPlanMode approval choice — sits between the existing
"Approve and execute" (purge session) and "Approve and keep context"
(full transcript). Runs `handleCompactCommand` against the plan-mode
transcript with a planning-specific custom instruction rendered from
`plan-mode-compact-instructions.md`, then dispatches the plan-approved
synthetic prompt so it lands as the first entry in the freshly-
summarized transcript — giving execution a fresh cache anchor with
the rationale carried over.
Cancel/fail contract:
- ok → bookkeeping runs, plan-approved synthetic prompt dispatched.
- cancelled → bookkeeping runs (tools restored, plan reference path
recorded), warning surfaced, dispatch skipped.
`markPlanReferenceSent` is intentionally deferred past
the cancel guard so `AgentSession.#buildPlanReferenceMessage`
re-injects the plan on the operator's next prompt() call.
If we marked it sent on cancel, the executor's first turn
would have no plan context.
- failed → bookkeeping runs, error already surfaced by executeCompaction,
dispatch proceeds best-effort. Approval intent stands.
Cancel vs. fail is discriminated via `instanceof CompactionCancelledError`
at the session/compaction error boundary (introduced in the previous
commit), so any abort source — operator Esc, extension hook, programmatic
abort — classifies uniformly without input-modality or message-string
coupling.
Op: extend
Introduce `CompactionCancelledError` and `CompactionOutcome` ("ok" |
"cancelled" | "failed") so callers can discriminate user-driven aborts
from generic failures via `instanceof`, instead of inspecting error
messages or `AbortError`-name strings.
`AgentSession.compact()`'s two abort-rejection sites now throw the
typed sentinel; the model-call wrapper normalizes AbortError-shaped
rejections to the sentinel only when the compaction's abort signal
is actually set, preserving every other exception unchanged so real
compaction bugs are not silently relabeled as cancellations.
`CommandController.executeCompaction` and `handleCompactCommand`
return `Promise<CompactionOutcome>`; the catch classifies via
`instanceof CompactionCancelledError`. Existing callers (`/compact`,
loop runner, auto-compact) ignore the return value — non-breaking.
Op: extend
- Updated addMessageToChat in UI helpers and InteractiveModeContext to return rendered components instead of void.
- EventController now tracks IRC message components and removes them after a 10-second TTL, avoiding duplicate expiry scheduling per message signature.
- EventController dispose now clears all pending IRC expiry timers and tests were added for immediate render, TTL removal, duplicate suppression, and timer cleanup.
- Trim logo from 14w to 12w (2-wide legs).
- Diagonal BL→TR gradient instead of per-line LTR.
- Truecolor: 3-stop magenta→violet→cyan path that skips the deep-blue valley.
- 256-color: same 6-stop ramp as fallback.
- Compute the colored logo once at module load instead of per render.
- Updated ExtensionUIContext, InteractiveModeContext, and InteractiveMode to require editor factories to return CustomEditor instances.
- Removed the runtime compatibility guard and warning for non-CustomEditor implementations in setEditorComponent.
- Removed the test that verified rejection of non-CustomEditor factories in interactive-mode editor-component tests.
- Render each exit_plan_mode submission as a fresh plan review entry so refined plans are emitted into terminal scrollback.
- Keep external-editor edits replacing the current preview instead of adding duplicate review entries.
- Updated the plan review regression test to preserve the first preview and append the second one after intervening chat content.
- Added optional `/loop` `count|duration` command arguments and wired `command.args` into loop handling.
- Implemented `loop-limit` parsing and runtime types/helpers for iteration and duration budget limits with validation.
- Updated interactive mode to enforce loop limits per iteration, check duration expiry, and clear budget state on disable.
- Added loop-limit parse/runtime tests and fixed `/loop` arg errors plus macOS `MallocStackLogging` environment leakage.
- Move planModeEnabled check before plan.enabled guard so /plan can
still exit an active session even if setting toggled off mid-session
- Clear stale plan/plan_paused mode_change entries when plan.enabled
is off during session restore, preventing unexpected re-entry when
the setting is later re-enabled
- Added session-draft persistence methods in SessionManager to write unsent editor text to an artifacts-sidecar draft file and delete it after single-shot consumption.
- Persisted editor text during interactive shutdown and restored that draft on resume when the editor was empty, enabling Ctrl+D draft recovery.
- Updated Ctrl+D handling in the editor/controller path and added tests covering draft round-trip, artifact cleanup, stale-draft eviction, and in-memory no-op behavior.
- Added `recordLocalSubmission` and `withLocalSubmission` to replace inline signature set mutations across input and compaction flush paths.
- Signatures are now cleaned up automatically on delivery failure, preventing stale entries from suppressing editor-draft protection on retries.
- Extended test fixtures and added cases covering signature lifecycle for idle, streaming, and fire-and-forget submission paths.
- Status-line rendering now treats `statusLine.sessionAccent` as disabled only when explicitly set to false.
- Updated status-line overflow tests to assert gap colors use session accent when enabled and theme border when disabled.
- Test teardown now restores `WSL_INTEROP` and `WSL_DISTRO_NAME` environment variables after mutation.
- Added an isSettingsInitialized helper to expose whether global settings were created.
- Updated interactive mode to use the session name when settings are not yet initialized.
- Guarded the status-line accent lookup behind settings initialization to avoid premature access.
- Added WSL detection in terminal initialization and skipped periodic OSC 11 polling when running under Windows Subsystem for Linux.
- Removed mode 2031 activity tracking and stopped OSC 11 polling immediately when DA1/Mode 2031 reports were received.
- Extended OSC 11 appearance tests to restore platform/env state and verify no polling is started under WSL.
Fixes#914
- Added a new boolean statusLine.sessionAccent setting to settings schema and propagated it through status-line preview, controller, and component setting updates.
- Updated status line rendering and interactive border coloring to disable session-based accent colors when the setting is false.
- Added a regression test verifying the status-line gap uses theme border color instead of session accent when session accents are disabled.
Fixes#918
- Removed title-source aware branching from session terminal-title and accent helpers, and updated callers to use session name plus cwd only.
- Dropped UUID-based recent-session naming by preferring explicit header titles or first user prompts and generating an "Untitled · <time>" fallback.
- Adjusted welcome session-row rendering for width-aware name truncation and disabled reasoning in title generation requests to keep terminal titles concise.
- Added a unified eval framework with parser grammar, backend interfaces, and JS/Python execution result types.
- Added eval tool docs and updated prompts for fenced cells, `eval.py`/`eval.js`, and fallback behavior.
- Replaced the built-in `python` tool with `eval` across registry, rendering, interactive modes, and tool settings.
- Migrated Python execution runtime from `src/ipy` to `src/eval/py`, renamed state fields, and removed legacy introspection.
- Refactored browser tooling from in-process VM helpers to worker-managed tab supervisors and protocol transport.
- Added eval parser fallback and JS tool-bridge tests, updated imports, and removed obsolete python-mode suites.
- Parallelized startup by deferring plugin preload and running AGENTS.md scan plus context/template/command discovery in parallel.
- Added AgentsMdSearch exports and options so prebuilt search results were passed into system-prompt construction.
- Reworked logger timing to use AsyncLocalStorage-backed nested spans, initialize a root span, and emit hierarchical summaries.
- Added PI_TIMING-gated TS/TSX module-load timing via side-effect module-timer registration and wrapped key init/request paths with logger.time.
- Removed `id` fields from todo models/fixtures and switched session clones to content-based task identity.
- Replaced `/todo_write` `replace` with `init`, updated setup schemas to `list`/`phase`, and append content-only items.
- Updated `/todo` command flows to match phases and tasks by names/content (exact/prefix/substr, case-insensitive), with no ID targeting.
- Updated rendering/output labels to `# Todos`, `formatPhaseDisplayName`, and Roman-numeral phase headings across todo views.
- Aligned prompts, changelog, and todo tests/fixtures with the new init and content-based todo-write contract.
When entering plan mode while the session is streaming, #applyPlanModeModel
defers the switch into #pendingModelSwitch and snapshots the previous model.
On exit, the snapshot was restored but the deferred switch was left queued,
so the next agent_end flush landed the session on the plan-role model after
the user had already left plan mode.
Drop the pending switch in #exitPlanMode when its target matches the
plan-role resolution; leave any other queued switch alone.
Fixes#816
- Added a shared session path resolver that maps local:// URLs through local-protocol options, skips other internal schemes, and returns an absolute filesystem path for real files.
- Updated streaming-edit pre-cache and post-edit cache invalidation to use the shared resolver, preventing internal-scheme assertions while keeping filesystem-based flow for local plan files.
- Extended streaming-edit tests to confirm local:// plan edits complete without panicking and that auto-generated checks receive resolved absolute paths.
- Added support for batch PR operations by accepting `pr` as string or array and dropping `worktree` input.
- Updated `pr_view` and `pr_diff` to normalize PR IDs, process multiple PRs in parallel, and emit combined summaries.
- Refactored checkout into `checkoutPullRequest`, added repo-locking, fixed worktree paths, and summary metadata outputs.
- Updated `remote.add` handling with URL-aware idempotency and per-repo queueing for serialized git mutations.
- Added temp-home test scaffolding and expanded tests for batched PR flows and remote add conflict/no-op cases.