@sema-agent/sdk 15.2.0 → 15.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +24 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/resources/runs.d.ts +12 -2
- package/dist/resources/runs.d.ts.map +1 -1
- package/dist/resources/runs.js +8 -2
- package/dist/resources/runs.js.map +1 -1
- package/dist/settings.d.ts +8 -1
- package/dist/settings.d.ts.map +1 -1
- package/dist/types.d.ts +54 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openapi.yaml +129 -5
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -677,7 +677,8 @@ paths:
|
|
|
677
677
|
(non-owner → 404, no existence leak; missing principal → 401). All responses are synchronous ACKs; actual
|
|
678
678
|
termination is async (same-replica immediate; cross-replica ≈30s via the heartbeat tick). A cancelled run
|
|
679
679
|
settles to `status` failed + `errorCode` "cancelled" (NO new status — distinguish via errorCode; the UI
|
|
680
|
-
shows "cancelled", not an error).
|
|
680
|
+
shows "cancelled", not an error). From server >= 7.112.0 the cancelled terminal also carries
|
|
681
|
+
`abortCause: "cancel_verb"` (see `TaskResult.abortCause`; `errorCode` "cancelled" is unchanged). A SUSPENDED (or `needs_review`) run IS cancellable here — the server
|
|
681
682
|
settles its pending checkpoint (CAS `expire`, the reaper's "≈ deny" terminal — deliberately not a
|
|
682
683
|
resume, since cancel means the run dies) and THEN terminalizes the row, releasing the session claim;
|
|
683
684
|
the ack is 202. (Corrected 2026-07-31: this paragraph used to say "409 — cancel it by DENYING its
|
|
@@ -1057,7 +1058,8 @@ paths:
|
|
|
1057
1058
|
responses:
|
|
1058
1059
|
'200':
|
|
1059
1060
|
description: >
|
|
1060
|
-
Queued/applied. Body `{ taskId, target, status, delivery, marker, note }`
|
|
1061
|
+
Queued/applied. Body `{ taskId, target, status, delivery, marker, note }` (+ `messageId` from server >= 7.111.0,
|
|
1062
|
+
see `SubagentSteerReceipt`) — `note` carries the
|
|
1061
1063
|
CC-verbatim "Message queued for delivery to <name> at its next tool round." receipt copy.
|
|
1062
1064
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1063
1065
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
@@ -1074,6 +1076,18 @@ paths:
|
|
|
1074
1076
|
description: 'errorCode "steer.content_too_large" — content over the per-steer cap; shorten and resend (retrying verbatim never succeeds).'
|
|
1075
1077
|
'429': { $ref: '#/components/responses/RateLimited' } # (declared 2026-07-31) rateLimited||quotaExceeded||leaseDenied all gate this verb (routes/runs.ts)
|
|
1076
1078
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
1079
|
+
'503':
|
|
1080
|
+
description: >-
|
|
1081
|
+
errorCode "steering.ledger_unavailable" (server >=7.111.0, S-966) — a subagent steer enters the same
|
|
1082
|
+
user-input ledger as a run steer (ONE rule: the ledger covers an input whose receipt promised delivery and
|
|
1083
|
+
whose carrying engine stream lives in a run leg of this server), written BEFORE the 200; the ledger could not
|
|
1084
|
+
be written (local data root not writable / SQL unreachable). The subagent received NOTHING. Client action:
|
|
1085
|
+
retry the SAME content later. SDK: `SteeringLedgerUnavailableError`. The sibling `…/resume` verb never
|
|
1086
|
+
takes this arm (a resume starts a new child leg; it does not feed an in-flight queue). Before 7.111.0 this
|
|
1087
|
+
verb wrote no ledger row and never answered 503 for it.
|
|
1088
|
+
content:
|
|
1089
|
+
application/json:
|
|
1090
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1077
1091
|
|
|
1078
1092
|
/v1/runs/{taskId}/compact:
|
|
1079
1093
|
parameters:
|
|
@@ -7551,7 +7565,8 @@ components:
|
|
|
7551
7565
|
`wiring_manifest` frame — test with `'wiringManifest' in result`, never `=== undefined`). The run's
|
|
7552
7566
|
boot-time wiring receipt: the `wiring_manifest` frame (minted after wiring, before the first turn)
|
|
7553
7567
|
projected by the SAME projector as the streaming leg (tenant face strips operator-only sections; an
|
|
7554
|
-
explicit operator gets the full face
|
|
7568
|
+
explicit operator gets the full face; server >=7.111.0 carries the self-minted `instructions` section here
|
|
7569
|
+
too, same present-iff reading as `Event_wiring_manifest.instructions`). NOT current state — runtime roster changes ride
|
|
7555
7570
|
`tool_roster_delta` frames. Shells judge a zero-tool run by `tools.count === 0`.
|
|
7556
7571
|
terminal:
|
|
7557
7572
|
allOf: [{ $ref: '#/components/schemas/TerminalCause' }]
|
|
@@ -7641,6 +7656,52 @@ components:
|
|
|
7641
7656
|
verdict: { type: string, enum: [PASS, FAIL, PARTIAL, unverified] }
|
|
7642
7657
|
rounds: { type: integer }
|
|
7643
7658
|
findings: { type: array, items: { type: string } }
|
|
7659
|
+
abortCause:
|
|
7660
|
+
allOf: [{ $ref: '#/components/schemas/AbortCause' }]
|
|
7661
|
+
description: >
|
|
7662
|
+
server >= 7.112.0 (S-947; cli L-212; contract §5.0d; additive) — the machine-readable CAUSE of a SERVER-INITIATED
|
|
7663
|
+
abort, a side key beside `cancelContext` (it is NOT inside `terminal`: `terminal` is the engine's cause, and one
|
|
7664
|
+
object must not have two minters). PRESENT-IFF this result IS the cancelled terminal the server minted for that
|
|
7665
|
+
abort (`terminal.kind: "failed"` + `terminal.code: "cancelled"`); a server >= 7.112.0 always stamps it on the
|
|
7666
|
+
cancelled terminal it mints (the mint's cause parameter is mandatory; the engine never mints `cancelled` itself).
|
|
7667
|
+
🔴 It sits BESIDE the cancel code and never replaces it: the row's `errorCode` column / `terminal.code`
|
|
7668
|
+
(`"cancelled"`) stays the "this is a cancel" discriminant, unchanged — this key only answers "who made it stop".
|
|
7669
|
+
ABSENT (not a cancelled terminal the server minted for its own abort): a detach disconnect
|
|
7670
|
+
(`x-detach-on-disconnect: true`, the server does not abort); the engine's own failure; a normal completion;
|
|
7671
|
+
`POST /v1/runs/{taskId}/interrupt` (terminal `completed` + `haltedByUser`); a park (including a #241 grace park);
|
|
7672
|
+
a terminal that RACED the abort (the engine finished first / failed with its own code — "fill the empty seat
|
|
7673
|
+
only": code, snapshot and cause are all left off together); a resume leg cancelled BEFORE its approved action
|
|
7674
|
+
started (the engine rules `resume.reopened_unstarted` and the park reopens — the run was not ended); a
|
|
7675
|
+
preempt (`paused`); an orderly shutdown or a dead-holder reap.
|
|
7676
|
+
🔴 A cancelled row persisted by a server before 7.112.0 has NO `abortCause` and is never back-filled: a row with
|
|
7677
|
+
`errorCode: "cancelled"` and the key absent = cause NOT RECORDED — do not fold it into any word.
|
|
7678
|
+
Four landings, one value: `GET /v1/runs/{taskId}` -> `result.abortCause` (beside `result.cancelContext`) ·
|
|
7679
|
+
`POST /v1/tasks/stream` -> `done.result.abortCause` · the `POST /v1/tasks` 200 body, at its TOP LEVEL (the body IS
|
|
7680
|
+
the result, contract §5.0c) · `GET /v1/runs/{taskId}/events` -> the `done` row's `result.abortCause`; a cancelled
|
|
7681
|
+
shape with NO `done` row to land on (a disconnect after which no done was read / the leg aborted before its
|
|
7682
|
+
terminal threw) lands on the `failed` row at its TOP LEVEL instead (`Event_failed.abortCause`, beside `errorCode`).
|
|
7683
|
+
Two wire VALUE changes ride the same release (not new keys): a resume leg cancelled AFTER the approved action
|
|
7684
|
+
started now ends `failed` + `errorCode: "cancelled"` + a `cancelContext` snapshot + `abortCause: "cancel_verb"`
|
|
7685
|
+
(before 7.112.0 it ended `failed` with NO code); an interactive `POST /v1/tasks/stream` that read no `done` and
|
|
7686
|
+
was NOT aborted by the server now ends with the honest failure sentence `stream ended before a terminal event`
|
|
7687
|
+
(no code, no `abortCause`; before 7.112.0 it was always minted as a "client disconnected" cancelled terminal).
|
|
7688
|
+
|
|
7689
|
+
AbortCause:
|
|
7690
|
+
type: string
|
|
7691
|
+
enum: [client_disconnected, ask_park_grace_exhausted, cancel_verb]
|
|
7692
|
+
description: >
|
|
7693
|
+
The closed three-word vocabulary of `abortCause` (server >= 7.112.0 / S-947; contract §5.0d) — who initiated a
|
|
7694
|
+
server-side abort. Each word has one real site: `client_disconnected` — a non-detach `POST /v1/tasks/stream` client
|
|
7695
|
+
disconnect while no in-stream ask was pending, aborted at once ("the connection dropped, the run was aborted" — not an
|
|
7696
|
+
engine error); `ask_park_grace_exhausted` — the same disconnect arm but an in-stream ask WAS pending: the server first
|
|
7697
|
+
turns the ask into a park through the window-expiry path and gives the engine a bounded grace (10 s) to finish
|
|
7698
|
+
parking, and the park still had not landed when the grace ran out, so the run was aborted; `cancel_verb` —
|
|
7699
|
+
`POST /v1/runs/{taskId}/cancel` (the same-replica fast path, a cross-replica durable cancel flag polled by the holding
|
|
7700
|
+
replica on any of the four legs — interactive stream / non-streaming / background / resume —, and a parked run the
|
|
7701
|
+
verb finalizes directly; the cause is the same word). First come, first served: a leg is aborted once, and the first
|
|
7702
|
+
landing names the word — a cancel verb arriving after a disconnect, or a disconnect after a cancel, never rewrites it.
|
|
7703
|
+
CLOSED set, additive-only by the server's rule (a new word is a new server version in `wire-changes` AND a new SDK
|
|
7704
|
+
minor, in this enum in the same batch): read an unknown word as "the server aborted this run, cause not recognised".
|
|
7644
7705
|
|
|
7645
7706
|
LegacyPlaneTaskResult:
|
|
7646
7707
|
type: object
|
|
@@ -12223,7 +12284,9 @@ components:
|
|
|
12223
12284
|
the server had answered 200 `applied` (interrupt{text}: 202) but the process carrying that run died
|
|
12224
12285
|
before the run settled; whether the run consumed them is NOT known (see `engine_notice`
|
|
12225
12286
|
`task.user_steer_undrained{cause:"crashed"}`). Converged rows only, one row per (taskId, messageId),
|
|
12226
|
-
newest 500.
|
|
12287
|
+
newest 500. From server >=7.111.0 (S-966) the rows include SUBAGENT steers (recorded under the run on the
|
|
12288
|
+
receipt; same row shape, `kind` is still only `steer`; `messageId` = the subagent steer receipt's).
|
|
12289
|
+
ABSENT = this read has nothing to report (zero rows, or the ledger could not be read —
|
|
12227
12290
|
the authoritative notice is the frame on the run stream); the `?message=` single-entry form never
|
|
12228
12291
|
carries it.
|
|
12229
12292
|
items:
|
|
@@ -14348,6 +14411,23 @@ components:
|
|
|
14348
14411
|
(`capabilities.rewindFiles`); only a run the REQUEST word turned off cannot restore itself.
|
|
14349
14412
|
OPEN on read: the server does not enumerate the word (a present non-string is dropped), a third word passes
|
|
14350
14413
|
through — treat it as unknown. ABSENT = an older engine / external derivation, never "capturing".
|
|
14414
|
+
instructions:
|
|
14415
|
+
allOf: [{ $ref: '#/components/schemas/WiringManifestInstructions' }]
|
|
14416
|
+
description: >
|
|
14417
|
+
server >= 7.111.0 (S-961; cli L-910; contract appendix G.21b) — SELF-MINTED by the server (core's
|
|
14418
|
+
`WiringManifest` has no such section; the server adds it beside core's own, and a core section of the
|
|
14419
|
+
same name would be a compile error server-side). TENANT and OPERATOR faces alike; rides the live frame, the
|
|
14420
|
+
durable ledger row and the sync receipt's `wiringManifest`. Which PROJECT-INSTRUCTION FILE the project-memory
|
|
14421
|
+
loader selected on THIS leg's own prepare: the chain `CLAUDE.md` > `.claude/CLAUDE.md` > `AGENTS.md` >
|
|
14422
|
+
`.claude/AGENTS.md` (first hit wins; a present-but-EMPTY `CLAUDE.md` is still the selected one and shadows
|
|
14423
|
+
`AGENTS.md`), each member spelled as the chain spells it, relative to the cwd.
|
|
14424
|
+
🔴 TWO MEANINGS, never fold them: the key ABSENT = this leg makes NO statement about instruction files
|
|
14425
|
+
(no loader wired — `PROJECT_MEMORY_ENABLED=false`, or the multi-user `REQUIRE_PRINCIPAL=true` form —, a
|
|
14426
|
+
hand-less leg, a cwd that is not a local absolute directory, a delegated subagent leg, or a server older
|
|
14427
|
+
than 7.111.0) — it does NOT mean "there is no instruction file". PRESENT with `selected: []` = the leg
|
|
14428
|
+
walked the chain and selected nothing. Today at most one member is sent (first hit wins); read it as a list.
|
|
14429
|
+
The segment reports what the model read at this leg's prepare, not the disk now (a resume leg reports the
|
|
14430
|
+
session snapshot). Not on `GET /v1/diagnostics/wiring` (a per-leg fact; the static half never mints it).
|
|
14351
14431
|
eventId: { type: string }
|
|
14352
14432
|
parentToolCallId: { type: string }
|
|
14353
14433
|
sourceTaskId: { type: string }
|
|
@@ -16601,6 +16681,8 @@ components:
|
|
|
16601
16681
|
type: object
|
|
16602
16682
|
# 封闭 + 回填 `activeTaskId`(census 轴一,2026-07-30):[1833] G10 —— session 已有活跃 run 的冲突
|
|
16603
16683
|
# 失败形会带上占用者 taskId(SDK events.ts 早已声明,spec 侧漏)。
|
|
16684
|
+
# server 7.112.0(S-947;sdk 15.4.0 / K-42):+`abortCause`(没有 done 可落的取消形的成因落在本行顶层)。封闭对象不声明它,server 的真 `failed` 行对 15.3.0 spec 就是
|
|
16685
|
+
# 「$ must NOT have additional properties」—— 门 6 契约套抓不到这一件,由 `test/server-7112-wire.test.ts` P2(真 `buildCancelledLedgerRow` × spec)抓。
|
|
16604
16686
|
additionalProperties: false
|
|
16605
16687
|
required: [type]
|
|
16606
16688
|
properties:
|
|
@@ -16608,6 +16690,16 @@ components:
|
|
|
16608
16690
|
errorCode: { type: string }
|
|
16609
16691
|
errorMessage: { type: string }
|
|
16610
16692
|
activeTaskId: { type: string, description: '冲突失败形:当前占着该 session 的 run —— 消费方可直接引导 cancel/attach。' }
|
|
16693
|
+
abortCause:
|
|
16694
|
+
allOf: [{ $ref: '#/components/schemas/AbortCause' }]
|
|
16695
|
+
description: >
|
|
16696
|
+
server >= 7.112.0 (S-947; contract §5.0d) — the cause of a cancelled shape that has NO `done` row to carry
|
|
16697
|
+
`result.abortCause` (a disconnect after which no done was read / the leg was aborted before its terminal threw),
|
|
16698
|
+
landing at this row's TOP LEVEL beside `errorCode` (the cancelled shape's `errorCode` is `"cancelled"`, unchanged).
|
|
16699
|
+
Same closed words and the same present-iff gate as `TaskResult.abortCause`: PRESENT-IFF this row is the cancelled
|
|
16700
|
+
shape the server minted for its own abort. A `failed` row WITHOUT `errorCode` / `abortCause` (only
|
|
16701
|
+
`errorMessage`, e.g. `stream ended before a terminal event`) is an honest failure and is NOT a cancel — never
|
|
16702
|
+
read it as "disconnected". A cancelled row persisted before 7.112.0 has no `abortCause` (cause not recorded).
|
|
16611
16703
|
|
|
16612
16704
|
# ══════════════════════════════════════════════════════════════════════════════════════════════
|
|
16613
16705
|
# 🔴 census 轴一(2026-07-30)补的**四个未登记臂**。它们不是「将来会有」——**今天就在 wire 上**:
|
|
@@ -17470,7 +17562,7 @@ components:
|
|
|
17470
17562
|
🔴 ONE RULE FOR EVERY "EFFECTIVE HALF ONLY" KEY (sdk 9.7.0, after a codex adversarial-review [high]):
|
|
17471
17563
|
this schema's only consumer today is `GET /v1/diagnostics/wiring`'s `static` half, and every key marked
|
|
17472
17564
|
"effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `hooks`, `lsp`,
|
|
17473
|
-
`modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`) is ALWAYS ABSENT on that
|
|
17565
|
+
`modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`, `instructions`) is ALWAYS ABSENT on that
|
|
17474
17566
|
wire ⇒ THEIR ABSENCE HERE CARRIES NO INFORMATION. The per-key absence readings ("absent = not armed",
|
|
17475
17567
|
"absent = a third state", …) hold for the LIVE FRAME (`Event_wiring_manifest`) and must not be carried
|
|
17476
17568
|
over to this response. For the facts behind those keys: a tenant reads
|
|
@@ -17651,6 +17743,13 @@ components:
|
|
|
17651
17743
|
K-24 (server >= 7.104.0 / S-724) — does this leg capture file history (`on` / `disabled`, OPEN word). EFFECTIVE
|
|
17652
17744
|
HALF ONLY ⇒ ALWAYS ABSENT ON THIS ENDPOINT; the deployment-level reading is `capabilities.fileHistoryCapture`.
|
|
17653
17745
|
Full per-key contract: see Event_wiring_manifest.fileHistory.
|
|
17746
|
+
instructions:
|
|
17747
|
+
allOf: [{ $ref: '#/components/schemas/WiringManifestInstructions' }]
|
|
17748
|
+
description: >
|
|
17749
|
+
server >= 7.111.0 (S-961) — SELF-MINTED by the server, PER-LEG: the instruction file the loader selected on one leg's
|
|
17750
|
+
own prepare. EFFECTIVE HALF ONLY ⇒ ALWAYS ABSENT ON THIS ENDPOINT (a deployment has no per-leg selection to report).
|
|
17751
|
+
🔴 DO NOT read absence here as "no instruction file" — it carries no information on this wire. Full per-key
|
|
17752
|
+
contract: see Event_wiring_manifest.instructions.
|
|
17654
17753
|
WiringManifestWriteProtection:
|
|
17655
17754
|
# sdk 9.7.0:与 `WiringManifestMcpEntry` / `WiringManifestLspSeam` 同一条裁定 —— 同一段形被 live 帧与
|
|
17656
17755
|
# 静态诊断面两处引用,内联就是两份会各自漂的镜像,所以具名单源。
|
|
@@ -17698,6 +17797,23 @@ components:
|
|
|
17698
17797
|
enum: [true]
|
|
17699
17798
|
description: "core's ONLY present shape — the construct gate refuses an armed-but-unrunnable state, so this is a SHAPE, not a value."
|
|
17700
17799
|
|
|
17800
|
+
WiringManifestInstructions:
|
|
17801
|
+
# S-961(server 7.111.0):与 `WiringManifestReadDeny` / `WiringManifestAutoConsolidation` 同一条裁定 —— 同一段形被 live 帧与静态诊断面两处引用,
|
|
17802
|
+
# 内联就是两份会各自漂的镜像,所以具名单源(`spec-field-drift-gate` 也按「导出的 interface 必有同名 schema」逼出它)。
|
|
17803
|
+
type: object
|
|
17804
|
+
additionalProperties: false
|
|
17805
|
+
description: >
|
|
17806
|
+
The `wiring_manifest.instructions` section (server >= 7.111.0 / S-961) — SELF-MINTED by the server, not a core
|
|
17807
|
+
section: which project-instruction file the project-memory loader selected on this leg's own prepare.
|
|
17808
|
+
`selected` members are a CLOSED four-word set — the server's instruction-file chain (`INSTRUCTION_FILE_CHAIN`,
|
|
17809
|
+
registered in its self-minted wire table `wiringInstructionsSelected`); a fifth chain member would be a new SDK minor,
|
|
17810
|
+
in this enum in the same batch. The present-iff / two-meanings reading is on `Event_wiring_manifest.instructions`.
|
|
17811
|
+
required: [selected]
|
|
17812
|
+
properties:
|
|
17813
|
+
selected:
|
|
17814
|
+
type: array
|
|
17815
|
+
description: 'The selected chain member(s), spelled as the chain spells them (relative to the cwd); `[]` = the chain was walked, nothing was selected.'
|
|
17816
|
+
items: { type: string, enum: ['CLAUDE.md', '.claude/CLAUDE.md', 'AGENTS.md', '.claude/AGENTS.md'] }
|
|
17701
17817
|
WiringManifestHookEntry:
|
|
17702
17818
|
# sdk 9.5.0:与 `WiringManifestMcpEntry` 同一条裁定 —— 同一份行形被 live 帧与静态诊断面两处引用,
|
|
17703
17819
|
# 内联就是两份会各自漂的镜像,所以一开始就具名。
|
|
@@ -18011,6 +18127,14 @@ components:
|
|
|
18011
18127
|
delivery: { type: string, description: 'Literal "applied" on today''s server.' }
|
|
18012
18128
|
note: { type: string, description: 'The CC-verbatim queued copy ("Message queued for delivery to <name>…").' }
|
|
18013
18129
|
marker: { type: string, description: 'Engine-minted delivery marker (present on both steer and resume 200s, server 1.214+).' }
|
|
18130
|
+
messageId:
|
|
18131
|
+
type: string
|
|
18132
|
+
description: >
|
|
18133
|
+
server >= 7.111.0 (S-966) — the STEER 200 only (absent on the `…/resume` 200 and on an older server): the id of
|
|
18134
|
+
this acceptance in the server's user-input ledger (uuidv7) — the SAME value a later
|
|
18135
|
+
`GET /v1/sessions/{id}` `userInputUndrained[].messageId` carries should the carrying server process die
|
|
18136
|
+
before the run settles. The same ledger write that guards a run steer guards a subagent steer: when it
|
|
18137
|
+
cannot be written the verb answers 503 `steering.ledger_unavailable` and the subagent got nothing.
|
|
18014
18138
|
|
|
18015
18139
|
SubagentOutputResult:
|
|
18016
18140
|
type: object
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.4.0",
|
|
4
4
|
"description": "Typed, zero-runtime-dependency SDK for the Sema agent fleet usage plane. The shared substrate for all doors (CC/Codex MCP façade + web). Server-side only — tokens never enter the browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|