@sema-agent/sdk 11.3.0 → 12.0.1

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.
Files changed (51) hide show
  1. package/README.md +111 -0
  2. package/dist/control-types.d.ts +12 -10
  3. package/dist/control-types.d.ts.map +1 -1
  4. package/dist/control-types.js +1 -1
  5. package/dist/control-types.js.map +1 -1
  6. package/dist/errors.d.ts +9 -1
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +11 -3
  9. package/dist/errors.js.map +1 -1
  10. package/dist/events.d.ts +10 -0
  11. package/dist/events.d.ts.map +1 -1
  12. package/dist/events.js.map +1 -1
  13. package/dist/health.d.ts +120 -6
  14. package/dist/health.d.ts.map +1 -1
  15. package/dist/health.js +58 -1
  16. package/dist/health.js.map +1 -1
  17. package/dist/index.d.ts +13 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +6 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/registry/auth.d.ts +36 -16
  22. package/dist/registry/auth.d.ts.map +1 -1
  23. package/dist/registry/auth.js +17 -4
  24. package/dist/registry/auth.js.map +1 -1
  25. package/dist/registry/errors.d.ts +6 -5
  26. package/dist/registry/errors.d.ts.map +1 -1
  27. package/dist/registry/errors.js +6 -5
  28. package/dist/registry/errors.js.map +1 -1
  29. package/dist/registry/index.d.ts +3 -3
  30. package/dist/registry/index.js +3 -3
  31. package/dist/registry/scopes-effective.d.ts +34 -6
  32. package/dist/registry/scopes-effective.d.ts.map +1 -1
  33. package/dist/registry/scopes-effective.js +2 -2
  34. package/dist/registry/scopes-effective.js.map +1 -1
  35. package/dist/resources/approvals.d.ts +11 -0
  36. package/dist/resources/approvals.d.ts.map +1 -1
  37. package/dist/resources/approvals.js.map +1 -1
  38. package/dist/resources/sessions.d.ts +40 -1
  39. package/dist/resources/sessions.d.ts.map +1 -1
  40. package/dist/resources/sessions.js +48 -0
  41. package/dist/resources/sessions.js.map +1 -1
  42. package/dist/resources/tool-approvals.d.ts +80 -14
  43. package/dist/resources/tool-approvals.d.ts.map +1 -1
  44. package/dist/resources/tool-approvals.js +49 -1
  45. package/dist/resources/tool-approvals.js.map +1 -1
  46. package/dist/types.d.ts +172 -10
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js.map +1 -1
  49. package/openapi.yaml +395 -12
  50. package/package.json +2 -2
  51. package/registry-openapi.yaml +6 -5
package/openapi.yaml CHANGED
@@ -2322,6 +2322,106 @@ paths:
2322
2322
  '422': { $ref: '#/components/responses/UnprocessableEntity' }
2323
2323
  '501': { $ref: '#/components/responses/NotImplemented' }
2324
2324
 
2325
+ /v1/sessions/{sessionId}/background:
2326
+ parameters:
2327
+ - $ref: '#/components/parameters/PrincipalHeader'
2328
+ - in: path
2329
+ name: sessionId
2330
+ required: true
2331
+ schema: { type: string }
2332
+ get:
2333
+ tags: [sessions]
2334
+ operationId: sessionsBackgroundList
2335
+ x-status: live # S-745 (server 7.102.0; core 7.32.0 #1107); SDK sessions.background.
2336
+ summary: The session's background tasks (the exit sheet's "keeps running / will stop" material).
2337
+ description: >
2338
+ S-745 (server >= 7.102.0; core 7.32.0 #1107; contract §16 "embedded-shape contract"; mint
2339
+ `src/http/routes/background.ts`). 200 `{ rows }` — each row is core `TaskRegistry.list()`'s row projected
2340
+ KEY BY KEY by an explicit whitelist (`task_id` renamed `id`; `toolUseId` / `updatedAt` deliberately
2341
+ stripped). Only THIS session's rows: the access tuple is the session's own `{owner: sid, sessionId: sid,
2342
+ scope}` and visibility is core's fail-closed `canAccess` (the session's session-resident shells, the run row
2343
+ whose task id is the session id, workflows this session started, background agents rooted at this
2344
+ session). `retained` rides ONLY when true (core's retain predicate: env / task lane / row mark) — present =
2345
+ "keeps running" on the exit sheet; absent = an `includeRetained:false` stop WILL stop it. `description` is
2346
+ the model's description, falling back to the launch command text (content family: redacted, cut at 500
2347
+ chars). At most 500 rows (core `list()`'s own cap). 🔴 IN-PROCESS: only rows on THIS replica.
2348
+ Zero model work: not billable, not refused by drain. Gates (same family as `mcp/reconnect`): 501
2349
+ `capability.session_ownership_required` (no `sessionStorage.ownerOf`) · 404 `not_found.session` — unknown
2350
+ session AND someone else's session answer the SAME code and SAME message (no existence oracle); an EXPLICIT
2351
+ operator may read any session · 400 `request.path_malformed`. Probe with `capabilities.background.listFace`;
2352
+ ABSENT key = an older server, where this path is 404 `not_found.route` (same status, different code).
2353
+ responses:
2354
+ '200':
2355
+ description: The session's background rows (read the row schema for the `retained` / `status` readings).
2356
+ content:
2357
+ application/json:
2358
+ schema: { $ref: '#/components/schemas/SessionBackgroundList' }
2359
+ '400': { $ref: '#/components/responses/BadRequest' }
2360
+ '401': { $ref: '#/components/responses/Unauthorized' }
2361
+ '404': { $ref: '#/components/responses/NotFound' }
2362
+ '501': { $ref: '#/components/responses/NotImplemented' }
2363
+
2364
+ /v1/sessions/{sessionId}/background/stop:
2365
+ parameters:
2366
+ - $ref: '#/components/parameters/PrincipalHeader'
2367
+ - in: path
2368
+ name: sessionId
2369
+ required: true
2370
+ schema: { type: string }
2371
+ post:
2372
+ tags: [sessions]
2373
+ operationId: sessionsBackgroundStop
2374
+ x-status: live # S-745 (server 7.102.0; core 7.32.0 #1107); SDK sessions.backgroundStop.
2375
+ summary: Stop the session's background tasks — soft, then one grace, then a synchronous hard kill; receipts are complete before 200.
2376
+ description: >
2377
+ S-745 (server >= 7.102.0; contract §16; mint `src/http/routes/background.ts`). The SAME session-level
2378
+ convergence function as the `DELETE /v1/sessions/{sessionId}` cascade: SOFT (core's session anchor SIGTERMs
2379
+ and settles the session's background agents / workflows; every still-running shell row the hard face will
2380
+ revisit gets a per-row soft stop — with `includeRetained:true` the retained live services receive SIGTERM
2381
+ here too) → GRACE (the hard face waits until every row it will revisit is past "its soft-stop instant +
2382
+ `HOST_BG_KILL_GRACE_MS`", default 1000 ms; nothing to wait for ⇒ no wait) → HARD (core
2383
+ `killAllBackgroundShellsNow` — a synchronous process-group SIGKILL; a shell ignoring SIGTERM does not
2384
+ survive it). 🔴 THE RECEIPTS ARE COMPLETE BEFORE THE 200: with background rows the answer is one grace
2385
+ slower — budget the shell's exit wait in seconds.
2386
+ Body `{ includeRetained }` is REQUIRED with NO default (core's rule: the caller states which kind of stop
2387
+ this is): `true` = also stop the explicitly retained live services (the shell's "Exit and stop tasks");
2388
+ `false` = keep them (they come back as `retained_skipped`; `sema kill`'s session-level reap). The body
2389
+ gate is STRICT — absent / non-boolean / an extra key ⇒ 400 `request.body_shape`.
2390
+ Receipts carry SHELL rows only (`background_bash` / `monitor`); `outcome` is core's four words passed
2391
+ through VERBATIM — `killed` (a live process group was reaped now) · `already_gone` (already exited, or
2392
+ already hard-killed — incl. exiting within the grace) · `retained_skipped` (kept by
2393
+ `includeRetained:false`) · `no_pgid` (NO synchronous hard kill landed: remote / sandbox lanes have no
2394
+ host-local process group — e2b / k8s·kata / local-docker / ssh / device / adb always answer it — or win32 /
2395
+ a refused signal; core already sent an ordinary kill ⇒ "MAY STILL BE RUNNING", neither a failure nor ever
2396
+ "stopped").
2397
+ 🔴 CREDENTIAL-GATED (server >= 7.102.0 as released): on a worker with no service credential
2398
+ (`SERVICE_AUTH_TOKEN(S)`) and without `ALLOW_UNAUTHED_WRITES`, this path answers 503
2399
+ `auth.service_token_required` BEFORE routing (same code and sentence as every other mutating door) — the
2400
+ principal header is self-asserted there, and stopping background processes is irreversible.
2401
+ `capabilities.background.exitFaces` does NOT include "credentials ready" (the same family gap as the
2402
+ `memoryCompliance` row) — branch on that code. Other gates as the list path: 501
2403
+ `capability.session_ownership_required` · 404 `not_found.session` (unknown and foreign sessions alike) · 400
2404
+ `request.path_malformed`; this path is rate-limited (429). NOT called by run cancel (Esc): session-resident
2405
+ background shells live across turns (CC parity). A delegated helper's shells hang on the helper's own
2406
+ session and are out of this door's reach. Probe with `capabilities.background.exitFaces`.
2407
+ requestBody:
2408
+ required: true
2409
+ content:
2410
+ application/json:
2411
+ schema: { $ref: '#/components/schemas/SessionBackgroundStopRequest' }
2412
+ responses:
2413
+ '200':
2414
+ description: The receipts (shell rows only). Read `no_pgid` as "may still be running".
2415
+ content:
2416
+ application/json:
2417
+ schema: { $ref: '#/components/schemas/SessionBackgroundStopResult' }
2418
+ '400': { $ref: '#/components/responses/BadRequest' }
2419
+ '401': { $ref: '#/components/responses/Unauthorized' }
2420
+ '404': { $ref: '#/components/responses/NotFound' }
2421
+ '429': { $ref: '#/components/responses/RateLimited' }
2422
+ '501': { $ref: '#/components/responses/NotImplemented' }
2423
+ '503': { $ref: '#/components/responses/Unauthorized' } # `auth.service_token_required` — the credential-gated write door (no service credential and no ALLOW_UNAUTHED_WRITES), before routing.
2424
+
2325
2425
  /v1/sessions/{sessionId}/memory-status:
2326
2426
  parameters:
2327
2427
  - $ref: '#/components/parameters/PrincipalHeader'
@@ -3031,6 +3131,15 @@ paths:
3031
3131
  (REOPENED) and re-appears on `/v1/approvals`. SDK → ParkedResumeStartupError. Client action:
3032
3132
  re-fetch the pending list and decide again, fixing what was rejected. (Before 5.12.0 this shape
3033
3133
  collapsed into the 409 `decide.revive_rejected`.)
3134
+ 🔴 core 7.32.0 (#1110) ADDS A CAUSE (server >= 7.102.0; contract appendix A.1, MIGRATION 7.102.0): an
3135
+ `approve` on a child parked on an INHERITED tool (a tool family the child inherits from the scenario
3136
+ layer — the task tools, WebFetch …) whose redemption cannot hand over the inherited seat ⇒ core refuses
3137
+ BEFORE consuming the approval: the approval stays PENDING and a `deny` still settles it. From server 7.102.0
3138
+ a ONE-LEVEL row (its root session = the parent session, and that root session STILL belongs to this card's
3139
+ tenant) is redeemed with the seat re-resolved from the root session, so it no longer lands here; a DEEPER
3140
+ (grandchild) row, or one whose root session was deleted / changed owner, still does (core #1112 pending) —
3141
+ render it as "this card can only be denied / wait for a server upgrade". Not a regression: 7.31.x children
3142
+ never had those tools.
3034
3143
  content:
3035
3144
  application/json:
3036
3145
  schema: { $ref: '#/components/schemas/ErrorResponse' }
@@ -3854,6 +3963,23 @@ paths:
3854
3963
  NOT strict (hand-written parser, unknown keys are ignored), so an older server answers 200 and
3855
3964
  records nothing. Bit absent = old server, do not offer the field. Bit present ⇒ read the
3856
3965
  per-call truth from the ack's `noteRecorded`.
3966
+ readRootGrant:
3967
+ type: string
3968
+ minLength: 1
3969
+ description: >-
3970
+ S-720 (server >= 7.102.0 / core 7.32.0 #1093), ADDITIVE — "Yes, and add directory": the frame's
3971
+ `readRootCandidate.dir` sent back BYTE FOR BYTE (a STRING — never normalised, cut or composed; not an
3972
+ object). Beside `allow` it also adds that directory to THIS RUN's read directories (read faces only).
3973
+ 🔴 `decision:"allow"` ONLY — on `allow_session` / `deny` the server refuses BEFORE the decision with 400
3974
+ `request.body_shape` (the card stays open; answer the same `approvalId` again). SHAPE gate: a non-empty
3975
+ string of at most core's `READ_ROOT_CANDIDATE_DIR_MAX`, else the same 400 (an over-long value is refused
3976
+ whole, never cut — a cut directory is another directory). The server judges SHAPE, never VALUE: whether
3977
+ it equals the card's string is the ENGINE's call, and the verdict arrives only as an `engine_notice` —
3978
+ `approval.read_root_granted` (the run's read roots really widened) or `approval.read_root_grant_rejected`
3979
+ (nothing changed; the decision stands). The 200 never says which. Reach: THIS RUN only (the ask row has no
3980
+ such column, so replay / failover / durable resume do not carry it) and THIS DOOR only (the durable
3981
+ `/decide` and the in-stream `…/asks/{askId}/decision` doors do not read it). An older server ignores the
3982
+ unknown key and answers 200 with a plain allow (no capability bit yet) — trust the notice.
3857
3983
  responses:
3858
3984
  '200':
3859
3985
  description: Ack (`decision` echoed).
@@ -6558,15 +6684,27 @@ components:
6558
6684
  rewindFiles:
6559
6685
  type: boolean
6560
6686
  description: >
6561
- CC Rewind parity (E18). On a NORMAL turn ⇒ CAPTURE a working-tree snapshot at turn end (per-turn, by leaf;
6562
- required so later rewinds have something to restore). On a resumeAt turn ⇒ RESTORE the tree to resumeAt's
6563
- snapshot ("both"). Needs a fileSnapshotStore wired (capabilities.rewindFiles).
6687
+ RETIRED SPELLING (the whole-tree snapshot epoch; S-15 / design/381, server >= 7.52 — note corrected in sdk
6688
+ 11.4.0, the same stale-note family as `rewindFilesTo`, board [8437] U3). Server `src/http/wire-types.ts`: still
6689
+ accepted on the wire — its capture sense (true, no resumeAt) is a tolerated no-op with a deprecation disclosure;
6690
+ its restore sense (true + resumeAt) is core's TYPED migration rejection naming `restoreFiles` (restore semantics
6691
+ really changed: whole tree ⇒ tracked set; the server never remaps it silently). Send `restoreFiles` (probe
6692
+ `capabilities.restoreFiles`); this key stays declared only for <= 7.51 servers.
6564
6693
  rewindFilesTo:
6565
6694
  type: string
6566
6695
  description: >
6567
- CC Rewind "code"-only (core 1.166.0 TaskSpec.rewindFilesTo). Restore the working tree to this user-message
6568
- entryId's snapshot WITHOUT forking the conversation (no setLeafId). Use instead of resumeAt+rewindFiles when
6569
- the user wants only files reverted. Target = a user-message SessionTreeEntry.id.
6696
+ CC Rewind "code"-only (core 1.166.0 TaskSpec.rewindFilesTo; server "R8"). Converge the files this session
6697
+ edited (the TRACKED set) to the history boundary at a prior USER message WITHOUT forking the conversation (the
6698
+ session leaf is untouched — only the files move). Use instead of resumeAt+restoreFiles when the user wants only
6699
+ files reverted. 🔴 The value is a HANDLE, not an entry id (corrected in sdk 11.4.0, board [8437] U3): the SAME
6700
+ kind of handle as `resumeAt`, resolved through the SAME anchor store — typically the `taskId` from that turn's
6701
+ 202 receipt (the server keys the user-message anchor by the run's taskId). Server `src/boot/resolve-spec.ts:686-697`:
6702
+ `resumeAnchorStore.resolve(sessionId, handle, principal)` → entry id; unknown handle ⇒ 404
6703
+ `rewind_files_to.unknown_event`; no session ⇒ 422 `rewind_files_to.no_session`; no anchor store / no getLeafId ⇒
6704
+ 501. ⚠️ The 501 is NOT the capability's whole predicate: `capabilities.rewindFilesTo` also requires the
6705
+ file-history store (capture face); without it the server does not 501 — core refuses in the run with
6706
+ `rewind.store_unconfigured` — so probe the bit first. Honored ONLY when `resumeAt` is absent. One-shot at submit
6707
+ (resume legs strip it, server >= 7.72.0).
6570
6708
  restoreFiles:
6571
6709
  type: boolean
6572
6710
  description: >-
@@ -8187,7 +8325,16 @@ components:
8187
8325
  with no explicit allowlist); ABSENT = an older server (degrade to not teaching, not validating).
8188
8326
  resumeAt: { type: boolean, description: "E18 resume-at-message anchors are resolvable." }
8189
8327
  rewindFiles: { type: boolean, description: "E19 working-tree snapshot/restore is wired." }
8190
- rewindFilesTo: { type: boolean, description: "Restore to a SPECIFIC entry id (not just the latest snapshot)." }
8328
+ rewindFilesTo:
8329
+ type: boolean
8330
+ description: >-
8331
+ Code-only rewind (`TaskRequest.rewindFilesTo`) is wired — mint `routes/capabilities.ts:839` =
8332
+ `Boolean(deps.fileHistoryStore && deps.resumeAnchorStore && deps.sessionStorage?.getLeafId)`: it needs the
8333
+ file-history store (to restore) AND the anchor map (to resolve the target HANDLE). Corrected in sdk 11.4.0
8334
+ (board [8437] U3): the store is the FILE-HISTORY store (not the pre-S-15 whole-tree snapshot store), and since
8335
+ server 7.97.0 (S-589) that seat is the CAPTURE face = backend AND the `FILE_HISTORY_CAPTURE` knob — a deployment
8336
+ that turns capture off reports this bit false together with `rewindFiles` / `restoreFiles` / `sessionSync`
8337
+ (and `fileHistoryCapture: "off"`).
8191
8338
  restoreFiles:
8192
8339
  type: boolean
8193
8340
  description: >-
@@ -8751,6 +8898,70 @@ components:
8751
8898
  properties:
8752
8899
  provider: { type: string, description: 'host | e2b | k8s | ssh | adb | local-docker | device — typed from the server''s RemoteExecProvider; `REMOTE_EXEC` unset ⇒ `host`.' }
8753
8900
  toolsOnThisHost: { type: boolean, description: 'The tools run on the process that answered this request (server-absolute paths mean something to the model''s tools).' }
8901
+ taskWriteFaceOpen:
8902
+ type: boolean
8903
+ description: >
8904
+ server >= 7.95.0 (S-591; value meaning refined at 7.96.0 / S-613; mint `routes/capabilities.ts:653` =
8905
+ `taskWriteFaceRefusal(deps.config) === undefined && autonomyOverrides(deps.config.autonomy).writeFace !== "roots"`)
8906
+ — DISCLOSURE BIT OF THE WRITE-CONTAINMENT FACE: does this deployment honour the task-level "open the write
8907
+ fence" declaration (`permissionMode:"bypassPermissions"` ⇒ `TaskSpec.writeFace:"open"`, writes outside the
8908
+ workspace roots)? `false` has two forms: (1) the hosted-posture gate refuses ⇒ sending that mode gets
8909
+ `422 request.host_posture_refused`; (2) the deployment runs `AUTONOMY=read-only|plan` ⇒ the request is
8910
+ accepted but the write face is clamped back to roots — the declaration silently does nothing. Three states
8911
+ are folded into one bit on purpose: the caller has exactly one decision (send that key or not); tier and
8912
+ evidence live in the refusal body and the operator's `GET /v1/diagnostics/wiring`. It speaks ONLY for the
8913
+ write-containment cell — the other two columns of `bypassPermissions` are unaffected.
8914
+ ABSENT = an older worker (<= 7.94) ⇒ read as `true` (contract appendix B.1: nothing refused it back then).
8915
+ taskApproverPosture:
8916
+ type: boolean
8917
+ description: >
8918
+ server >= 7.95.0 (S-591 leg ③; mint `routes/capabilities.ts:659` = `taskApproverPostureHonored(deps.config)`,
8919
+ the SAME predicate as the real consumer) — DISCLOSURE BIT OF `approverPosture`: does this deployment honour
8920
+ the submit body's host-posture statement ("this run's approval cards are auto-answered by the host
8921
+ itself")? `false` ⇒ the key is IGNORED (the request is still 202-accepted; the server logs
8922
+ `task_approver_posture_ignored`) — deliberately NOT refused: the resume legs replay the persisted body
8923
+ verbatim and the caller cannot remove it, so a refusal would brick a parked task forever. Same reach as
8924
+ the hosted-gate half of `taskWriteFaceOpen` (hosted posture ⇒ both false); `AUTONOMY=read-only|plan`
8925
+ only clears `taskWriteFaceOpen`, never this bit.
8926
+ ABSENT = an older worker (<= 7.94) ⇒ read as `true` (contract appendix B.1: it passed through back then).
8927
+ fileHistoryCapture:
8928
+ type: string
8929
+ enum: ['off', on-always]
8930
+ description: >
8931
+ server >= 7.97.0 (S-589; mint `routes/capabilities.ts:847` = `fileHistoryCaptureOf(deps.fileHistoryStore)`,
8932
+ closed word set owned by the server's `src/file-history-capture.ts` `FILE_HISTORY_CAPTURE_WORD_SET`) —
8933
+ CAN FILE-HISTORY CAPTURE BE TURNED OFF. Derived from the ASSEMBLY RESULT (capture face = backend AND the
8934
+ `FILE_HISTORY_CAPTURE` deployment knob), NOT an echo of the knob — a deployment without the backend is
8935
+ `off` too; the SAME judgement as `rewindFiles` / `restoreFiles` / `rewindFilesTo` / `sessionSync`.
8936
+ `off` = this deployment captures no first-touch snapshots and has no rewind / restore / code-only rewind /
8937
+ session-sync ⇒ render neither a "turn capture off" switch nor a rewind entry. `on-always` = capturing, and
8938
+ it CANNOT be turned off per session (core's first-touch capture is process-wide) ⇒ render one read-only true
8939
+ sentence, never a switch that cannot switch.
8940
+ 🔴 A third word `on-optional` ("this session may skip capture") is DELIBERATELY UNDECLARED by the server (it
8941
+ waits for a per-session no-capture seat in core); when it lands it is an additive server change and this
8942
+ enum grows with it. Keep a default arm (unknown word ⇒ treat as unknown, render no switch). Turning capture
8943
+ off does NOT delete what was already captured.
8944
+ ABSENT = an older worker (<= 7.96) ⇒ fall back to `rewindFiles` (`true` ⇒ `on-always`, `false` ⇒ `off`).
8945
+ background:
8946
+ type: object
8947
+ additionalProperties: true
8948
+ description: >
8949
+ server >= 7.102.0 (S-745 / core 7.32.0 #1107; mint `routes/capabilities.ts:308` = `{ listFace:
8950
+ sessionBackgroundFacesAvailable(deps), exitFaces: sessionBackgroundFacesAvailable(deps) }`) — presence of the
8951
+ session background-task doors: `listFace` = `GET /v1/sessions/{sessionId}/background`, `exitFaces` =
8952
+ `POST /v1/sessions/{sessionId}/background/stop` (contract §16). Both bits use the SAME predicate as the two
8953
+ doors' 501 (the session-ownership face `sessionStorage.ownerOf`), so "says yes but 501s" is structurally
8954
+ impossible; without it both bits are explicitly `false` and both doors answer 501
8955
+ `capability.session_ownership_required`. ENDPOINT-GATE FORM: `false` ⇒ do not call. True only promises the
8956
+ endpoint — not that this replica holds any background row of that session (the registry is in-process).
8957
+ ⚠️ `exitFaces` does NOT cover "credentials ready": on a worker with no service credential and without
8958
+ `ALLOW_UNAUTHED_WRITES` the bit is true while the stop door answers 503 `auth.service_token_required` —
8959
+ branch on that code (the same family gap as `memoryCompliance`). ABSENT = an older server (both doors 404)
8960
+ ⇒ the shell's exit dialog offers only "Stay / Exit", never "Exit and stop tasks".
8961
+ required: [listFace, exitFaces]
8962
+ properties:
8963
+ listFace: { type: boolean }
8964
+ exitFaces: { type: boolean }
8754
8965
  WriteProtectionCapability:
8755
8966
  type: object
8756
8967
  additionalProperties: false
@@ -10806,6 +11017,13 @@ components:
10806
11017
  sessionId: { type: string }
10807
11018
  requiresRealApproval: { type: boolean, enum: [true] }
10808
11019
  governanceForced: { type: boolean, enum: [true] }
11020
+ mandated: { type: boolean, enum: [true], description: 'server >= 7.101.0 (T4①): the mandated bit, same layer and shape as the two flags above (present only when true); the SAME value as `frame.mandated` (read once when the entry is minted).' }
11021
+ mandate:
11022
+ allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
11023
+ description: 'server >= 7.102.0 (S-721): which word the mandated bit stands on — same layer and shape as `mandated`, the SAME value as `frame.mandate`. Absence never names a word.'
11024
+ origin:
11025
+ allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
11026
+ description: 'server >= 7.102.0 (S-755 / cli L-695): WHO raised this ask, read once together with `frame.origin` when the entry is minted. The durable `pending[]` rows of the same response carry it top-level too — one reading for both row families. OPEN set (see AskOrigin).'
10809
11027
  fromSubagent: { type: boolean, enum: [true], description: 'The ask originates from a delegated subagent.' }
10810
11028
  originTaskId: { type: string, description: 'S-52 C2 (server ≥7.52, A-075.87): the delegated child taskId (= the child''s core runSourceTaskId, uuid) — correlates this live ask to the child run row. Minted by the SAME conditional spread as `fromSubagent`: the two keys are always both present or both absent (三键恒等亲证在案).' }
10811
11029
  contentKind: { type: string, description: 'S-62 (server >= 7.6x): content-question kind — `content_ask` when the gated tool is AskUserQuestion (the SAME word as the two durable read faces and core''s summarize face). Absent = an ordinary tool ask. Display/triage only; it NEVER takes part in decision routing.' }
@@ -11114,6 +11332,27 @@ components:
11114
11332
  presence may differ between the two legs for one ask. Derived from hot-reloadable governance knobs —
11115
11333
  long subscribers follow the stream's re-emitted frames. Absence ≠ "not governance-forced"; it means
11116
11334
  "no governance-origin evidence". Never written as false.
11335
+ # ── park-row facts (server `src/approval-card.ts` `ParkRowFacts` — the five facts core mints on the parked
11336
+ # `PendingAction.tool_approval` arm, projected by `parkRowFacts`, the SAME projection on both stores and on the
11337
+ # `/stream` `pending` frame). DISPLAY / TRIAGE projection, never a permission input; each present only when
11338
+ # true / a word. sdk 11.4.0 declares all five (the first three were already on the wire since 7.100.0 / 7.101.0).
11339
+ requiresRealApproval:
11340
+ type: boolean
11341
+ enum: [true]
11342
+ description: 'server >= 7.100.0 (S-700): this parked ask can only be cleared by a REAL HUMAN (core park-row twin seat, strict `=== true`). Absent = not marked, never "clearable without a person".'
11343
+ mandated:
11344
+ type: boolean
11345
+ enum: [true]
11346
+ description: 'server >= 7.101.0 (S-663 part 2 / core 7.31.0 #1079): the durable twin of the mandated bit (no rule can clear this ask). Independent of `requiresRealApproval` (which implies it) and `ruleOffersAbsence` — projected bit by bit, never inferred.'
11347
+ mandate:
11348
+ allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
11349
+ description: 'server >= 7.102.0 (S-721): which word the mandated bit stands on — the park-row twin seat read through `readClosedWordSeat(…, "mandate")` (core `isPersistedRuleMandate`); an out-of-set word reads as absent. Answers the same as the inbox row for the same row.'
11350
+ origin:
11351
+ allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
11352
+ description: 'server >= 7.102.0 (S-755 / cli L-695 / C-R111): WHO raised this ask — the park-row twin seat `PendingAction.tool_approval.origin` read through `readClosedWordSeat(…, "origin")` (core `isAskOrigin`). Same word as the live card frame and the inbox row. Absent = an old row (parked before core 7.5.0) or an out-of-set word — NOT "policy".'
11353
+ ruleOffersAbsence:
11354
+ allOf: [{ $ref: '#/components/schemas/RuleOffersAbsence' }]
11355
+ description: 'server >= 7.100.0 (S-700): WHY the park row offers no rule — the same narrow read and closed three-word set as the live card frame and `card_json`.'
11117
11356
  hasBidiControls:
11118
11357
  type: boolean
11119
11358
  enum: [true]
@@ -11220,6 +11459,20 @@ components:
11220
11459
  🔴 NEVER minted as `false` (the OMIT contract this row's other flags follow); absence is "not marked",
11221
11460
  never "confirmed clearable without a person". The value comes WHOLE from core (`summarizeCheckpoint`
11222
11461
  projects the park row's own bit) — the server neither recomputes nor redacts it.
11462
+ mandated:
11463
+ type: boolean
11464
+ enum: [true]
11465
+ description: >-
11466
+ server >= 7.101.0 (S-663 part 2 / core 7.31.0 #1079), ADDITIVE, present ONLY when true: the durable twin of
11467
+ the mandated bit (core `summarizeCheckpoint` screens the park row's `PendingAction.tool_approval.mandated`
11468
+ to a literal `true`; the server mints the key on strict `=== true`). Declared in sdk 11.4.0 — this schema is
11469
+ CLOSED, so before that a strict validator rejected every row that carried it.
11470
+ mandate:
11471
+ allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
11472
+ description: >-
11473
+ server >= 7.102.0 (S-721 / core 7.32.0 #1092): which word the mandated bit stands on (core
11474
+ `CheckpointSummary.mandate`, already screened by core's `isPersistedRuleMandate`; the server does not screen
11475
+ twice). Answers the same as the operator queue row for the same park row.
11223
11476
  denialLimitFallback:
11224
11477
  $ref: '#/components/schemas/DenialLimitFallback'
11225
11478
  description: >-
@@ -11849,6 +12102,73 @@ components:
11849
12102
  budgetMs: { type: integer }
11850
12103
  error: { type: string }
11851
12104
 
12105
+ SessionBackgroundRow:
12106
+ type: object
12107
+ description: >
12108
+ One row of `GET /v1/sessions/{sessionId}/background` (S-745, server >= 7.102.0; mint
12109
+ `src/http/routes/background.ts` `SessionBackgroundRow`) = core `TaskRegistry.list()`'s row projected key by
12110
+ key (`task_id` renamed `id`; `toolUseId` / `updatedAt` stripped). The three word sets are OWNED BY CORE
12111
+ (7.32.1 `SemaTaskType` / `SemaTaskStatus`), transcribed verbatim. 🔴 IN-PROCESS: only rows on this replica.
12112
+ Response projection: declared key by key AND open (additive keys between SDK releases must not make a legal
12113
+ row unreadable — the LivePendingRow ruling).
12114
+ additionalProperties: true
12115
+ required: [id, type, status, createdAt, sessionScoped]
12116
+ properties:
12117
+ id: { type: string, description: 'core `task_id` (renamed). A receipt''s `id` is the same value.' }
12118
+ description: { type: string, description: 'The model''s description, falling back to the launch command text (core keeps no separate raw command). Content family: redacted, cut at 500 characters. UNTRUSTED for display.' }
12119
+ type: { type: string, enum: [background_bash, workflow, background_agent, monitor], description: 'core `SemaTaskType`.' }
12120
+ status: { type: string, enum: [pending, running, parked, completed, failed, killed, cancelled], description: 'core `SemaTaskStatus` (`parked` = a background agent suspended on a pending approval — neither live nor terminal).' }
12121
+ createdAt: { type: integer, description: 'Registration time (epoch ms).' }
12122
+ sessionScoped: { type: boolean, description: '`true` = session-resident (lives across turns); `false` = run-scoped.' }
12123
+ retained:
12124
+ type: boolean
12125
+ enum: [true]
12126
+ description: >-
12127
+ core's retain predicate (env declaration / task lane / row mark — any ⇒ kept) — present ONLY when true,
12128
+ never minted as false, and only ever on a shell row (`background_bash` / `monitor`; core `list()` row
12129
+ doc). Present = "keeps running" on the exit sheet; absent = an `includeRetained:false` stop WILL stop it.
12130
+ SessionBackgroundList:
12131
+ type: object
12132
+ description: '`GET /v1/sessions/{sessionId}/background` 200 body (contract §16). An idle session answers `{ rows: [] }`.'
12133
+ additionalProperties: true
12134
+ required: [rows]
12135
+ properties:
12136
+ rows:
12137
+ type: array
12138
+ items: { $ref: '#/components/schemas/SessionBackgroundRow' }
12139
+ SessionBackgroundStopRequest:
12140
+ type: object
12141
+ description: >
12142
+ `POST /v1/sessions/{sessionId}/background/stop` body — server `StopBodySchema = z.object({ includeRetained:
12143
+ z.boolean() }).strict()`: EXACTLY this key, REQUIRED, NO default. `true` = also stop explicitly retained live
12144
+ services ("Exit and stop tasks"); `false` = keep them (`retained_skipped`). Absent / non-boolean / an extra
12145
+ key ⇒ 400 `request.body_shape`.
12146
+ additionalProperties: false
12147
+ required: [includeRetained]
12148
+ properties:
12149
+ includeRetained: { type: boolean }
12150
+ SessionBackgroundReceipt:
12151
+ type: object
12152
+ description: >
12153
+ One receipt of the stop door — SHELL rows only (`background_bash` / `monitor`). `outcome` = core 7.32.1
12154
+ `BackgroundShellHardKillReceipt.outcome` (`BackgroundHardKillOutcome` ∪ `retained_skipped`), passed through
12155
+ VERBATIM: `killed` / `already_gone` (both = "this row is reaped") · `retained_skipped` (kept, process alive) ·
12156
+ `no_pgid` (no synchronous hard kill landed — MAY STILL BE RUNNING; never render it as stopped).
12157
+ additionalProperties: true
12158
+ required: [id, outcome]
12159
+ properties:
12160
+ id: { type: string, description: 'The row id (core taskId).' }
12161
+ outcome: { type: string, enum: [killed, already_gone, retained_skipped, no_pgid] }
12162
+ SessionBackgroundStopResult:
12163
+ type: object
12164
+ description: '`POST /v1/sessions/{sessionId}/background/stop` 200 body. The receipts are COMPLETE before the 200 (soft → grace → hard is awaited).'
12165
+ additionalProperties: true
12166
+ required: [receipts]
12167
+ properties:
12168
+ receipts:
12169
+ type: array
12170
+ items: { $ref: '#/components/schemas/SessionBackgroundReceipt' }
12171
+
11852
12172
  # ── 2c session-sync (P1d) — the cloud-as-a-SYNC-PEER schemas ──────────────────────────────────────────────
11853
12173
  SyncEntry:
11854
12174
  type: object
@@ -13651,6 +13971,17 @@ components:
13651
13971
  spec-resolver, which now passes the notice seat). Consequence for consumers that assert on ledger
13652
13972
  CONTENTS: a resume leg's ledger MAY now carry one extra `engine_notice` row it did not before — assert
13653
13973
  "may appear", never an exact row count or order (and consume idempotently: reconnect replay shows it again).
13974
+ `approval.read_root_granted` / `approval.read_root_grant_rejected` (server >= 7.102.0 / S-720 / core 7.32.0
13975
+ #1093) — the ENGINE's verdict on a `readRootGrant` answer (POST /v1/tool-approvals/{id}/respond), at most one
13976
+ frame per answered ask. GRANTED = this run's read directories really include it now (core: the ONLY evidence the
13977
+ run widened; read faces only, this run only) — `{dir, covers?, root, toolName, toolCallId, sessionId, runId,
13978
+ taskId?}`, `root` = the canonical spelling the engine holds. REJECTED = nothing changed and the decision stands
13979
+ (say so plainly) — `{reason, offered?, requested?, toolName, toolCallId, sessionId, runId, taskId?}`, `reason` one of
13980
+ core's eight words (`on_refusal` / `not_a_string` / `no_candidate` / `mismatch` / `unresolvable` /
13981
+ `resolves_elsewhere` / `admits_artifact_store` — the directory contains, lies inside or is the local artifact
13982
+ store; unreachable on a server 7.102.0 deployment, which wires no artifact host — / `no_read_roots`), passed
13983
+ through verbatim by the server (echo-only, not enumerated) — read it as an OPEN set. `toolCallId` joins to the
13984
+ `tool_approval` frame.
13654
13985
  `delegation.ask_unresolvable` (server >= 7.69.0 / core 7.10.0 #648) — an `ask` reached a FINAL DENY with
13655
13986
  NOBODY having ruled on it: the approver consulted for the call answered `unavailable` and no durable park
13656
13987
  caught it afterwards. The deny itself is unchanged (`tool_end.gate.settlement.kind:"approver_unavailable"`
@@ -14324,8 +14655,18 @@ components:
14324
14655
  description: >
14325
14656
  (server >= 7.93.0, core 7.26.0 #997) This card was MANDATED — a read-station / rule-lane forced ask (a rule can
14326
14657
  never clear it; an approver's yes cannot release a deny-listed read). Present only when true, literal `true`;
14327
- absent = an ordinary ask. The durable parked row carries no twin bit: read `ruleOffersAbsence: "mandated"` there
14328
- (the same fact on the durable face).
14658
+ absent = an ordinary ask. ⚠️ CORRECTED (sdk 11.4.0): the durable parked row DOES carry a twin bit since core
14659
+ 7.31.0 #1079 (`PendingAction.tool_approval.mandated`), projected since server 7.101.0 onto the operator queue
14660
+ row / the `/stream` `pending` frame / the inbox row (S-663 part 2) and the `livePending` row top level (T4①)
14661
+ — four faces, one bit. `card_json` does not carry it (`ApprovalCardSchema` is `.strict()`).
14662
+ mandate:
14663
+ allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
14664
+ description: >-
14665
+ server >= 7.102.0 (S-721 / core 7.32.0 #1092), "tool_approval" only, ADDITIVE — which word the `mandated`
14666
+ bit stands on (server `src/tool-approval.ts:841`, read through `readClosedWordSeat(req, "mandate")` =
14667
+ core's `isPersistedRuleMandate` screen). Present only when the WHOLE cause of `mandated:true` is that one
14668
+ word; absence never names a word and is not "not mandated". Same value on the `livePending` row, the
14669
+ operator queue row and the inbox row; NOT on `card_json` / `approval_request`.
14329
14670
  denialLimitFallback: { $ref: '#/components/schemas/DenialLimitFallback' }
14330
14671
  parked:
14331
14672
  type: boolean
@@ -14627,6 +14968,13 @@ components:
14627
14968
 
14628
14969
  The SAME type is the `origin` member of `GateOutcome` on `tool_end` — one vocabulary, two faces.
14629
14970
 
14971
+ server >= 7.102.0 (S-755 / cli L-695 / C-R111): the word now also rides the `livePending` row top level
14972
+ (read once with the frame's) and the operator queue row (`GET /v1/approvals` `pending[]` + the `/stream`
14973
+ `pending` frame — the park-row twin seat, screened by core's `isAskOrigin`), besides the frame and the inbox
14974
+ row — five faces, one word. `card_json` / the `approval_request` frame still do not carry it (the card is
14975
+ `.strict()`). The eleven known words are exported at runtime as the SDK's `ASK_ORIGINS` (core 7.32.1
14976
+ `ASK_ORIGINS`, verbatim and in order) — known words, NOT an enforcement table.
14977
+
14630
14978
  RuleOffersAbsence:
14631
14979
  type: string
14632
14980
  enum: [mandated, shadowed, lane_cannot_speak]
@@ -14644,6 +14992,26 @@ components:
14644
14992
  server-side narrow read, so both faces carry identical values; a word outside the set is treated as
14645
14993
  malformed and the key is not minted at all (the server never passes an unknown word through).
14646
14994
 
14995
+ PersistedRuleMandate:
14996
+ type: string
14997
+ enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, write_protection_unresolved]
14998
+ description: >
14999
+ WHICH WORD a mandated ask stands on (server >= 7.102.0 / S-721 / core 7.32.0 #1092) — core's
15000
+ `PERSISTED_RULE_MANDATES` six words, transcribed verbatim and in order (core 7.32.1
15001
+ `dist/core/ask-origin.d.ts:349`; the vocabulary's owner is core). Rides FOUR faces with one value: the
15002
+ `tool_approval` frame, the `livePending` row top level, the operator queue row (`GET /v1/approvals`
15003
+ `pending[]` + the `/v1/approvals/stream` `pending` frame) and the inbox row. NOT on `card_json` / the
15004
+ `approval_request` frame (live or reconnect replay — `ApprovalCardSchema` is `.strict()`), same as `mandated`.
15005
+ 🔴 A TRUE CLOSED SET, deliberately unlike `AskOrigin`: on every face the server screens it through core's
15006
+ `isPersistedRuleMandate` (`approval-card.ts` `readClosedWordSeat`; the inbox face is screened by core's own
15007
+ `summarizeCheckpoint`) and an out-of-set word reads as ABSENT, never on the wire.
15008
+ 🔴 ABSENCE NEVER NAMES A WORD and is NOT "not mandated": another door (governance / hook / ancestor) or more
15009
+ than one reason ⇒ absent; whether the ask is mandated is `mandated`. For an ENGINE-MINTED value, present ⇒
15010
+ `mandated` is true (core: present ⇔ that word is the bit's WHOLE reason); the converse does not hold. ⚠️ On the
15011
+ durable faces (queue row / inbox row) the server projects the two seats INDEPENDENTLY (it does not bind `mandate`
15012
+ to `mandated`, `approval-card.ts` `readClosedWordSeat`), so a hand-edited or generation-skewed row may carry one
15013
+ without the other — read `mandated` for the bit, never infer it from this word. Echo-only — the server never
15014
+ branches on the word.
14647
15015
  DenialLimitKind:
14648
15016
  type: string
14649
15017
  enum: [consecutive, total]
@@ -15199,14 +15567,15 @@ components:
15199
15567
  type: object
15200
15568
  description: >
15201
15569
  Decision-maker identity assertion (design/171 §5.1; the cross-repo source of truth is
15202
- `@sema-agent/registry-core` ActorAssertionWire — the SDK holds a value copy).
15570
+ `@sema-agent/settings-schema` ActorAssertionWire — the SDK holds a value copy; the package was named
15571
+ `@sema-agent/registry-core` before 1.0.0).
15203
15572
 
15204
15573
  NORMATIVE, not a style note: an ACTOR NEVER PARTICIPATES IN THE PERMISSION DECISION — authority always
15205
15574
  belongs to the principal; this shape exists only for audit/echo/presentation. `id` is ALWAYS server-minted
15206
15575
  (= the verified principal; an auth-off deployment mints the `"_"` sentinel), and a wire requester may
15207
15576
  submit ONLY `label`.
15208
15577
  required: [id]
15209
- additionalProperties: false # registry-core's ActorAssertionWire is .strict()
15578
+ additionalProperties: false # settings-schema's ActorAssertionWire is .strict()
15210
15579
  properties:
15211
15580
  id: { type: string, minLength: 1, maxLength: 256, description: 'Server-minted principal ("_" sentinel when auth is off). Never submittable by the requester.' }
15212
15581
  label: { type: string, maxLength: 256, description: 'Unverified display text — the ONLY field a requester may submit (server redacts + bounds it). UNTRUSTED.' }
@@ -15217,7 +15586,7 @@ components:
15217
15586
  description: >
15218
15587
  Audit axis for which authorization path accepted the decision: `owner` (row owner) or `operator`
15219
15588
  (explicit operator seat). CLOSED — verbatim-equal to the owning schema
15220
- (registry-core ActorAssertionWire). Widening it here without widening the owner is copy drift.
15589
+ (settings-schema ActorAssertionWire). Widening it here without widening the owner is copy drift.
15221
15590
 
15222
15591
  AskDecisionBody:
15223
15592
  type: object
@@ -15866,6 +16235,20 @@ components:
15866
16235
  SAME projection as the `GET /v1/approvals` row (`projectPendingForWire`), declared here explicitly so
15867
16236
  a stream consumer sees it typed instead of through the open index signature. Present ONLY when true;
15868
16237
  absence = "not detected", never "confirmed clean" (see PendingCheckpoint.hasBidiControls).
16238
+ # sdk 11.4.0 (che-OV adversarial review [low] F5): the `pending` frame spreads the PendingCheckpoint row and the
16239
+ # `live_pending` frame (server >= 7.87.0) spreads the LivePendingRow — so the rows' park-row facts / mandate bit /
16240
+ # origin word ride these frames with the same names and values. Declared for the same reason as hasBidiControls.
16241
+ requiresRealApproval: { type: boolean, enum: [true], description: '`pending` / `live_pending` frames — see PendingCheckpoint / LivePendingRow.requiresRealApproval.' }
16242
+ mandated: { type: boolean, enum: [true], description: '`pending` / `live_pending` frames (server >= 7.101.0) — see the row schemas.' }
16243
+ mandate:
16244
+ allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
16245
+ description: '`pending` / `live_pending` frames (server >= 7.102.0 / S-721) — see PendingCheckpoint.mandate / LivePendingRow.mandate.'
16246
+ origin:
16247
+ allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
16248
+ description: '`pending` / `live_pending` frames (server >= 7.102.0 / S-755) — see PendingCheckpoint.origin / LivePendingRow.origin. OPEN set.'
16249
+ ruleOffersAbsence:
16250
+ allOf: [{ $ref: '#/components/schemas/RuleOffersAbsence' }]
16251
+ description: '`pending` frames only (server >= 7.100.0 / S-700) — see PendingCheckpoint.ruleOffersAbsence.'
15869
16252
 
15870
16253
  ParkedDecideAccepted:
15871
16254
  type: object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/sdk",
3
- "version": "11.3.0",
3
+ "version": "12.0.1",
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",
@@ -52,6 +52,6 @@
52
52
  "prepublishOnly": "rm -f tsconfig.tsbuildinfo && npm run build && npm run typecheck --workspaces=false --prefix ../.. && npm test --workspaces=false --prefix ../.."
53
53
  },
54
54
  "devDependencies": {
55
- "@sema-agent/registry-core": "^0.17.1"
55
+ "@sema-agent/settings-schema": "^5.0.0"
56
56
  }
57
57
  }
@@ -4,7 +4,8 @@ info:
4
4
  version: "0.1.0"
5
5
  description: >
6
6
  ⚠️ AUTHORITY POSTURE (read first): the registry SERVER lives in the sema-registry repo (web AI);
7
- the machine contract single-source is `@sema-agent/registry-core` (zod schemas + path constants —
7
+ the machine contract single-source is `@sema-agent/settings-schema` (renamed from
8
+ `@sema-agent/registry-core` at 1.0.0, 2026-08-26; zod schemas + path constants —
8
9
  AUTH_V1_PATHS/SCOPES_V1_PATHS etc.; the SDK keeps value-copies with same-source anchor tests).
9
10
  THIS file documents the surface the SDK's registry subpath actually calls, so a consumer generating
10
11
  a client from spec sees the full face — it mirrors, it does not rule. Backfilled 2026-07-28 from
@@ -12,7 +13,7 @@ info:
12
13
  `registry-spec-path-gate.test.ts` (reflective: every /api path the SDK hits must be here, zero baseline).
13
14
  USER-PLANE paths carry real request/response shapes; the ADMIN family (RegistryAdmin, user-JWT
14
15
  role-gated — "admin" is a registry-side ROLE, not a separate credential) is documented loose
15
- (operator tooling; shapes live in registry-core/zod and the registry server).
16
+ (operator tooling; shapes live in settings-schema/zod and the registry server).
16
17
  x-sdk-subpath: "@sema-agent/sdk/registry"
17
18
  paths:
18
19
  /api/healthz:
@@ -27,7 +28,7 @@ paths:
27
28
  post:
28
29
  operationId: registryDeviceCode
29
30
  summary: Start the device-authorization flow (requestDeviceCode).
30
- requestBody: { required: false, content: { application/json: { schema: { type: object, additionalProperties: true, description: 'registry-core DeviceCodeRequest (open: client metadata).' } } } }
31
+ requestBody: { required: false, content: { application/json: { schema: { type: object, additionalProperties: true, description: 'settings-schema DeviceCodeRequest (open: client metadata).' } } } }
31
32
  responses:
32
33
  '200':
33
34
  description: '{device_code, user_code, verification_uri(_complete)?, interval, expires_in}.'
@@ -36,7 +37,7 @@ paths:
36
37
  post:
37
38
  operationId: registryDeviceToken
38
39
  summary: Poll the device flow (pollUntilApproved's leg).
39
- requestBody: { required: true, content: { application/json: { schema: { type: object, required: [grant_type, device_code], properties: { grant_type: { type: string, description: 'The RFC 8628 device grant type constant (registry-core DEVICE_GRANT_TYPE).' }, device_code: { type: string } } } } } }
40
+ requestBody: { required: true, content: { application/json: { schema: { type: object, required: [grant_type, device_code], properties: { grant_type: { type: string, description: 'The RFC 8628 device grant type constant (settings-schema DEVICE_GRANT_TYPE).' }, device_code: { type: string } } } } } }
40
41
  description: >
41
42
  OAuth device-token semantics: `authorization_pending` keeps the interval, `slow_down` adds +5s,
42
43
  `access_denied`/`expired_token` are terminal (typed errors in the SDK). Success = the token pair.
@@ -85,7 +86,7 @@ paths:
85
86
  operationId: registryScopesList
86
87
  summary: List the caller's scopes (listScopes; `?counts=` optional).
87
88
  responses:
88
- '200': { description: 'ScopesListResponse (registry-core schema).', content: { application/json: { schema: { type: object, additionalProperties: true } } } }
89
+ '200': { description: 'ScopesListResponse (settings-schema schema).', content: { application/json: { schema: { type: object, additionalProperties: true } } } }
89
90
  post:
90
91
  operationId: registryScopesCreate
91
92
  summary: 'ADMIN: create a scope/space.'