# Changelog

All notable changes to @oni.bot/core are documented here.

Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.3] — 2026-06-14

### Fixed
- `AgentPool.dispose()` now wakes coroutines sleeping in a retry delay so they reject instead of hanging forever; previously, disposing a pool mid-retry-delay left the `invoke()` caller's promise permanently unsettled.
- `SwarmSnapshotStore` now retains the full `MAX_SNAPSHOTS` capacity — the eviction guard was off by one and capped the store at `MAX_SNAPSHOTS - 1`.
- `createAgentNode` retry delays no longer leak abort-signal listeners on the normal-timer path, preventing unbounded listener accumulation on a long-lived shared `AbortSignal`.
- Multi-mode subgraph streaming now emits every active stream-mode tag (e.g. `updates` and `values`) when `debug` is also requested; secondary tags were previously dropped for forwarded subgraph events.
- `Command.send` returned by `Send`-dispatched (fan-out) nodes is now forwarded to the next superstep, so chained sends execute instead of being silently dropped.
- `LSPClient.clearAllWaiters()` now settles every pending diagnostics waiter; live-array mutation during iteration was skipping waiters and hanging callers awaiting diagnostics at shutdown.
- The session-init smoke-test timeout timer is now cleared once initialization succeeds, so it no longer holds the Node event loop open for the remainder of the timeout.
- `MemoryLoader.loadType()` now returns all units of a type regardless of session load state, so memory consolidation no longer early-returns and skips when units were already loaded earlier in the session.

## [1.3.2] — 2026-06-07

### Changed
- Refreshed the npm README with the ONI Core banner and current package surface.

### Fixed
- Hardened CLI external-agent watchdog cleanup so process timeouts and idle timers
  do not fire after provider exit while stdio close is still draining.
- Added a direct-kill fallback for Windows process-tree termination and made the
  idle watchdog reset test less sensitive to full-suite scheduling delays.

## [1.3.1] — 2026-05-12

### Added
- Background-agent platform control-plane APIs under `@oni.bot/core/platform`.
- In-memory implementations for task submission, session queueing, environment provisioning, scoped identity, capability grants, artifacts, review gates, and audit traces.
- JSON-file platform session and artifact stores for local/single-node durable background-agent state.
- SQLite platform session and artifact stores for indexed local/single-node background-agent state with `better-sqlite3` kept as an optional peer.
- Postgres platform session and artifact stores for multi-node background-agent state with `pg` kept as an optional peer.
- Local execution environment provider for session-scoped workspace directories.
- HTTP and Cerebro execution environment providers for remote devbox provisioning, release, and health checks.
- External-agent platform runner that bridges `AgentSessionRunner` to harness `ExternalAgentDriver` instances.
- Runtime platform policy helpers for path, command, network, and explicit env secret enforcement.
- CLI and scheduled trigger adapters for normalizing launch events into platform `AgentTrigger` records.
- Reusable `ToolDefinition` runtime policy wrappers for enforcing tool capability, path, command, and network scope before tool execution.
- `oni platform-smoke` CLI command for local end-to-end background-agent platform verification with durable JSON session and artifact state.
- Bounded event/output retention options for CLI-backed external-agent drivers, including `maxEvents`, `maxOutputChars`, `maxStderrChars`, and `maxEventContentChars`.
- Harness `agentLoop` platform runner adapter for running native loop sessions behind the `AgentSessionRunner` contract.
- Swarm platform runner adapter for running compiled ONI/Swarm skeletons behind the `AgentSessionRunner` contract.
- Built package subpath export smoke script covering every root `package.json` export target and its generated type file.
- Root exports for platform primitives and `ONI_CORE_VERSION`.
- External black-box coding agent harness APIs for conductor-style orchestration of local Codex and Claude Code workers.
- CLI external-agent driver factories, JSONL event parsers, swarm-node helpers, and root/harness exports for downstream packages.
- Rich Codex and Claude Code driver option builders for model, sandbox, permissions, MCP config, worktree, budget, and extra CLI arguments.
- External agent runtime registry with default Codex and Claude Code runtime factories for npm consumers.
- Release verification gate covering normal verify, blocking coverage quality thresholds, strict typecheck, root build, package builds, production dependency audit, root npm pack dry run, and publishable workspace package pack dry runs.
- Injectable structured logger (`LoggerLike`, `getLogger`, `setDefaultLogger`, `consoleLogger`, `noopLogger`) exported from the root; every non-CLI core library module now logs through it instead of `console.*`.
- Versioned external-agent event taxonomy (`EXTERNAL_AGENT_EVENT_TAXONOMY`, `externalAgentEventPhase`, `isTerminalExternalAgentEvent`) for stable platform observability.
- Cross-platform inactivity watchdog (`idleTimeoutMs`) for CLI external-agent drivers and the platform external-agent runner.
- Opt-in path-scope runtime policy hook on `SkillLoader`.
- `fast-check` property/fuzz suites for path-scope normalization and artifact/audit serialization, plus deeper coverage for functional, namespaced-checkpointer, LSP, CLI, GitHub, and auth-resolver surfaces.

### Security
- Runtime policy enforcement extended to code-execution tools (`node_eval`, `e2b_sandbox`) with tool-capability and network grant checks; `e2b_sandbox` requires a network grant.
- Shared `redactSecrets` utility now redacts granted secret values from `agentLoop` artifacts/output, matching the external-agent runner.
- Content secret scanner (`audit:secrets`) and per-rule lint-warning budget (`lint:budget`) added as blocking steps in `verify:release`.
- Raised the `axios` dependency override to a patched `1.16.0` to clear new transitive advisories.

### Fixed
- Replaced `SessionBridge`'s stale hard-coded agent version with the shared package version constant.
- Cleared remaining strict ESLint errors in the package test helper, registry types, and advanced swarm factory guard.
- Updated workspace verification scripts so package typechecks and tests actually run on Windows.
- Hardened dependency overrides and test tooling versions to clear current moderate/high npm audit findings.
- Fixed strict `noUncheckedIndexedAccess` failures in parallel tool execution and supervisor-verifier swarm stages.
- Brought the private `@oni.bot/community` stub into workspace build, typecheck, and test gates.
- Aligned workspace `@oni.bot/core` peer dependency ranges to the current `^1.3.0` compatibility line.
- Restricted publishable workspace package tarballs to runtime `dist` output, excluding compiled test artifacts.
- Recorded platform policy denials in session audit logs and redacted granted secret values from external-agent summaries and artifacts.
- Blocked unsafe external-agent CLI options by default, including raw provider `extraArgs`, Codex approval/sandbox bypass, and Claude Code permission bypass unless an explicit `unsafe` override is provided.
- Improved external-agent CLI timeout and abort handling with process-tree termination on Windows and capped retained provider events/output.
- Enforced external-agent ownership paths for CLI `cwd`, Codex `addDirs`, and Claude Code `mcpConfig`/`worktree` path options before provider processes start.
- Added structured capability summaries to platform `capability.granted` audit events without recording secret values.
- Hardened external-agent JSONL parsing for nested provider frames, including Claude `tool_use` content arrays, provider-style Codex/Claude samples, malformed frames, and encrypted reasoning.
- Preserved sanitized external-agent resume metadata and guaranteed failed-run diagnosis artifacts for failed platform-run external-agent sessions.
- Added CLI external-agent env isolation and event redaction controls; platform-run CLI agents now avoid broad `process.env` inheritance by default and redact granted secret values before stdout/stderr events escape.
- Added the subpath export smoke check to `verify:release` after the root build.
- Added type-level public API smoke checks for every root package export subpath.
- Added a tracked operations runbook for stuck sessions, failed external providers, audit review, and release gates.
- Added a structural `runtimePolicy` hook to `@oni.bot/tools` filesystem tools so platform sessions can enforce grants and path scope in the package surface without importing core internals.
- Added publishable package tarball snapshot checks to catch missing entrypoints, source/test leakage, local artifacts, and secret-like files.
- Documented the package source-map policy and added a tarball guard against embedded `sourcesContent`.
- Expanded the pull request template with platform/session, release-packaging, and semver production-readiness checklists.
- Added platform health and audit summary helpers plus `BackgroundAgentPlatform#getHealthSnapshot()` and `getAuditSummary()`.
- Added optional structured logger and OpenTelemetry-compatible platform span hooks around lifecycle phases.
- Added blocking `coverage:quality` thresholds for global coverage plus platform, external-agent, MCP/LSP, prebuilt, tool, GitHub, and auth-resolver surfaces.
- Added real stdio MCP transport integration coverage and ReAct agent graph-loop coverage for `createReactAgent`.
- Added `GitHubArtifactStore` for publishing platform artifacts as GitHub pull requests or issue/PR comments while mirroring enriched artifact records locally.
- Added GitHub webhook, chat command, and dependency alert trigger adapters, including HMAC verification for GitHub raw webhook bodies.
- Made the circuit-breaker half-open integration test deterministic under coverage instrumentation by replacing wall-clock sleeps with fake timers.
- Made retry backoff tests deterministic and ensured `maxDelay` caps the initial retry delay when it is lower than `initialDelay`.

## [1.2.0] — 2026-03-16

Automated bug pipeline sweep: **90 bugs** found, fixed, and independently verified (BUG-0024 through BUG-0182). Primarily security hardening and reliability improvements across the entire codebase.

### Security — Injection & Traversal
- **Path traversal prevention:** `persistSemantic()`, `persistEpisodic()`, `persistInternal()`, `safeSkillPath()`, and GitHub API calls now validate/sanitize paths (BUG-0064, 0075, 0100, 0101, 0106, 0163, 0166)
- **Null-byte injection:** Stripped from `sessionId`, `domain`, and `topic` fields before filesystem operations (BUG-0163, 0166)
- **Command injection:** `execSync` replaced with `execFileSync` (array args) in CLI commands; `shell:true` removed from spawn (BUG-0063, 0104)
- **Prototype pollution:** `deepMerge` filters `__proto__`/`constructor`/`prototype` keys; recursive strip in `modifiedInput` (BUG-0062, 0144)
- **Mermaid injection:** Bracket characters escaped in node labels to prevent diagram injection (BUG-0174)
- **Role string sanitization:** LLM message interpolation sites in supervisor sanitized (BUG-0173)
- **LLM-generated skill validation:** Content validated before writing to disk (BUG-0157)
- **ReDoS prevention:** Replaced vulnerable `rm -rf` regex with O(n) token-based check (BUG-0180)

### Security — SSRF & Exfiltration
- **URL scheme validation:** All model factories (`anthropic`, `openai`, `openrouter`, `google`, `ollama`) and `A2AClient` now reject non-HTTP(S) `baseUrl` schemes to prevent API key exfiltration (BUG-0105, 0141, 0142, 0143, 0170, 0179)
- **API key validation:** All model factories throw at construction time if API key is missing (BUG-0098, 0099, 0159)

### Security — Information Disclosure
- **Error message sanitization:** Raw API response bodies replaced with generic status messages across all model adapters, GitHub, Firecrawl, web-search, and A2A handlers (BUG-0076, 0102, 0111, 0155, 0161, 0164, 0165, 0167)

### Security — Access Control & DoS
- **TOCTOU race fix:** `checkAllowedPath()` returns resolved path; all 6 filesystem handlers use it for I/O (BUG-0065, 0181)
- **Fail-closed semantics:** Empty `allowedPaths` now throws instead of allowing all access; hook timeouts fail-closed for security-critical events (BUG-0149, 0168, 0169)
- **Default-deny permissions:** Missing agent entries in permission config now deny by default (BUG-0172)
- **Safety gate strictness:** `approved` field checked with strict boolean equality (BUG-0162)
- **Body size limits:** A2A server enforces 1MB max body; `requestHandler()` enforces `MAX_BODY_SIZE` for Fetch-API callers (BUG-0077, 0145)
- **Buffer overflow guards:** MCP `StdioTransport` enforces `MAX_BUFFER_SIZE`; LSP client caps buffer at 64MB (BUG-0068, 0182)
- **Unbounded growth caps:** `ExperimentLog` capped at 1000 records; `DeadLetterQueue` at 100 per thread (BUG-0129, 0130)
- **CORS enforcement:** A2A server adds preflight handling and `Content-Type` enforcement (BUG-0171)

### Security — Cryptographic
- **PRNG hardening:** `Math.random` replaced with `crypto.randomUUID` for HITL resume IDs, broker IDs, and `generateId()` (BUG-0095, 0103, 0122)

### Fixed — Reliability
- **Shared mutable state:** 6 module-level counters/maps moved to per-instance scope to prevent cross-tenant interference (BUG-0070, 0082, 0083, 0092, 0123, 0134)
- **Race conditions:** `refreshTools()` coalescing lock prevents concurrent races; `fileVersions` re-read at increment point; race timeout properly cleared (BUG-0124, 0125, 0127)
- **Resource leaks:** `ReadableStream` reader released in `finally` block; `onAny()` returns unsubscribe function (BUG-0079, 0128)
- **Lifecycle events:** `SessionEnd` fires on all loop exit paths including HITL interrupt; telemetry span closes on interrupt (BUG-0080, 0086)
- **Redis atomicity:** `SET+ZADD` combined into single Lua script for `put()`; `DEL+ZREM` wrapped in `MULTI/EXEC` (BUG-0073, 0096, 0126)
- **ESM compatibility:** `require()` calls replaced with static ESM imports in `SkillLoader` and `safeSkillPath` (BUG-0078, 0081)
- **Stream resilience:** OpenRouter adapter handles usage-only SSE chunks and guards `choices` dereference; `SafetyGate.check()` handles non-string/non-array content (BUG-0153, 0178)
- **Error handling:** JSON-RPC handler catches sync throws; spawn processes get `error` event handlers; JSONL parsing skips malformed lines (BUG-0029, 0114, 0115, 0150)
- **Input validation:** `fromJSON` validates input shape; nested object schemas enforce required fields; `validate` callback invoked on resumed user input; `Object.freeze` no longer blocks VM result write-back (BUG-0024, 0112, 0151, 0152)
- **Minor fixes:** Empty CSV guard, PII regex `/g` flag removal, Slack `username`/`iconEmoji` passthrough, round-robin over full slot list, `structuredClone` fallback, dotless path guard in `getLoader`, null-safe `refreshTools`, unknown channel key filtering, state method signature alignment, E2B timeout cleanup, off-by-one in `fireSessionEnd` turn count, fallback truncation `continue` fix (BUG-0025, 0026, 0027, 0028, 0030, 0067, 0090, 0093, 0107, 0120, 0121, 0133, 0136, 0137, 0154, 0175)

### Added
- 8 new test files covering prototype pollution, hooks eval bypass, PII regex safety, skill evolver ESM paths, DAG unsatisfiable deps, supervisor routing errors, wrap-agent loop errors, and A2A handler subscribe errors

## [1.1.1] — 2026-03-15

### Fixed
- **Deep equal cycle guard:** Two separate WeakSets for independent object tracking prevents false equality on cyclic structures
- **Direction-aware improvement check:** `ExperimentalExecutor` now correctly evaluates optimization direction
- **ESM error code:** Postgres store uses `ERR_MODULE_NOT_FOUND` (correct ESM code) instead of `MODULE_NOT_FOUND`
- **Streaming tool-call ID collisions:** Counter-based IDs prevent duplicates in parallel tool calls
- **SSE error propagation:** Nested try/catch with `controller.error` for proper stream error handling
- **Fallback truncation:** `continue` instead of `break` so oversized messages don't halt truncation
- **Silent parse failures:** `console.warn` surfaced across all 5 model adapters and `responseFormat` parsers
- **Postgres checkpoint deserialization:** Runtime validation on restored checkpoint data
- **PubSub subscriber errors:** Errors in subscriber callbacks are now logged instead of silently swallowed
- **Bridge tracer cleanup:** `startTimes` map entries removed on `unsubscribe` to prevent memory leaks
- **MCP client error propagation:** `.catch()` reordered so callback errors propagate correctly
- **Mermaid graph rendering:** Router-to-target edges now render correctly in `toMermaid()`
- **`contentLength()` accounting:** Tool call tokens included in content length calculation
- **`interruptAfter` parallel safety:** Moved to post-loop pass to avoid interrupting mid-superstep
- **`executeTools` parallel safety:** `parallelSafe` check now matches `defineAgent` pattern
- **EventBus dispose:** `waitFor` promises correctly reject on bus disposal
- **Harness hooks engine:** Error isolation between hook handlers
- **OpenAI adapter streaming:** Robust chunk parsing for partial SSE frames
- **Skill evolver:** Pattern learner and evolver state management fixes
- **Redis store:** Connection lifecycle and error handling improvements

### Changed
- Removed internal planning documents from repository (architecture docs, bug trackers, sprint plans)
- Moved developer guide to root level (`GUIDE.md`)

## [1.0.2] — 2026-03-13

### Fixed
- **Budget guardrails:** `BudgetTracker.record()` is now called from `defineAgent` after each `model.chat()` via a RunContext callback; throws `BudgetExceededError` when `maxTokensPerRun`/`maxTokensPerAgent`/`maxCostPerRun` is exceeded.
- **defineAgent ToolContext:** `store` and stream `emit` now read from the live RunContext instead of being hard-coded to `null`/noop, so tools receive the real store and can emit custom stream events.
- **parallelSafe enforcement:** `parallelSafe: false` is now preserved through `ToolDefinition` and respected by `defineAgent` — when any tool in a batch has `parallelSafe: false` all calls in that step execute sequentially.
- **pathMap compile-time validation:** `StateGraph.compile()` now validates conditional edge `pathMap` targets at compile time, throwing `NodeNotFoundError` instead of failing silently at runtime.
- **spawnAgent in unsupervised swarms:** `spawnAgent()` now throws a clear error when called on a swarm without a supervisor, rather than silently adding an agent that never executes.
- **removeAgent edge cleanup:** `removeAgent()` now removes stale static edges pointing to the removed node from `_edgesBySource`, preventing `NodeNotFoundError` when Pregel tries to route to a removed agent.
- **Lifecycle events from defineAgent:** `llm.request`, `llm.response`, `tool.call`, and `tool.result` events are now emitted and audit entries written for every model call and tool execution inside `defineAgent`.
- **toolPermissions enforcement:** `checkToolPermission()` is called before each tool execution in `defineAgent`, outside the tool's try/catch, so `ToolPermissionError` propagates as a real graph failure.

## [1.0.1] — 2026-03-13

### Fixed
- **Token streaming (parallel nodes):** Replaced module-level `_tokenHandler` global with `AsyncLocalStorage` — each node in a parallel fan-out now gets its own token handler, preventing tokens from being silently dropped or misrouted to the wrong node.
- **HITL resume:** `resume()` now looks up the session by `resumeId` (not just the first pending interrupt) and calls `markResumed()` so sessions transition from `"pending"` to `"resumed"` after being handled.
- **Subgraph checkpointer restore:** The child runner's original `checkpointer` is saved before being overwritten with a `NamespacedCheckpointer` and restored after the subgraph completes, preventing the child's checkpointer from leaking across invocations.
- **Circuit breaker fallback:** The user-supplied `fallback(state, error)` is now called with the real node state and the `CircuitBreakerOpenError` instance rather than `(undefined, undefined)`.

## [1.0.0] — 2026-03-13

### Breaking Changes
- `oni-code` AI coding assistant extracted to `@oni.bot/code` (separate package)
- `sentinel` code analysis engine extracted to `@oni.bot/sentinel` (separate package)
- `oni` and `oni-code` CLI binaries removed from this package (install `@oni.bot/code` for the CLI)

### Added
- `./config` sub-module export (`@oni.bot/core/config`) — JSONC config loader with env var substitution and hierarchical merge
- `"sideEffects": false` — enables full tree shaking in bundlers

### Framework
- 5 model adapters (anthropic, openai, openrouter, google, ollama) — zero runtime dependencies
- 21 total exports: root + 20 named subpaths

## [0.7.0] - 2026-03-08

### Added
- Structured error codes with `ONI_<CATEGORY>_<NAME>` taxonomy — every error carries code, category, recoverable flag, suggestion, and context
- Per-node timeouts via `addNode(name, fn, { timeout: ms })` with `NodeTimeoutError`
- Global default timeout via `compile({ defaults: { nodeTimeout: ms } })`
- Circuit breaker pattern: `addNode(name, fn, { circuitBreaker: { threshold, resetAfter, fallback? } })`
- Dead letter queue: `compile({ deadLetterQueue: true })` captures failed node inputs for recovery
- OpenTelemetry tracing adapter (`ONITracer`) — zero-dep, user brings own tracer
- Backpressure streaming with `BoundedBuffer` (drop-oldest and error strategies)
- Testing utilities: `mockModel()`, `assertGraph()`, `createTestHarness()` via `@oni.bot/core/testing`
- `oni init` CLI command for project scaffolding
- 7 new error types: `NodeTimeoutError`, `CircuitBreakerOpenError`, `SwarmDeadlockError`, `ModelRateLimitError`, `ModelContextLengthError`, `CheckpointCorruptError`, `StoreKeyNotFoundError`

### Changed
- `ONIError` now accepts optional `ONIErrorOptions` as second constructor parameter
- All existing error classes enhanced with structured codes (backward compatible)

## [0.6.3] - 2026-03-05

### Added
- `set()` alias for `put()` on `InMemoryStore` and `NamespacedStore`

## [0.6.2] - 2026-03-05

### Fixed
- `createReactAgent` now accepts `ONIModel` (auto-adapts chat to invoke)

### Changed
- Package renamed from `@oni-bot/core` to `@oni.bot/core`

## [0.6.1] - 2026-03-05

### Changed
- Removed all external framework references from codebase and documentation

### Fixed
- Resolved TypeScript strict errors in swarm template `Send` casts

## [0.6.0] - 2026-03-04

### Added
- `SwarmGraph` builder for multi-agent orchestration
- `SwarmGraph.hierarchical()` template — supervisor-workers pattern
- `SwarmGraph.fanOut()` template — parallel agent execution with reducer
- `SwarmGraph.pipeline()` template — linear chain with conditional transitions
- `SwarmGraph.peerNetwork()` template — decentralized agent handoffs
- `SwarmGraph.mapReduce()` template — parallel map with reducer
- `SwarmGraph.debate()` template — multi-round parallel debate with judge
- `SwarmGraph.hierarchicalMesh()` template — nested team coordination
- Lazy coordination auto-wiring (broker and pubsub) on `SwarmGraph`
- Handoff execution — agent `Handoff` returns converted to `Command` routing
- Retry-then-fallback — agents retry on failure, fall back to supervisor

### Changed
- Replaced `SwarmLLM` with `ONIModel` in supervisor routing

## [0.5.0] - 2026-03-04

### Added
- `ONIModel` interface and core LLM types
- Anthropic LLM adapter
- OpenAI LLM adapter
- Ollama LLM adapter
- Google Gemini LLM adapter
- Models export path and re-exports
- Tool framework with `defineTool()` and `ToolContext`
- `AgentContext` and agent types
- `defineAgent()` declarative agent factory
- `agent()` functional agent factory
- `addAgent()` on `StateGraph` to wire agent nodes
- Request/response and pub/sub coordination patterns
- Tool permission guardrails
- Budget tracking and cost control guardrails
- Content filtering guardrails
- Audit trail and guardrails exports
- `EventBus` for structured lifecycle events
- Guardrails and event bus wired into compile/execution pipeline
- Integration tests for agents, tools, and guardrails

### Removed
- Direct `openai` dependency (adapters are now bring-your-own-client)

## [0.4.0] - 2026-03-04

### Added
- `StateGraph` builder with `addNode()`, `addEdge()`, `addConditionalEdges()`
- Pregel execution engine (`ONIPregelRunner`) with parallel superstep execution
- `Command` and `Send` primitives for dynamic routing
- Subgraph support via `addSubgraph()`
- Functional API (`entrypoint`, `task`)
- `MemoryCheckpointer` and `NoopCheckpointer`
- `InMemoryStore` and `NamespacedStore` for shared key-value state
- Human-in-the-loop via `interrupt()` and `getUserInput()`
- Token streaming with `emitToken()` and `TokenStreamWriter`
- Stream modes: `values`, `updates`, `events`, `messages`, `custom`
- Graph inspection via `getGraphDef()`
- `createReactAgent` prebuilt for tool-calling loops
- `ToolNode` prebuilt for automatic tool dispatch
- Messages reducer (`messagesReducer`, `addMessages`, `removeMessages`)
- Retry policies with configurable backoff
- Swarm primitives: `AgentRegistry`, `AgentPool`, `Mailbox`, `Supervisor`
- Ephemeral channel support
- Map-reduce parallel fan-out pattern
