- 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.
- server-port-conflict opened the module-global db against the live agent stats.db, poisoning later files (sync-serial read 2.28M real rows); installStatsTestIsolation gives it a temp agent dir and closes the handle in teardown
Versioned the dashboard identity header and required the current security version with no CORS permission before reusing a listener.
Older versioned and headerless stats dashboards are now identified by their process and restarted so loopback-only binding takes effect immediately.
Fixes#7633
Replaced the 127.0.0.2 fetch, which a configured HTTP proxy could intercept, with a direct Bun.connect TCP probe so the loopback-only bind is asserted against the real listener.
Fixes#7633
Bound the dashboard and reuse probe to IPv4 loopback, removed wildcard CORS, and reported the actual listening hostname.
Added regression coverage for non-loopback refusal and absent cross-origin access.
Fixes#7633
- 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.
Installed a five-second SQLite busy timeout before the read-only usage query and covered lock contention with a subprocess-backed regression test.
Fixes#7300
- Guarded malformed persisted content blocks so later project files continue ingesting.
- Marked full-session migrations complete only after a successful sync pass.
Fixes#6373
On macOS SO_REUSEADDR lets startServer's wildcard bind coexist with a
127.0.0.1-only listener, so the EADDRINUSE path was never exercised and
three of the four conflict tests failed. Wildcard-bind the holders and
the reused dashboard so the conflict is real on every platform.
Recorded listener command lines across supported platforms and required an omp-stats-specific command identity before terminating Bun, Node, or omp holders. Unrelated runtimes now take the refusal path without receiving a signal.
Fixes#5970
Stamped an x-omp-stats-dashboard header on dashboard responses and required it (or the models JSON-array shape) in the reuse probe, so a foreign 200 responder such as an SPA dev server catch-all is no longer mistaken for a live dashboard.
Fixes#5970
Reused live stats dashboards sharing the requested port and reclaimed stale Bun, Node, or omp listeners after a failed health probe. Foreign listeners now produce an ownership-specific error.
Fixes#5970
- Anchored advisor compaction on provider-reported context usage (cached
input + generated output) floored by a full local estimate including the
advisor system prompt and tool schemas, so a near-full cached context is no
longer undercounted by the per-message estimate.
- Rejected stale provider usage retained across advisor compaction via a
runtime-only usage-anchor boundary recorded on the summary message.
- Recovered provider overflow by clearing only the advisor's own context at
the current primary cursor, retrying the bounded failing batch once against
a fresh context without replaying old primary history, and keeping later
updates eligible.
- Threaded the selected dashboard range through the stats Recent Errors UI,
API, and database timestamp filter before ordering and the 50-row limit.
Fixes#5282
- Coerce missing `stopReason`, token counts, and timestamps at the parser boundary to satisfy database NOT NULL constraints.
- Skip assistant entries missing essential model attribution or usage data instead of aborting the sync process.
- Filter invalid tool call blocks that lack required identifiers to ensure successful database insertion.
- Resolved a crash occurring when syncing legacy session files that lack usage cost breakdowns.
- Updated cost resolution to fallback to catalog pricing when stored cost is unavailable or zero.
- Adjusted yelling, profanity, and anguish criteria to reduce false-positive metrics.
- Implemented refined regex patterns for negation, blame, and noise reduction.
- Incremented the backfill key to v8 to accommodate updated signal definitions.
- Expanded test suite to validate new constraints for yelling, exclusion words, and sentiment triggers.
- Allowed the priority premium-request fixture to set assistant message `api` values.
- Covered direct Anthropic priority traffic with `api: "anthropic-messages"` so premium-request backfill follows API-family classification.
smokeTestSyncWorker spawned a worker via createSyncWorker on every platform, so omp --smoke-test (and the macOS signing pre-launch run in scripts/ci-macos-sign.sh) still hit the Bun-worker re-entry path the serial macOS sync default avoids. Early-return on darwin and document the carve-out.
Fixes#3733
Stats tests set PI_CONFIG_DIR + setAgentDir(home/<config>/agent), which resolves equal to the default agent dir and routes stats.db through $XDG_DATA_HOME/omp/stats.db whenever an XDG var is set, leaking rows across tests. The shared installStatsTestIsolation helper now snapshots and clears XDG_*_HOME with PI_CONFIG_DIR on each test, points the agent dir at a fresh TempDir, closes the DB handle, and restores the prior env after the test.
Keyed the serial-parser branch off the caller-requested worker count instead of the per-pool clamp, so a one-file sync still fans out to workers when the caller (or default) asked for more than one.
Fixes#3733
Replaced the stats session parser's Bun.JSONL.parseChunk path with a lenient JS line scanner so large session files do not enter the native parser before /stats launches.
Fixes#3733
Kept the documented workers: 1 path inline and defaulted macOS stats sync to that serial parser path so /stats dashboard launches do not re-enter Bun workers on macOS.
Fixes#3733
- 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.
SessionManager.fork() and createBranchedSession() deep-copy a parent's
entries into the child JSONL — same entry_id, timestamp, model,
responseId, token counts, cost. Stats keyed uniqueness on
(session_file, entry_id), so both files contributed to request, token,
and cost totals.
insertMessageStats and insertUserMessageStats now skip rows whose
(entry_id, timestamp) already exists under a different session_file
(first-write-wins). A one-shot migration on initDb, gated by the
fork_dedupe_v1 meta sentinel, collapses pre-existing duplicate rows
in messages and user_messages by keeping the lowest-id row per
(entry_id, timestamp) group.
Fixes#3370
- Implemented agent type classification and persistence in the database, including a backfill for legacy records.
- Added `AgentType` categorization and aggregated token usage metrics to the backend services.
- Created an `AgentTokenShare` visualization component to display usage distribution on the overview dashboard.
- Integrated agent-based tracking into existing data pipelines, view models, and testing suites.
Rewrite the local `omp stats` web UI on the OMP brand palette with a left nav, focused per-section views, a new Projects view, a system-aware light/dark toggle, and flicker-free navigation. Same data, endpoints, and command; the only server change is a 1h time-range bucketing fix in the aggregator.
The PR bumped USER_MESSAGES_BACKFILL_KEY to user_messages_v6, but the
behavior-backfill regression still seeded the dead user_messages_v5
sentinel, so it no longer exercised the user-messages backfill reset
path. Point both fixtures at v6.
Addresses review feedback on #2457.
Adds a computeUserMessageMetrics() assertion that ordinary `git`
prose scores profanity: 0, so the dropped token cannot be silently
reintroduced by a future profanity-list edit.
Addresses review feedback on #2457.
- Centralized catalog and registry handling on `ModelSpec` and `buildModel`, resolving compatibility at model build time.
- Removed runtime compatibility detectors and switched provider request flows to direct `model.compat` reads.
- Added compat fields (`supportsReasoningParams`, `alwaysSendMaxTokens`, `strictResponsesPairing`, `whenThinking`).
- Persisted explicit compatibility overrides through `compatConfig` in discovery and cache merge paths.
Stats sync depends on service_tier_change entries to derive priority premium requests since 69043d307 stopped folding priority-tier into per-message premiumRequests. parseSessionFile(path, fromOffset) initialized currentServiceTier to undefined per call, so an incremental resume past the tier change attributed subsequent priority OpenAI replies with premiumRequests: 0. When fromOffset > 0, parseSessionFile now replays bytes[0..start] purely to seed currentServiceTier from the latest service_tier_change before parsing the unprocessed tail. Bytes are already loaded, so no extra I/O.
- Updated read range expansion to use 1 leading and 3 trailing context lines.
- Changed read.defaultLimit from 500 to 300 in settings defaults.
- Updated read docs and tests to reflect the asymmetric context line behavior.
- Added read-selector analyzers and replay simulators to evaluate coverage and savings.
- Added plotting tools that output new session-stats PNG dashboards from local usage data.