Repository navigation
Conversation
…he tab is not script-closable (@Hunter-124)
…osures and floating promise leaks during subagent teardown (@jaimehgb) # Conflicts: # packages/utils/src/postmortem.ts
…rged fixes - Ran biome over files touched by the merged PRs and narrowed the shake test user-message lookup for the current AgentMessage union.
- Updated SETTINGS_SCHEMA to set `extendedContext` default to false. - Added changelog entry documenting that `extendedContext` now defaults to off. - Modified tests to enable `extendedContext` and adjust model identifiers accordingly.
- Test module already imports super::*, so summary::SummarySegment failed to resolve (E0433) and broke the bazel rust workspace CI job. - Replaced the empty-array assert_ne with a direct is_empty check.
- Added crates/pi-vcs/BUILD.bazel and the //crates/pi-vcs dep on the pi_natives cdylib; the new crate was never registered with bazel, so the native addons job failed with E0432 unresolved import pi_vcs. - Allowed MPL-2.0 for uluru (pi-vcs -> jj-lib -> gix -> gix-pack), package-scoped like the existing inferno exception; cargo-deny's license gate rejected it. - Diff rendering now interns lines with their terminators instead of gix's stripped interned_input(), so CRLF content keeps literal CR bytes and a final line without a newline diffs as a distinct line, matching git byte-for-byte. The old sink re-added bare LF, which only matched git when user-level core.autocrlf leaked into the git oracle; on hermetic runners the new pi-vcs_test target would fail.
… strict - Generated clippy-strict config now leads with -Aunknown_lints: the lint policy is authored against the rustup nightly, so names the pinned bazel toolchain predates (clippy::assert_is_empty) turned into E0602 hard errors under the aspect's -Dwarnings. - Added //crates/pi-vcs/... to the strict clippy scope in ci.yml; the crate opts into the workspace lint policy but predated the list. - Fixed the one strict finding in pi-vcs (Duration::from_secs).
…g OK A single-file `lsp diagnostics` request waited SINGLE_DIAGNOSTICS_WAIT_TIMEOUT_MS (3s) for the pull-diagnostic response and mapped a timed-out or errored pull to an empty result, which rendered as a clean `OK`. Project-aware pull servers (Roslyn, tsserver, ...) compute diagnostics on demand and routinely overrun that budget, so real diagnostics silently vanished. waitForDiagnostics now distinguishes a usable full report (empty items = clean) from a failed pull and rethrows the failure so the tool marks the server failed rather than clean. Project-aware servers also get a larger single-file pull budget (PROJECT_DIAGNOSTICS_WAIT_TIMEOUT_MS), still capped by the tool-level timeout. Fixes can1357#10035
A pull-capable server can also publish diagnostics. Keep the remaining wait budget after a transient pull rejection so a fresh publish can satisfy the request, while preserving the configured settle window for unversioned reports. Added contracts for no-publish failure, accepted fallback publish, and an unversioned publish that has not settled by the deadline. Fixes can1357#10035
- SQLite 3.52+ flattens the correlated EXISTS into a join step (SEARCH w EXISTS USING INDEX ...), so asserting the literal CORRELATED SCALAR SUBQUERY text failed on CI's newer bundled SQLite while passing on 3.51 locally. - Assertions now match the actual contract - a per-candidate index probe - in either plan shape; the LIST SUBQUERY / SCAN negative assertions and the rejected-IN control are unchanged and verified against both 3.51.0 and 3.53.4.
…er pi-vcs migration - Added native/vcs.js and native/vcs.d.ts to the published pi-natives core file list; the exports map advertised ./vcs but the packed tarball omitted the files, so the installed CLI failed with Cannot find module @oh-my-pi/pi-natives/vcs (install smoke). - Keybindings mocks in selector-settings-side-effects now provide getDisplayString, which the model picker calls since the model hub navigation change. - Replaced the git TUI sidebar additions-split test with a mixed-dir staging test: the pi-vcs migration removed the separate pure- additions list, so the old premise no longer holds; dir staging of modified + untracked files is the surviving contract.
- Added a `TuiDebugServer` to provide runtime TUI introspection, input injection, and process control via Unix domain sockets. - Instrumented TUI components with `debugState` methods and metadata to expose layout, state, and child trees for external tools. - Implemented a Bun-native PTY-based testing tool (`.omp/tools/tui`) for headless automation and frame inspection. - Updated package dependencies and integrated zlib-rs support to facilitate terminal emulation and rendering tasks.
…config - Branch create, worktree add, reset, and stash ref updates went through gix edit_references with the configured committer, which is None on hosts without user.name/email (CI runners, fresh installs), failing with 'The reflog could not be created or updated'. git only requires identity for commits, never for branch/reset/stash ref updates, so the new update_reference helper falls back to a synthesized 'oh-my-pi <omp@localhost>' signature for the reflog line. git commit keeps demanding a real identity. - Verified by creating a branch with HOME empty and all git config scrubbed: the reflog line carries the fallback ident and the gh pr_checkout suite passes in that environment.
- The bazel rustfmt aspect rejected the hand-formatted fallback-ident code from the previous commit.
Applied the theme-resolved user message foreground when composer styles leave their text surface transparent. Preserved background-specific contrast for filled field and rail styles. Fixes can1357#10038
Kept userMessageText scoped to composer styles that paint userMessageBg. Covered Light Poimandres so transparent text follows its readable normal text token. Fixes can1357#10038
Routed the shape preview prompt through the same resolved/filled-surface foreground path as the live editor so transparent previews stay readable when text is empty. Fixes can1357#10038
Defaulted extension composer styles without filledSurface metadata to their previous undecorated-row behavior while retaining explicit built-in surface handling. Added a regression proving an existing extension's surface foreground is not overridden by editor text color. Fixes can1357#10038
Added the full issuer-path well-known candidate used by Keycloak-style OpenID Connect discovery without changing the existing origin-root and RFC 8414 fallbacks. Covered the nested issuer path through the public discovery contract. Fixes can1357#10042
Replaced MCPOAuthFlow's duplicate metadata URL construction with the shared candidate builder so dynamic client registration follows the same nested-path discovery behavior. Covered DCR registration through the public authorization flow. Fixes can1357#10042
Kept issuer-appended metadata first for OpenID Connect discovery while trying RFC 8414 path-ful metadata before the compatibility form for other well-known documents. Covered both ordering contracts to prevent avoidable discovery timeouts.
Ordered each well-known document's standard form ahead of both the parent-relative and cross-form compatibility candidates so a slow gateway fallback no longer stalls discovery behind a 10-second timeout. Locked the OIDC standard-before-parent-relative ordering with a regression.
Carried the metadata issuer through endpoint discovery, reauthentication, and the add wizard so dynamic client registration probes issuer metadata instead of deriving paths from the authorization endpoint. Reworked the Keycloak regression to use its real protocol authorization endpoint.
Config-declared discovery providers (e.g. LiteLLM in models.yml) populate the model registry via fire-and-forget background discovery started before the session is built. With a cold discovery cache — the first launch after an update bumps the cache namespace — the registry has no models at construction, so synchronous startup validation reported every valid selector the provider will supply as "references unknown model". The append-only configWarnings array is snapshotted once into the header, so the false warnings stuck for the whole session. Validation now treats a selector whose provider discovery state is still `idle` as pending and suppresses the warning. Once the initial background refresh settles, the session re-runs validation, retracting warnings discovery resolved and surfacing any that stayed unknown; the interactive header rebuilds on a new config_warnings_changed event. Fixes can1357#10048
- Text de-dup is keyed by SDK block index, not a bare "anything streamed" flag, so a thinking-then-text turn and a message where only block 0 streamed no longer lose their unstreamed text blocks. - Every tool_use is tracked until its tool_result arrives. On abort, error or a generator that ends early, each still-unpaired call gets a synthetic error toolResult. A kCursorExecResolved block the agent loop skips would otherwise sit unanswered and read as freshly runnable on resume. - Drop calculateCost. Claude Code turns bill against the subscription, so a per-token cost would be fiction; token counts stay, usage.cost stays zero. - CLAUDE_AGENT_SDK_CLIENT_APP now carries the pi-ai version. - Images on the last user message are sent as SDK base64 content blocks via an async-iterable prompt; text-only turns keep the plain string. Seven new tests. Five of them fail against the previous implementation: index-keyed text, unpaired tool settle, images, zero cost on a priced model, and the versioned client app string. The thinking-streaming and abort tests are spec-named coverage that already held. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
Effort picker already resolves low..max via the static thinking.efforts baked in Task 1 (getSupportedEfforts reads model.thinking.efforts directly), so thinking.ts and model-controls.ts need no changes. Adds the live smoke script and docs for the claude-code subscription provider. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
Five findings from the whole-branch review: - Reasoning effort never reached the SDK. `mapOptionsForApi` did not put `reasoning` on the mapped options, so the provider's structural cast always read undefined and `effort` was never sent. Declare `reasoning` on `ClaudeAgentSdkOptions`, pass it through the mapper, drop the cast. - No recovery when `resume` failed. Claude Code prunes its session store, so a persisted id turns every later turn into a hard error. Detect an unknown-session message (strings taken from the installed CLI binary), call `resetSdkSession()`, and replay the flattened history once. Retried only before anything reached the stream, so two attempts cannot splice into one assistant message. - Discovered models inherited opus's 1M context window. Use the literal 200000 the spec states. - `endedSdkIndexes` was never cleared between assistant messages, dropping a later message's non-streamed text at an index that streamed earlier. - Document that the Claude Code subprocess loads the user's own ~/.claude settings, CLAUDE.md, and hooks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
v18 added the compat engine and its `compat parity` gate, which re-derives every baked models.json `thinking` block from scratch and requires the engine to reproduce it exactly. The six `claude-code` rows bake the SDK's own low/medium/high/xhigh/max ladder, but the generic deriver resolved them to the Anthropic-class minimal/low/medium/high, failing the gate on six rows. The ladder comes from the local Claude Code CLI (`ModelInfo.supportedEffortLevels`), not from the model lineage, and the `claude-agent-sdk` stream passes the selected level straight through as the `effort` option. So it is declared provider-wide in a new `providers/claude-code.kdl`, mirroring `providers/ollama.kdl`, rather than exempted from re-derivation. This also keeps `rebakeModelThinking` reproducing the baked values on the next `gen:models` run instead of overwriting them. `bun.lock` records the `@anthropic-ai/claude-agent-sdk` dependency added to packages/ai and packages/catalog; the cherry-picked lock hunk was regenerated by `bun install` against v18's lockfile rather than merged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
… provider
The assistant-message fallback skips a text block only when the block already
reached the stream, and it decided that from `endedSdkIndexes` — a set filled
at `content_block_stop`. The real SDK emits the full `assistant` message BEFORE
`content_block_stop`, so the set was always empty when the fallback read it and
every streamed text block was emitted a second time. A live smoke turn prompted
with "Reply with exactly: OK" came back as "OKOK".
Verified against @anthropic-ai/claude-agent-sdk 0.3.251, whose message order is:
message_start
content_block_start 0
content_block_delta 0 (xN)
assistant [{type:"text",...}] <- fallback ran here, set still empty
content_block_stop 0
message_delta / message_stop
result
The set is now keyed on `content_block_start` and renamed `streamedSdkIndexes`,
which is the property the guard actually wants: did this SDK block index ever
open a streaming block. The `content_block_stop` insert is dropped, so nothing
lands in the set after `handleAssistantMessage` clears it and leaks into the
next message's index 0. Clearing stays at the end of `handleAssistantMessage`.
The defect predates this port: the existing fixture ordered `content_block_stop`
before the `assistant` message, an order the SDK never produces, so the suite
passed while real turns duplicated their text. Both directions of the guard are
now pinned by tests that replay the true ordering — one asserting a streamed
block is not re-emitted, one asserting a block at an index that never streamed
still is. Both fail against the previous implementation.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
Default settingSources to [project, local] so the operator's global ~/.claude hooks (a Stop hook drove extra turns in the smoke) never run inside an omp turn. OMP_CLAUDE_CODE_SETTING_SOURCES overrides (comma list, 'all' = CLI default, 'none' = isolation). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
The SDK echoes each block as its own assistant message with a one-element content array, so a text block streamed at index 1 (after thinking) echoes at position 0 and the index-keyed guard re-emitted it (haiku: "OKOK"). A block is now a duplicate iff a block opened by content_block_start already carries the same text. Regression test replays the captured haiku order. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
… once the cache is cold The warm-cache guard (8k suffix, dcb16d8) is narrower than the age protect window (40k newer tool tokens), so pruneToolOutputs could never select an age victim and only superseded/useless results in the last 8k were ever blanked. A 400k-token session showed zero prunes. Lift the guard after idleFlushMs (90 min, same rule as the supersede pass): replaying the real transcript reclaims 247 results / 304k tokens when cold, 0 before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
…pt tokens) Adds an `advisors` status-line segment showing the roster size, advisor model ids, and the prompt tokens (input + cacheRead) advisors have consumed this session, colored by the worst runtime status. Added to the default, full, and nerd presets so advisor burn is visible without /advisor status. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
…iption auth A bare ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN was treated as a valid "logged in" signal for the claude-code provider, but the CLI subprocess inherits the parent env and bills that key per token while every claude-code-static.ts model spec reports zero cost — a silent cost-tracking blindspot. detectClaudeCodeLogin now requires an actual subscription-login marker (keychain, .credentials.json, or .claude.json), so the provider correctly reports "not available" instead of silently switching to metered billing. Metered API-key use belongs to the `anthropic` provider, which already computes real cost from usage. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
…xt blocks wasStreamed() checked content equality against any previously-streamed text block, so two distinct streamed blocks with identical text in one turn (e.g. two separate "Done." blocks) both matched the first block's identity and the second was silently dropped from the assistant echo fallback. Replace the WeakSet content-equality check with an ordered queue of streamed text blocks. The `assistant` echo visits blocks in the same relative order they streamed in, so matching only against the front of the queue and shifting it off on a match claims each streamed block at most once, regardless of duplicate text. Also removes the dead `streamedSdkIndexes` set (written at content_block_start, cleared per assistant message, never read). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
… + TASK_RUN_ID stamp Port of sorcerai/mods f25011b (July extension-runtime work) onto the post-rewrite architecture (SessionTools owns tool state). Re-targeted for the rewritten session layer: - Extension runtime actions (createTaskExtensionRuntimeActions) spread into the task executor's ExtensionActions alongside setLabel; runtimeMode and refreshRegisteredTools are required (fail-closed provenance), wired at all production initialize sites (runtime-init, acp-agent, extension-ui-controller, executor). - Session-layer semantics ported into SessionTools instead of July's agent-session restructure: #extensionTools canonical snapshots with constructor seeding, refreshExtensionTools with collision/replacement/ idempotency checks and scoped rollback, tool-mutation revision counter. - Vibe-mode desired-baseline model: transactional activate/deactivate/ removePreservingActive with capture/restore; live set stays restricted to required+vibe during transitions; queued changes update the desired set. - MCP membership is ownership-based (mcpManagerToolNames ∪ extensionMcpTools) instead of name-pattern; same-name manager tools still dedup via the stable winner; only collisions with non-MCP-owned registry entries throw. - Arktype compat for the newer arktype/omptype: callable detection accepts apply OR rootApply, extended internal-key list, symbol-key presence fingerprints. Parameter schema snapshots stay detached but NOT deep-frozen: the wire-schema post-processor (toolWireSchema) mutates nested nodes in place, so frozen subtrees silently killed model requests.
Token files now accept a grant map of tokens to {principal, role, sessions}
records, resolved server-side on every request so rotated grants apply
without a restart. Session-scoped gates cover MCP session requests, peer
discovery, mesh message origin, inbox claims, and waits; /v1/peers POST
and /v1/audit require a supervisor. Bare-token files keep full authority
as one supervisor; malformed grant files authenticate nobody. The four
ADR authority proofs run as regression tests.
…ries Prime chains session_info/session_state/agent_status/git_state/ child_usage_attributed entries into the parent lineage like any other entry; the importer dropped them without re-linking children, silently losing every entry after the first state entry in ordinary v0.9.3 data. Children now re-link to their nearest projected ancestor, the latest session_info name imports as the session title, and the session header git field plus the markdown settings block stop registering as unknown-field losses.
packages/prime-bridge is a workspace package, but no CI bucket listed it, so none of its suites ever ran in CI. The per-caller authority work adds authority.test.ts and grants.test.ts — the four ADR re-opening proofs plus grant parsing — and without a bucket entry those pass locally and are gated by nothing. Add it to fastWorkspacePackages: 120 tests, ~12s, no native addon needed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
Two Node-vs-Bun runtime divergences made every Prime destination apply fail wholesale (all items 'lost' with destination-apply-failed) under Bun 1.4, which CI pins: - fs.opendir Dir handles are auto-closed when async iteration ends (including early break/throw), so skillTreeDigest's explicit close() in finally threw ERR_DIR_CLOSED; Node keeps the handle open and expects the close. The close is now tolerant of already-closed. - bun:sqlite fileControl rejects typed-array arguments smaller than 8 bytes, so the SQLITE_FCNTL_HAS_MOVED identity assertion failed with a 4-byte Int32Array and every credential open aborted as 'credential destination changed during open'; pass 8 bytes and keep reading the moved flag at index 0.
SQLite stamps a newly created `-wal`/`-shm` with the database file's mode at creation time. `SqliteAuthCredentialStore.open()` chmods the database to 0600 only after `new Database(dbPath)`, so on a first run under the common umask 022 the companions are created at 0644 — and `-shm` survives later opens, staying world-readable indefinitely. Beyond the permissions themselves, this breaks Prime migration: the importer's `probeCredentialStore` rejects a non-private companion as an unsafe credential companion, which fails the credential probe and aborts the whole apply with `destination-invalid`, leaving sessions and settings unimported. A fresh omp install is exactly the state a user migrates from. Restrict the database and its `-wal`/`-shm`/`-journal` companions together on every open, so an install created that way heals itself. Verified end to end: a fresh install (agent.db 0600, companions 0644) fails `omp import prime --apply` with `destination-invalid`; after one open with this change the companions are 0600 and the same import exits 0 with the session and setting imported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
fix: Prime destination apply under Bun 1.4.x
… to 0600 fix(ai): restrict credential database SQLite companions to 0600
…h store PR #16 chmod'd the credential database and its SQLite companions, but only from `SqliteAuthCredentialStore.open()`. On a fresh install that path never runs: `AgentStorage.open()` is what creates `agent.db` on a bare `omp config list`, and it chmods nothing. So a brand-new install still ended up with 600 agent.db 644 agent.db-wal 644 agent.db-shm leaving `-shm` world-readable and still failing `omp import prime --apply` with `destination-invalid` — the exact case #16 set out to fix. Move the helper to `@oh-my-pi/pi-utils` as `restrictAgentDbPermissions()` and call it from both openers. agent.db holds `auth_credentials`, so 0600 is the right floor regardless of which store opened it first. Verified: a fresh `HOME` running `omp config list` now yields 0600 for the database and both companions, and the previously failing import exits 0 with credential, session, and setting all imported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
The Codex backend version-gates model availability against the pinned client version on both `/models?client_version=` and `/responses`. The fork pinned 0.144.1, and `gpt-6-astra` requires >= 0.153.0, so the backend silently hid it from discovery — a refresh could never surface it. Ports the relevant parts of upstream 95ebc4f: - Bump `CODEX_CLIENT_VERSION` to 0.153.0. - Send `x-codex-routing-hint` (`model=<slug>`, plus `;tier=` when a service tier is set) on Codex Responses, WebSocket handshake, and remote-compaction requests. The bump and this header ship together upstream: the newer client version is what the server expects the hint alongside. - Standardize the Codex `originator` header to `omp`. - Skip an account whose credential the backend rejected (401/403) during multi-account discovery instead of letting it veto every sibling's models. - Add the Astra compat rule: documented 1.05M window floor (discovery still reports a stale 272K/872K pair), credit-equivalent pricing, free cache writes. Ungated by design — Astra carries no long-context surcharge. Deliberately not ported: the commit's bundled `models.json` regeneration (this fork's copy has independent drift and already carries the OpenAI-side Astra entry) and `openai-configuration-update.ts` (absent here). Verified against the live backend: `openai-codex/gpt-6-astra` now appears in discovery at 1,050,000 ctx, and a real turn returns correctly. Regression-checked `openai-codex/gpt-5.6-luna` first, since the pin gates `/responses` for every Codex model — it still answers. catalog 884/884, agent 532/532, ai codex suites 261/261; tsgo clean for catalog, ai, and agent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8cbkqQyPiwEBPyqkqAHYz
feat(catalog,ai,agent): support openai-codex/gpt-6-astra
fix: restrict agent.db companions from every opener, not just the auth store
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ports the per-caller bridge authority model onto the v18 prime-bridge, and fixes three Prime importer data-loss bugs found auditing against prime-agent v0.9.3.
Per-caller bridge authority
{ "<token>": { principal, role: "supervisor" | "worker", sessions: string[] } }. A bare token file parses as one full-authority supervisor, so legacy deployments keep working unchanged./mcp/v1/sessions/<id>authenticates and checks the session grant before delegating to thehandleV1hook (403 ungranted, 404 no host)./v1/peersGET filters both OMP and Prime peer lists to the caller's granted sessions;/v1/peersPOST and/v1/auditGET require supervisor./v1/messagesPOST requires a grant onoriginSessionId(a worker cannot forge the apparent sender)./v1/inboxand/v1/waitrequire a grant ontargetId(an ungatedpeek=falseclaim could drain and deny another target's delivery).test/authority.test.ts): session-allowlisted discovery, administrative refusal of unprivileged callers, fail-closed unknown credentials, and non-self-assertable authority (forgedx-principal/x-role/role/x-omp-capabilityheaders and path-encoded session names cannot escalate). Grants parsing has its own unit tests (test/grants.test.ts).Prime importer fixes (vs prime-agent v0.9.3)
session_state,agent_status,git_state,child_usage_attributed,session_info) into the session parent lineage like any other entry. The importer dropped them without re-linking children, so every entry after the first state entry was silently lost on ordinary v0.9.3 data. Children now re-link to their nearest projected ancestor.session_infowas unsupported); the latestsession_infoname now imports as the session title.gitfield and themarkdownsettings block (mermaid,codeBlockIndent) no longer register as unknown-field losses.Verification
packages/prime-bridge: 120/120 tests pass (17 new authority/grants tests + all pre-existing).packages/coding-agentprime surfaces: parser tests 54/54 including the new state-chain regression; skills/source/bridge-client/lifecycle/external-peers 69/69.test/prime-import-destination.test.ts+test/prime-import.test.tshave 10 failures identical to pristine upstream-canonical main (d852215edc) — pre-existing, byte-for-byte the same set; no new failures introduced.npm run check(biome + tsgo + cargo) exits 0.Note: the original branch also gated a
/v1/tool-hostWebSocket upgrade behind the supervisor role; this port has no tool-host surface, so that proof has no route to exercise. The/mcp/v1/sessions/gate is in place for when tool hosting returns viahandleV1.