Skip to content

feat(prime-bridge): per-caller bridge authority + Prime v0.9.3 importer fixes - #2

Open
sorcerai wants to merge 1009 commits into
unsigned-gg:mainfrom
sorcerai:feat/prime-bridge-authority-v18
Open

sorcerai wants to merge 1009 commits into
unsigned-gg:mainfrom
sorcerai:feat/prime-bridge-authority-v18

Conversation

@sorcerai

@sorcerai sorcerai commented Sep 6, 2026

Copy link
Copy Markdown

Fork-to-fork PR: this branch sits on top of sorcerai/oh-my-pi main, which includes the v18.0.11 upstream port. Your main was last pushed 2026-08-24, so the diff here also carries that port; the actual change being proposed is the two commits at the tip: feat(prime-bridge): enforce per-caller authority and fix(coding-agent): re-link Prime sessions past daemon bookkeeping entries.

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 files accept a grant map: { "<token>": { principal, role: "supervisor" | "worker", sessions: string[] } }. A bare token file parses as one full-authority supervisor, so legacy deployments keep working unchanged.
  • The token file is re-read per request, so grant rotation applies without a restart; a malformed grant file authenticates nobody (fail closed). Authority is resolved server-side only — nothing in headers, body, or path can widen it.
  • Gates:
    • /mcp/v1/sessions/<id> authenticates and checks the session grant before delegating to the handleV1 hook (403 ungranted, 404 no host).
    • /v1/peers GET filters both OMP and Prime peer lists to the caller's granted sessions; /v1/peers POST and /v1/audit GET require supervisor.
    • /v1/messages POST requires a grant on originSessionId (a worker cannot forge the apparent sender).
    • /v1/inbox and /v1/wait require a grant on targetId (an ungated peek=false claim could drain and deny another target's delivery).
  • The four ADR re-opening proofs run as regression tests (test/authority.test.ts): session-allowlisted discovery, administrative refusal of unprivileged callers, fail-closed unknown credentials, and non-self-assertable authority (forged x-principal/x-role/role/x-omp-capability headers 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)

  • Prime chains daemon bookkeeping entries (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.
  • User-renamed Prime sessions lost their names (session_info was unsupported); the latest session_info name now imports as the session title.
  • The session header git field and the markdown settings 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-agent prime 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.ts have 10 failures identical to pristine upstream-canonical main (d852215edc) — pre-existing, byte-for-byte the same set; no new failures introduced.
  • Full npm run check (biome + tsgo + cargo) exits 0.

Note: the original branch also gated a /v1/tool-host WebSocket 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 via handleV1.

can1357 and others added 30 commits August 28, 2026 05:30
…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
sorcerai and others added 30 commits September 2, 2026 10:35
- 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
… 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
…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
fix(compaction): let per-turn tool-output pruning reclaim age victims once the cache is cold
feat(coding-agent): advisors status-line segment
local mods: extension runtime actions + subagent directives injection + TASK_RUN_ID stamp
feat(ai): claude-code provider via the Claude Agent SDK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.