- A blank run at EOF now breaks the list without consuming the blank,
matching real marked: '- item\n\n' lexes as a tight list plus a space
token instead of a loose list whose raw includes the blank.
- Completes the 17.2.10 mid-document fix; same-marker continuation and
indented item content across blanks are unaffected.
- Added list/blank boundary token-shape tests (verified against marked
v15) since the tui incremental tests compare the lexer to itself.
- A blank line before a non-continuing top-level line (including plain
paragraphs) now closes the list without consuming the blank, so it
always lexes as a separate space token like real marked.
- List token shape no longer depends on the follower's block type,
restoring the TUI streaming lexer's freeze invariant (lex(prefix) ++
lex(tail) == lex(full) under append-only growth).
- A list followed by a paragraph is now tight, not loose, per CommonMark.
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
Registered live session resume commands with postmortem handling so a
fatal rejection or exception identifies every recoverable agent before
cleanup. Escaped terminal control characters in recovery output.
Account-reset hint evaluated before short retry hints; account-scoped caps rotate on status 403 or undefined (Devin statusless trailer); statusless concurrency caps marked transient; transient same-model retries use the concurrency backoff.
Refuted: quota-worded concurrency caps were already excluded from rotation before the usage-limit text match.
(cherry picked from commit f2b9a18d715ddbcb6ae703670f2212da36bb2826)
- Added native `FileLock` bindings supporting cross-process advisory locking on Linux, Unix, and Windows.
- Replaced directory-based file locking and custom stale-lock reclamation with OS-backed native locks.
- Updated TypeScript declarations, native bindings, and package documentation for the new API.
- Added comprehensive unit tests and fixtures validating single-owner constraints and process death handoff.
- Moved the coding-agent lock-directory primitive to @oh-my-pi/pi-utils/file-lock
and migrated settings, MCP config-writer, and security store imports.
- Replaced the stats aggregator's parallel ~200-line token/breaker lock protocol
with the shared primitive: dead owners reclaimed immediately, live-but-wedged
owners after STATS_SYNC_LOCK_STALE_MS, unstamped acquisitions after the new
acquireStaleMs grace (10s).
- Shared primitive now treats EPERM kill probes as live owners.
- Rewrote the stats lock-reclamation regressions against the shared protocol
and moved the file-lock contract test into pi-utils.
The postmortem module bound the native hard-exit once at module init
(process.reallyExit.bind(process)). The shipped bundle defers this
module's evaluation until first access, which can land inside a
withHostGuard window where process.reallyExit is the ExtensionExitError-
throwing stub; .bind() then froze that stub permanently, so every later
host-owned exit (SIGHUP 129, SIGINT 130, fatal 1) threw and re-entered
the unhandled-rejection fatal path in a loop (exit 129 storm).
Resolve the native exit on every call instead of binding at init, and
have withHostGuard stamp its throwing replacement with the native
primitive it shadows so a signal arriving mid-guard still exits (#6488)
without the guard poisoning later exits (#7393).
Fixes#7393
On Windows process.env/Bun.env lookups are case-insensitive, so the
"env var name, else literal" resolvers turned a literal /login key like
`public` (OpenCode Zen's free key) into the built-in PUBLIC=C:\Users\Public,
sending `Authorization: Bearer C:\Users\Public` and 401ing every request.
Added `$envExact` in pi-utils, which trusts an env lookup only when an
exact-case key is enumerated (the only case-preserving signal on Windows;
the getter and hasOwnProperty/getOwnPropertyDescriptor traps are all
case-insensitive there). Wired it into all three resolvers:
resolve-config-value.ts, model-registry.ts, and auth-storage.ts.
Fixes#7361
- Implement the OMP Browser Relay extension with WebSocket communication and CDP RPC execution.
- Add browser relay server, daemon management, and bridge multiplexing in the coding agent.
- Introduce CLI commands and settings schema options for configuring and installing the relay.
- Add utility functions and test suites supporting environment parsing and relay lifecycle handling.
Scoped test-runtime detection to explicit runner markers and Bun test entrypoints, so application NODE_ENV/BUN_ENV values no longer make ProcessTerminal headless.
Added subprocess regression coverage and propagated the private marker to test children.
Fixes#7261
These four paths bypassed DirResolver's XDG-aware rootSubdir/agentSubdir
hooks, resolving directly against getConfigRootDir()/getAgentDir() and
ignoring XDG state/data layout. Add XDG-aware path helpers in dirs.ts
and route all four through them:
- secret-placeholder.key → $XDG_STATE_HOME/omp/ (state, agent flattened)
- marketplaces.json → $XDG_DATA_HOME/omp/ (data)
- run/daemons/<hash>/ → $XDG_STATE_HOME/omp/run/ (state)
- run/provider-inflight/ → $XDG_STATE_HOME/omp/run/ (state)
omp config init-xdg migrates secret-placeholder.key and marketplaces.json
from their legacy locations; run/ is ephemeral and rebuilds on restart.
Headless hosts (print/RPC/ACP/eval/SDK) run the agent loop on the same
thread as bun:sqlite, so a lock-contention busy-wait of the interactive
5s timeout freezes the protocol loop for seconds at a time with no
liveness signal. Use a 1s busy_timeout for session-critical databases
(agent.db, history.db, stats.db) when the host is not interactive, and
let the existing asynchronous open/retry paths recover from contention.
Skipped stdout draining after ProcessTerminal observes a native Windows terminal disconnect, while preserving normal postmortem cleanup and drain behavior for every other shutdown path.
Fixes#6917
(cherry picked from commit b45fc00ab4b5075ccb9650584947dde061beea20)
Compiled Bun binaries autoload project dotenv files, so snapshotting Bun.env inside one captured the secrets as launcher-owned and forwarded them to every shell. Drop that branch and record launcher values, restoring an empty launcher value that Bun overwrote with a dotenv secret.
- filterChildShellEnv now also filters Bun-autoloaded .env.{NODE_ENV||development}
entries, closing the .env.production/.env.development leak into child shells.
- parseEnvLine skips backslash-escaped quotes when locating the closing
delimiter, restoring baseline/Bun-literal handling of values like JSON="{\"a\":1}"
that the new parser truncated.
- Adds a parseEnvFile regression test for escaped quotes.
Handled export prefixes and quote-aware inline comments when parsing dotenv files, and filtered child shells by launcher provenance so injected values are dropped regardless of value formatting.
Covered export and inline-comment forms in unit and shell-filter tests.
Fixes#6813
Tracked project values loaded by OMP separately from names present in the original launch environment, preserving parent values even when dotenv repeats the same bytes.
Covered Bun-autoloaded and no-env-file launch modes.
Fixes#6813