Argument/flag validation failures in the minimal CLI framework threw a
plain Error that bubbled to the process-level catch in cli.ts, which
dumps a Bun.inspect code frame — a minified dist/cli.js excerpt in
compiled binaries. A missing model on `omp bench` looked like a crash.
- Add CliUsageError; throw it from Command.parse for missing/invalid
args and flags.
- Catch CliUsageError in run(): print `error: <msg>` plus the command
usage line to stderr, exit 1, no stack.
- Render required variadic positionals as MODELS... in usage, not the
misleading optional [MODELS]; extract commandUsageLine helper.
Fixes#5369
Rules whose condition led with a PCRE-style inline flag group (e.g.
`(?i)`) never registered: `new RegExp("(?i)...")` throws in Bun/JS, so
the condition failed to compile and `TtsrManager.addRule` dropped the
rule as having zero usable conditions.
- Add `compileRuleCondition` in capability/rule.ts translating a leading
`(?i)`/`(?m)`/`(?s)` group into native RegExp flags; wire it into the
TtsrManager and both ttsr-cli compile sites.
- Strip surrounding quotes from scope tokens so a malformed
`scope: "text","thinking"` recovers to canonical `text`/`thinking`.
- Reparse each value in parseFrontmatter's YAML fallback so one bad line
can't leave sibling values wrapped in literal quotes.
Fixes#4796
- Added bounded A* routing extents plus an expansion backstop so unreachable attachment points return null instead of searching the unbounded quadrant.
- Covered the reported declaration-order graph and an enclosed destination attachment point.
- Documented the Mermaid ASCII routing fix in the utils changelog.
Fixes#5293
- Relocated `AsyncDrain` class from `coding-agent` to `utils` package.
- Updated `HistoryStorage` to import `AsyncDrain` from shared utilities.
- Centralized the utility to allow reuse across the codebase.
On a fresh profile ~/.omp/logs may not exist yet (the logger creates it
lazily), so opening getLogPath() with "a" threw and the guard fell back to
/dev/null — discarding macOS diagnostics and native crash reports instead
of preserving them in the omp log. mkdir the redirect target's parent
(recursive) before opening; the /dev/null fallback stays as the safety net.
On macOS, libmalloc writes runtime diagnostics (e.g. "MallocStackLogging:
can't turn off malloc stack logging because it was not enabled") directly
to fd 2 of the running TUI process at arbitrary times, painting into the
viewport. The existing env-strip only protects child processes.
Add a fd-level stderr guard in pi-utils (suppressTerminalStderr /
restoreTerminalStderr) that dup2-redirects fd 2 to the omp log file while
the TUI owns the terminal, and restores it at every ownership handoff
(external editor, Ctrl+Z suspend, shutdown, crash restore). Postmortem
fatal handlers restore fd 2 before printing so crash reports stay visible.
Mirrors openai/codex#24459.
- Introduced `stringifyJson` helper to preserve bigint precision by serializing them as decimal strings.
- Replaced native `JSON.stringify` across compaction and session management modules to prevent serialization errors when handling bigint values in tool arguments.
- Added regression tests in `agent` and `coding-agent` packages to ensure bigint tool arguments remain intact through compaction and persistence flows.
Moved the config.yml/config.yaml filename order into pi-utils as
MAIN_CONFIG_FILENAMES and taught the auth-broker config reader to probe
both extensions with the same precedence as the settings loader.
Fixes#4914
- Introduced a rejection interception mechanism to capture unhandled promise rejections from eval cell code.
- Attributed floating rejections to specific runs to fail the owning cell instead of crashing the process or worker.
- Downgraded rejections occurring after a cell finished to warn logs to prevent silent failures.
Filtered Bun-autoloaded launch .env.local entries out of child shell environments so nested commands can load their own dotenv files.
Added a regression test covering Convex-style inherited deployment variables while preserving ordinary inherited env values.
Fixes#4723
- Added markExpectedCleanupError and isExpectedCleanupError to identify and downgrade routine teardown errors to warnings.
- Updated global uncaughtException and unhandledRejection handlers to suppress process exit for tagged cleanup errors.
- Introduced a 10s execution deadline for cleanup callbacks to prevent process hanging during teardown.
- Implemented classifyJsonPrefix to categorize buffers as complete, valid prefix, or invalid based on RFC 8259 strictness.
- Added utility to support disambiguation of identifierless streaming tool-call deltas during model response processing.
- Validated classifier logic with comprehensive suite covering nested structures, escape sequences, and strict formatting rules.
- Added support for the `retry-after-ms` header in `getRetryAfterMsFromHeaders` to parse millisecond-based retry delays.
- Implemented `parseRetryAfterMsHeader` utility to safely validate and convert header values to milliseconds.
- Updated `extractRetryHint` in `fetch-retry` to prioritize the `retry-after-ms` header during transport response processing.
- Included `x-ratelimit-reset-ms` header support in `extractRetryHint` to better handle rate limit reset timings.
- Added support for parsing unquoted bareword strings in object and array value positions.
- Implemented safety checks to prevent bareword recovery from masking structure, consuming non-finite atoms, or swallowing valid JSON delimiters.
- Included logic to preserve URL-style and Windows-style paths containing colons while rejecting invalid or ambiguous syntax.
- Extracted the `tls-fetch` implementation and tests from `@oh-my-pi/pi-ai` to `@oh-my-pi/pi-utils`.
- Exported the `wrapFetchForExtraCa` and `withExtraCaFetch` utilities publicly from `@oh-my-pi/pi-utils`.
- Introduced `ExtraCaError` to replace the AI-specific `ValidationError` for missing `NODE_EXTRA_CA_CERTS` paths.
- Updated imports in `packages/ai/src/stream.ts` to consume the relocated utility.
- Added preprocessing to quote ambiguous plain scalars containing a colon-space sequence when standard YAML parsing fails.
- Preserves the parsed types of unaffected fields and prevents fallback warnings for common unquoted description strings.
- Added tests to verify successful recovery of unquoted values and continued fallback warning coverage for unrecoverable syntax.
- Restored the fetchWithRetry early return for Retry-After and quota hints larger than maxDelayMs.
- Added coverage so oversized provider retry hints do not sleep and retry internally.
- Introduced `isProbablyBinary` utility to sniff file headers for NUL bytes or invalid UTF-8 sequences.
- Updated `ReadTool` to use the binary sniffer, preventing mojibake corruption in output when reading non-text files.
- Refined `file-mentions` auto-reads to skip binary files and mark them as `binary` in the message transcript.
- Added comprehensive unit tests for binary detection logic, covering NUL bytes, truncated multibyte characters, and path-based file sniffing.
Rejoined split Windows extension module paths before launch parsing finishes and stripped extended-length Win32 prefixes before Bun import and worker spawn APIs see them.
Fixes#3804
- Introduced comprehensive support for multiple concurrent, independently-configured advisors via `WATCHDOG.yml` files.
- Implemented a full-screen TUI overlay for managing advisor rosters, models, tools, and instructions.
- Added session-wide advisor initialization, telemetry aggregation, and named transcript isolation.
- Enhanced advisor security and observability with secret redaction in tool results and secure XML attribute encoding.
Bun's `Response(stream).bytes()` returns the raw `ArrayBuffer` once the
body arrives in more than one chunk, which happens for subprocess stdout
past ~128 KB. The public contract of `ptree.ChildProcess.bytes()` is
`Promise<Uint8Array>`, and callers — most visibly the `ssh://` read
path's `decodeUtf8Text` — rely on `Uint8Array` methods such as `.indexOf`
and `.subarray`. On larger remote text files this surfaced as:
TypeError: bytes.indexOf is not a function
Normalize the result at the boundary: when `Response.bytes()` hands back
an `ArrayBuffer`, wrap it in a zero-copy `Uint8Array` view before
returning. Adds a regression test that drives a 256 KB stdout payload
through `ptree.spawn(...).bytes()` and asserts the contract.
Fixes#3712
- Renamed the `find` and `search` tools to `glob` and `grep` respectively across the codebase to improve command clarity.
- Implemented full-stack support for the renamed tools, including CLI arguments, system prompts, SDK exports, and tool registration.
- Added automated migration logic in `settings` to transform legacy `find` and `search` configuration keys to their new equivalents.
- Updated the `collab-web` renderer registry to ensure backwards compatibility with legacy tool outputs.
- Added a `worktree.base` setting to allow users to specify a custom directory for agent-managed git worktrees.
- Updated the `worktree` command to ensure settings are initialized before operations to respect the configured base path.
- Enhanced directory resolution logic to support `~` expansion and enforce absolute paths for worktree environments.
- Centralized JSON parsing and stream processing logic by moving utilities from `packages/ai` to the shared `@oh-my-pi/pi-utils` package.
- Standardized import paths for JSON parsing and streaming across the agent, ai, and coding-agent packages.
- Refactored SSE stream handling to use consolidated `parseStreamingJson` logic and introduced robust error recovery for malformed container-shaped tail events.
- Cleaned up legacy bundled registry references and updated related module exports and tests to reflect the new utility structure.
The retry-on-EBUSY logic in removeSyncWithRetries/removeWithRetries
used 40 retries × 25ms = 1 second total. Windows can hold file locks
on SQLite databases for up to ~1.5s after close(), so tests that
already used removeSyncWithRetries (e.g. settings-manager.test.ts,
sdk-credential-disabled-bridge.test.ts) still failed with EBUSY.
Fix: increase the delay to 50ms (40 × 50ms = 2s total window). This
only affects Windows — the retry logic only runs on win32. Linux CI
is unaffected.
(cherry picked from commit ac67e96f1285ce0d80b2022c40c383b7ca262354)
- Set logger to silent mode when no transports are active to avoid "no transports" errors during log emission.
- Added a regression test to verify that disabling all transports suppresses warnings and that log output resumes after re-enabling transports.
- Added a check for empty transport arrays during logger initialization.
- Set the logger to silent mode if no transports exist to prevent unnecessary warning messages on every log emit.