- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
Two boundary defects on the mirrored-todo path.
1. The Agent error drain snapshotted #cursorToolResultBuffer without
awaiting entry.pending, unlike #emitCursorSplitAssistantMessage. An
async cursorOnToolResult still running when the provider errored
patched an entry the catch path had already detached, so the
pre-transform payload was persisted. A provider error is exactly when
a transform is most likely to be in flight.
2. The todo renderer interpolated mirrored provider text straight into
terminal output. A Cursor snapshot carries model-authored task
content, phase names and summary text verbatim, so a label holding
ANSI/C0 sequences rewrote the terminal on every render and replay.
sanitizeText alone is not enough - it preserves tabs, which punch
holes in bordered output - so every display path now funnels through
one forDisplay() helper: task labels, blocker notes, phase headers,
the zero-task fallback, and the streaming renderCall preview. Raw
values are untouched; content and phase name are the identity keys
the local list is looked up by and what gets persisted.
- Kept op required in the todo schema; lenientArgValidation now routes raw args to execute(), where resolveTodoParams re-validates and repairs an omitted op (list -> init, phase+items -> append, bare items on empty list -> init).
- Ambiguous op-less calls surface the schema error as a retryable tool error instead of a hard validation failure.
selectCollapsedTodos took the active-overflow branch at active.length >= cap, so exactly cap actives plus trailing pending returned the cap rows with an empty summary — the pending work vanished with no '… N more' indicator.
Use a strict '> cap' guard so equality falls through to the normal branch, which counts every hidden row.
Fixes#5873
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
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>
Carry task.blocker through AgentSession clone so a blocker reason survives storage round-trips; skip non-open tasks when blocking a phase so completed/abandoned work is never reopened; reject targetless block/unblock; render blocked rows distinctly (warning fg + reason) in the tool renderer and keep them visible in the collapsed HUD. Adds regression tests (red-green verified on the clone path).
A `blocked` status (plus `block`/`unblock` ops and an optional blocker
note) for tasks that are open but waiting on something the agent can't act
on — a user decision, another agent, or an external action. Blocked tasks
stay in the tracker but are excluded from the stop-time incomplete-todo
reminder (via the existing pending/in_progress allowlist) and from
auto-promotion. Syncs the mode-layer TodoStatus, the ACP status map/guard,
the markdown markers, and the renderers.
Refs can1357/oh-my-pi#3581
- Implemented mutable session titles with audit tracking, including storage persistence for SQL and Redis backends.
- Added comprehensive session management features such as idle recap triggers, incremental subagent yield submissions, and automated title refreshing.
- Enhanced task tracking in the TodoTool with progress prioritization and improved session cleanup logic.
- Introduced citation tag handling for OpenAI-compatible source markers and improved edit parsing.
- Redesigned the Todo HUD as a connector tree with fixed-budget stage previews.
- Anchored status and HUD containers to prevent redundant UI elements in terminal scrollback.
- Implemented tree-based rendering for project phases and tasks while removing dynamic border rules.
- Upgraded `sherpa-onnx` and related packages to support current infrastructure.
- Removed the enforced minimum length for the `items` array in the tool schema to prevent unnecessary validation errors on operations that ignore the field.
- Added tests to verify schema acceptance of empty `items` arrays and confirmed that runtime errors are still correctly thrown for empty inputs during specific operations like `append`.
- Refactored `todo` tool to accept a single operation object instead of an `ops` array.
- Implemented parameter normalization to maintain backward compatibility with legacy array-based tool calls.
- Updated tool instructions, documentation, and UI rendering components to reflect the new interface.
- Added compatibility tests to verify rendering and execution for both legacy and current operation formats.
- Replaced usage of `ReturnType<typeof setTimeout>` and `ReturnType<typeof setInterval>` with the explicit `Timer` type across the codebase.
- Updated several type definitions and function signatures to use concrete types instead of inferred return types for improved clarity and maintainability.
- Updated `init` handling to build a single-phase list from `items` when `list` is absent, using `phase` if provided or defaulting to `Tasks`.
- Kept the existing init validation behavior by emitting `Missing list for init operation` only when neither `list` nor `items` was supplied.
- Added tests for flattened init forms, including implicit phase defaulting, explicit phase use, and the missing-input error case.
- Added Unreleased changelog documentation for the new read-only `todo.view` behavior.
- Documented revised bash tool guidance distinguishing safe computation pipelines from byte-trimming commands.
- Documented the cached-model selector fix for dropping the first Enter during refresh.
- Added `TodoTool` tests for `view` on populated and empty lists without mutating session state.
- Collapsed non-touched phases to one-line summaries in multi-phase todo renders while retaining full output for active, touched, or expanded views.
- Computed touched phases from in-progress tasks, completion transitions, and tool operations, with init operations now marking all phases.
- Added renderer tests covering collapsed rendering, argument-less fallback behavior, expanded mode, and separator-free phase output.
The todo tool's renderCall ran args?.ops?.map(...) directly, which throws
TypeError on any non-array ops value. parseStreamingJson surfaces such
shapes mid-stream: a partial Anthropic input_json_delta buffer like
'{"ops":"[{' becomes { ops: '[{' }, and intermediate states can hand back
null entries before object fields arrive. Each crash spammed Tool
renderer failed warnings and starved the TUI render loop.
Guard against:
- ops being any non-array (string, object, primitive)
- entries being null / non-object
- entry.items being a non-array
The fix is in the TUI renderer only — schema validation in the agent
loop is unchanged, so any genuinely malformed model output still
surfaces an invalid-args tool error to the model.
Fixes#2005
- Renamed `TodoWriteTool` to `TodoTool` and its source/prompt files.
- Updated tool registration, schema, renderers, and gating to `todo`.
- Adjusted cursor provider native tool names and tests to match.
- Renamed strike-animation constants and `todo-error-reminder` type.