@sema-agent/server 7.136.0 → 7.138.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.
Files changed (327) hide show
  1. package/MIGRATION.md +501 -139
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +149 -34
  5. package/deploy/sema-up/README.md +14 -0
  6. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +21 -14
  9. package/dist/approval-card.js +1 -0
  10. package/dist/approval-content-kind.d.ts +6 -0
  11. package/dist/approval-content-kind.js +7 -0
  12. package/dist/approval-gate-currency.d.ts +48 -6
  13. package/dist/approval-gate-currency.js +16 -9
  14. package/dist/approval-hmac.d.ts +13 -1
  15. package/dist/approval-hmac.js +1 -1
  16. package/dist/approval.js +3 -3
  17. package/dist/audit.js +1 -0
  18. package/dist/auth-bridge.js +2 -2
  19. package/dist/background-agent-name.d.ts +5 -0
  20. package/dist/background-agent-name.js +5 -0
  21. package/dist/boot/budget-tracing.d.ts +1 -12
  22. package/dist/boot/deployment-mods.d.ts +46 -16
  23. package/dist/boot/deployment-mods.js +82 -6
  24. package/dist/boot/execution-env.d.ts +24 -1
  25. package/dist/boot/execution-env.js +69 -6
  26. package/dist/boot/governance-seams.d.ts +10 -17
  27. package/dist/boot/governance-seams.js +5 -17
  28. package/dist/boot/leader.d.ts +3 -0
  29. package/dist/boot/leader.js +1 -0
  30. package/dist/boot/org-delivery.js +15 -2
  31. package/dist/boot/reapers.d.ts +3 -0
  32. package/dist/boot/reapers.js +15 -1
  33. package/dist/boot/resolve-spec.d.ts +7 -0
  34. package/dist/boot/resolve-spec.js +36 -26
  35. package/dist/boot/retention-lane.d.ts +11 -5
  36. package/dist/boot/retention-lane.js +2 -2
  37. package/dist/boot/runner-deps.d.ts +7 -3
  38. package/dist/boot/runner-deps.js +1 -0
  39. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  40. package/dist/boot/stage-04-stores.d.ts +2 -13
  41. package/dist/boot/stage-05-execution-env.d.ts +6 -13
  42. package/dist/boot/stage-05-execution-env.js +17 -5
  43. package/dist/boot/stage-06-runners.d.ts +6 -13
  44. package/dist/boot/stage-06-runners.js +10 -3
  45. package/dist/boot/stage-07-capability-layer.d.ts +7 -13
  46. package/dist/boot/stage-07-capability-layer.js +3 -3
  47. package/dist/boot/stage-08-reapers.d.ts +7 -13
  48. package/dist/boot/stage-08-reapers.js +2 -1
  49. package/dist/boot/stage-09-leader.d.ts +7 -13
  50. package/dist/boot/stage-09-leader.js +2 -2
  51. package/dist/boot/stage-10-http-server.d.ts +7 -13
  52. package/dist/boot/stage-10-http-server.js +6 -3
  53. package/dist/boot/stores.d.ts +1 -1
  54. package/dist/boot/web-admin.d.ts +5 -2
  55. package/dist/boot/web-admin.js +3 -3
  56. package/dist/brain.js +5 -5
  57. package/dist/broker/broker.d.ts +89 -0
  58. package/dist/broker/broker.js +287 -0
  59. package/dist/broker/constants.d.ts +39 -0
  60. package/dist/broker/constants.js +15 -0
  61. package/dist/broker/http1.d.ts +111 -0
  62. package/dist/broker/http1.js +256 -0
  63. package/dist/broker/lease-book.d.ts +87 -0
  64. package/dist/broker/lease-book.js +142 -0
  65. package/dist/broker/lease-file.d.ts +60 -0
  66. package/dist/broker/lease-file.js +127 -0
  67. package/dist/broker/main.d.ts +2 -0
  68. package/dist/broker/main.js +20 -0
  69. package/dist/budget.d.ts +17 -15
  70. package/dist/budget.js +2 -2
  71. package/dist/capabilities/composite-members.d.ts +2 -1
  72. package/dist/capabilities/composite-members.js +2 -1
  73. package/dist/capabilities/engine-capabilities.js +1 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -11
  75. package/dist/capabilities/mcp-probe.js +44 -5
  76. package/dist/capabilities/scenarios.d.ts +23 -8
  77. package/dist/capabilities/scenarios.js +13 -8
  78. package/dist/capabilities/skills.d.ts +28 -5
  79. package/dist/capabilities/skills.js +8 -0
  80. package/dist/capability-facts.d.ts +6 -0
  81. package/dist/capability-facts.js +5 -0
  82. package/dist/center-credential-renewer.js +5 -1
  83. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  84. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  85. package/dist/checkpoint-identity.d.ts +13 -6
  86. package/dist/config-catalog.js +16 -7
  87. package/dist/config-types.d.ts +24 -7
  88. package/dist/config.d.ts +1 -1
  89. package/dist/config.js +42 -13
  90. package/dist/deployment-governance.d.ts +2 -2
  91. package/dist/deployment-governance.js +7 -9
  92. package/dist/deployment-shape.d.ts +6 -6
  93. package/dist/device-ws-protocol.d.ts +1 -0
  94. package/dist/device-ws-protocol.js +2 -1
  95. package/dist/file-history-disclosure.d.ts +4 -2
  96. package/dist/file-history-disclosure.js +2 -0
  97. package/dist/gate-settlement.d.ts +71 -0
  98. package/dist/gate-settlement.js +40 -0
  99. package/dist/hooks/classic-stations.d.ts +12 -54
  100. package/dist/hooks/classic-stations.js +1 -0
  101. package/dist/hooks/command-spawn.d.ts +2 -2
  102. package/dist/hooks/hook-runner.js +14 -14
  103. package/dist/http/admission.js +14 -9
  104. package/dist/http/approval-sweeps.js +4 -3
  105. package/dist/http/caller-trust.d.ts +2 -1
  106. package/dist/http/caller-trust.js +1 -3
  107. package/dist/http/checkpoint-ctx.d.ts +48 -7
  108. package/dist/http/checkpoint-ctx.js +40 -0
  109. package/dist/http/dispatch.d.ts +4 -0
  110. package/dist/http/dispatch.js +18 -10
  111. package/dist/http/durable-run-leg.d.ts +5 -1
  112. package/dist/http/durable-run-leg.js +5 -3
  113. package/dist/http/health-self-report.d.ts +2 -2
  114. package/dist/http/memory-compliance-failure-reply.js +3 -0
  115. package/dist/http/principal-gate.d.ts +15 -10
  116. package/dist/http/principal-gate.js +48 -9
  117. package/dist/http/resume-legs.d.ts +7 -31
  118. package/dist/http/resume-legs.js +185 -126
  119. package/dist/http/route-ctx.d.ts +38 -53
  120. package/dist/http/route-ctx.js +2 -5
  121. package/dist/http/routes/a2a-serve.js +10 -4
  122. package/dist/http/routes/agents-roster.d.ts +1 -1
  123. package/dist/http/routes/agents-roster.js +5 -1
  124. package/dist/http/routes/approvals-assistant.js +24 -10
  125. package/dist/http/routes/capabilities.js +23 -11
  126. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  127. package/dist/http/routes/mcp-reconnect.js +7 -7
  128. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/rules.js +3 -3
  131. package/dist/http/routes/runs.js +13 -8
  132. package/dist/http/routes/session-sync.js +42 -6
  133. package/dist/http/routes/sessions.js +6 -3
  134. package/dist/http/routes/side-query.js +2 -3
  135. package/dist/http/routes/tasks.js +794 -780
  136. package/dist/http/server.d.ts +35 -25
  137. package/dist/http/stored-body-replay.d.ts +3 -3
  138. package/dist/http/stored-body-replay.js +6 -1
  139. package/dist/http/wire-types.d.ts +66 -33
  140. package/dist/identity-source.d.ts +65 -0
  141. package/dist/identity-source.js +45 -0
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +1 -0
  144. package/dist/leader/wire.d.ts +7 -0
  145. package/dist/leader/wire.js +5 -4
  146. package/dist/mcp-assertion-header.d.ts +51 -40
  147. package/dist/mcp-assertion-header.js +10 -11
  148. package/dist/mcp-authorization-face.d.ts +27 -0
  149. package/dist/mcp-authorization-face.js +15 -0
  150. package/dist/memory-operator-faces.d.ts +13 -4
  151. package/dist/memory-operator-faces.js +1 -17
  152. package/dist/memory-store-refusal.d.ts +3 -3
  153. package/dist/memory-sync-client.js +72 -57
  154. package/dist/memory-sync.d.ts +1 -1
  155. package/dist/model-entry-refusal.d.ts +2 -0
  156. package/dist/model-entry-refusal.js +11 -0
  157. package/dist/model-route-gap.d.ts +6 -22
  158. package/dist/model-route-gap.js +7 -5
  159. package/dist/model-select.d.ts +6 -17
  160. package/dist/model-select.js +0 -3
  161. package/dist/mods-declaration.d.ts +110 -0
  162. package/dist/mods-declaration.js +109 -0
  163. package/dist/namespaced-rule-name.d.ts +1 -1
  164. package/dist/observability/err-text.d.ts +5 -0
  165. package/dist/observability/err-text.js +9 -0
  166. package/dist/observability/fail-open.d.ts +17 -1
  167. package/dist/observability/fail-open.js +17 -1
  168. package/dist/observability/metrics.js +1 -1
  169. package/dist/observability/run-terminal.js +1 -0
  170. package/dist/observability/secret-env-scrub.d.ts +1 -1
  171. package/dist/observability/secret-env-scrub.js +1 -1
  172. package/dist/operator-ask.d.ts +2 -2
  173. package/dist/org-delivery-gate.js +1 -1
  174. package/dist/org-memory-admission.d.ts +2 -2
  175. package/dist/org-memory-admission.js +39 -2
  176. package/dist/parked-decide.d.ts +15 -2
  177. package/dist/parked-decide.js +17 -10
  178. package/dist/peer-directory.js +2 -0
  179. package/dist/peer-seat.d.ts +150 -0
  180. package/dist/peer-seat.js +239 -0
  181. package/dist/permission-rule-list.d.ts +2 -2
  182. package/dist/permission-rule-vocab.d.ts +7 -7
  183. package/dist/permission-rule-vocab.js +3 -3
  184. package/dist/plain-string-record.d.ts +38 -0
  185. package/dist/plain-string-record.js +38 -0
  186. package/dist/plugins/background-agent-store-sql.js +6 -3
  187. package/dist/plugins/caching-session-store.d.ts +5 -0
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
  190. package/dist/plugins/checkpoint-store-sql.js +14 -14
  191. package/dist/plugins/file-history-store-sql.js +10 -16
  192. package/dist/plugins/file-run-store.js +8 -2
  193. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  194. package/dist/plugins/k8s-exec-protocol.js +116 -28
  195. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  196. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  197. package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
  198. package/dist/plugins/k8s-pod-reaper.js +122 -0
  199. package/dist/plugins/local-checkpoint-store.d.ts +4 -17
  200. package/dist/plugins/local-checkpoint-store.js +3 -4
  201. package/dist/plugins/local-session-store.d.ts +66 -27
  202. package/dist/plugins/local-session-store.js +60 -28
  203. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  204. package/dist/plugins/mailbox-store-sql.js +103 -15
  205. package/dist/plugins/memory-run-store.js +2 -0
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +34 -12
  209. package/dist/plugins/one-time-migrations.js +51 -9
  210. package/dist/plugins/permission-rule-store-file.js +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  212. package/dist/plugins/permission-rule-store-sql.js +37 -30
  213. package/dist/plugins/pg-pool.js +4 -0
  214. package/dist/plugins/pg-session-storage.d.ts +10 -2
  215. package/dist/plugins/pg-session-storage.js +20 -7
  216. package/dist/plugins/remote-env-adb.d.ts +6 -1
  217. package/dist/plugins/remote-env-adb.js +2 -1
  218. package/dist/plugins/remote-env-device.d.ts +6 -1
  219. package/dist/plugins/remote-env-device.js +5 -1
  220. package/dist/plugins/remote-env-e2b.d.ts +5 -0
  221. package/dist/plugins/remote-env-e2b.js +2 -1
  222. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  223. package/dist/plugins/remote-env-file-error.js +7 -1
  224. package/dist/plugins/remote-env-host.d.ts +10 -2
  225. package/dist/plugins/remote-env-host.js +8 -2
  226. package/dist/plugins/remote-env-k8s.d.ts +140 -11
  227. package/dist/plugins/remote-env-k8s.js +277 -15
  228. package/dist/plugins/remote-env-local-docker.d.ts +5 -0
  229. package/dist/plugins/remote-env-local-docker.js +2 -1
  230. package/dist/plugins/remote-env-ssh.d.ts +6 -1
  231. package/dist/plugins/remote-env-ssh.js +2 -1
  232. package/dist/plugins/retention-store-sql.d.ts +14 -2
  233. package/dist/plugins/retention-store-sql.js +6 -0
  234. package/dist/plugins/run-store-sql.js +10 -4
  235. package/dist/plugins/session-fork.d.ts +10 -13
  236. package/dist/plugins/session-fork.js +5 -25
  237. package/dist/plugins/session-ownership.d.ts +24 -3
  238. package/dist/plugins/session-ownership.js +24 -5
  239. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  240. package/dist/plugins/session-workspace-cell.js +38 -0
  241. package/dist/plugins/sql-errors.d.ts +23 -2
  242. package/dist/plugins/sql-errors.js +15 -0
  243. package/dist/plugins/store-backend.js +7 -7
  244. package/dist/plugins/store-contracts.d.ts +10 -1
  245. package/dist/plugins/store-fault.d.ts +2 -2
  246. package/dist/plugins/store-fault.js +4 -2
  247. package/dist/plugins/tidb-pool.js +13 -0
  248. package/dist/plugins/tidb-session-store.d.ts +17 -2
  249. package/dist/plugins/tidb-session-store.js +18 -7
  250. package/dist/plugins/tool-result-store-sql.d.ts +13 -6
  251. package/dist/plugins/tool-result-store-sql.js +8 -7
  252. package/dist/plugins/worktree-isolation.d.ts +3 -2
  253. package/dist/plugins/worktree-isolation.js +1 -7
  254. package/dist/project-identity.d.ts +1 -14
  255. package/dist/project-identity.js +0 -4
  256. package/dist/request-key-closure.js +1 -1
  257. package/dist/request-value-closure.d.ts +31 -2
  258. package/dist/request-value-closure.js +7 -1
  259. package/dist/rule-entry-list.d.ts +3 -2
  260. package/dist/rule-entry-list.js +2 -2
  261. package/dist/rules-consent.js +12 -7
  262. package/dist/run-local.d.ts +2 -2
  263. package/dist/run-local.js +12 -6
  264. package/dist/runs.d.ts +7 -1
  265. package/dist/runs.js +8 -2
  266. package/dist/runtime-governance.d.ts +5 -5
  267. package/dist/sandbox-git-lease.d.ts +49 -0
  268. package/dist/sandbox-git-lease.js +60 -0
  269. package/dist/sandbox-git-plane.d.ts +84 -0
  270. package/dist/sandbox-git-plane.js +105 -0
  271. package/dist/security.d.ts +16 -4
  272. package/dist/security.js +8 -3
  273. package/dist/server-secret-env.d.ts +12 -3
  274. package/dist/server-secret-env.js +18 -2
  275. package/dist/session-error-wire.d.ts +14 -6
  276. package/dist/session-error-wire.js +2 -1
  277. package/dist/session-incarnation.d.ts +4 -5
  278. package/dist/session-incarnation.js +2 -2
  279. package/dist/session-policy-wire.d.ts +1 -1
  280. package/dist/session-policy-wire.js +2 -2
  281. package/dist/session-sync.d.ts +1 -1
  282. package/dist/session-workspace.d.ts +130 -0
  283. package/dist/session-workspace.js +83 -0
  284. package/dist/spec-fields.d.ts +44 -14
  285. package/dist/spec-fields.js +33 -12
  286. package/dist/standing-answer-grant.d.ts +2 -13
  287. package/dist/standing-answer-grant.js +0 -7
  288. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  289. package/dist/stored-request-prompt-profile-m30.js +25 -0
  290. package/dist/task-a2a.d.ts +44 -14
  291. package/dist/task-a2a.js +46 -20
  292. package/dist/task-mcp.d.ts +34 -21
  293. package/dist/task-mcp.js +46 -22
  294. package/dist/task-settings.d.ts +2 -2
  295. package/dist/tool-approval.d.ts +43 -9
  296. package/dist/tool-approval.js +57 -15
  297. package/dist/tool-rule-names.d.ts +5 -0
  298. package/dist/trace/core-keyset-guard.d.ts +34 -19
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +4 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +5 -2
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/ledger-sink.d.ts +4 -5
  306. package/dist/trace/ledger-sink.js +3 -7
  307. package/dist/trace/project.d.ts +62 -10
  308. package/dist/trace/project.js +49 -9
  309. package/dist/trace/redact.d.ts +18 -6
  310. package/dist/trace/redact.js +154 -60
  311. package/dist/trace/self-minted-wire.d.ts +500 -7
  312. package/dist/trace/self-minted-wire.js +182 -1
  313. package/dist/trace/wire-projection-faces.d.ts +7 -5
  314. package/dist/trace/wire-projection-faces.js +9 -4
  315. package/dist/user-authored-text.d.ts +2 -2
  316. package/dist/user-authored-text.js +16 -1
  317. package/dist/web-admin-client/apply-effective.js +0 -1
  318. package/dist/web-admin-client/center-request.d.ts +23 -4
  319. package/dist/web-admin-client/center-request.js +42 -8
  320. package/dist/web-admin-client/http-client.js +6 -6
  321. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  322. package/dist/web-admin-client/skills-mcp.js +31 -18
  323. package/dist/web-admin-client/types.d.ts +10 -5
  324. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  325. package/package.json +3 -3
  326. package/wire-changes/server@7.137.0.json +825 -0
  327. package/wire-changes/server@7.138.0.json +446 -0
@@ -0,0 +1,40 @@
1
+ export const NO_SETTLEMENT_EVIDENCE = Object.freeze({});
2
+ const settled = (gate) => ({
3
+ decisionCommitted: true,
4
+ ...(gate.checkpointId !== undefined ? { checkpointId: gate.checkpointId } : {}),
5
+ });
6
+ export function buildSettlementEvidence(crossing) {
7
+ switch (crossing.at) {
8
+ case "engine_accepted":
9
+ case "engine_terminal": {
10
+ const c = crossing.commitment;
11
+ switch (c.kind) {
12
+ case "gate_resolved":
13
+ return settled(c);
14
+ case "delivered":
15
+ return NO_SETTLEMENT_EVIDENCE;
16
+ default: {
17
+ const unhandled = c;
18
+ throw new Error(`unhandled gate commitment: ${JSON.stringify(unhandled)}`);
19
+ }
20
+ }
21
+ }
22
+ case "replay_matched":
23
+ return settled({});
24
+ case "agent_revived":
25
+ case "card_voided":
26
+ return settled(crossing.gate);
27
+ default: {
28
+ const unhandled = crossing;
29
+ throw new Error(`unhandled settlement crossing: ${JSON.stringify(unhandled)}`);
30
+ }
31
+ }
32
+ }
33
+ export function withoutSettlementEvidence(body) {
34
+ const { decisionCommitted: _committed, checkpointId: _identity, ...rest } = body;
35
+ return rest;
36
+ }
37
+ export function decisionCommittedOf(out) {
38
+ return out.status === 200 && out.body.decisionCommitted === true;
39
+ }
40
+ //# sourceMappingURL=gate-settlement.js.map
@@ -2,8 +2,8 @@
2
2
  * 引擎的 `classic.*` 站 —— 本仓挂 handler 的唯一入口(core 7.52.0 起扩展点 = mods 注册,`Hooks` 记录退役)。
3
3
  *
4
4
  * 三件事只写在这里:
5
- * ① **事件名 → { `e` 型, 答案型 }**:core 逐个导出了每站的 `e` 型与答案型,但没有导出二者的映射(宿主侧配对是今天的唯一读法)。
6
- * 这张对位表是那一配对的唯一一份;core 导出映射型的那一版,本表改读它、删掉手写的十一行。
5
+ * ① **事件名 → { `e` 型, 答案型 }**:读 core 的 `ClassicEventMap`(7.56.0 起包根导出;此前本文件手写十一行配对,随之删)。
6
+ * 每站的角色(链 / 观察)由 {@link CLASSIC_STATION_ROLE} 说,它在编译期对着 core 的答案形核:答案形是 `ObservedAnswer` 的站必须是 `observe`、其余是 `chain`。
7
7
  * ② **handler 怎么挂**:链成员「无意见 ⇒ `next(e)`」(链 handler 返回 `undefined` 是站点违约,refuse 站上即 fail-closed 拒),
8
8
  * 观察者「恒返回 `undefined`」(观察者的判词不采纳、被引擎报告)。两条都在 {@link hangClassic} / {@link observeClassic} 里成形,
9
9
  * 调用方只写「这一站我答什么」或「这一站我看什么」,不再各自记得这两条。
@@ -13,55 +13,9 @@
13
13
  * 站的集合 = 引擎事件表里有站的 `classic.*` 名(一条钉从 `MOD_EVENT_TABLE` 派生对拍,不手抄第二份)。
14
14
  * 观察站(`StopFailure` / `PostCompact` / `PermissionDenied`)只许观察者:答案形是「无」,core 的迁移配方要求挂 `{ observe: true }`。
15
15
  */
16
- import type { EngineDollar, On, PermissionDeniedPayload, PostCompactEvent, PostToolBatchEvent, PostToolBatchResult, PostToolUseEvent, PostToolUseFailureEvent, PostToolUseFailureResult, PostToolUseResult, PreCompactEvent, PreCompactResult, PreToolUseEvent, PreToolUseResult, StopEvent, StopFailureEvent, StopHookResult, UserPromptSubmitEvent, UserPromptSubmitResult } from "@sema-agent/core";
17
- /** 每一站的 `e` 型与答案型(答案 `void` = 观察站)。 */
18
- export interface ClassicStationTypes {
19
- "classic.PreToolUse": {
20
- e: PreToolUseEvent;
21
- answer: PreToolUseResult;
22
- };
23
- "classic.PostToolUse": {
24
- e: PostToolUseEvent;
25
- answer: PostToolUseResult;
26
- };
27
- "classic.PostToolUseFailure": {
28
- e: PostToolUseFailureEvent;
29
- answer: PostToolUseFailureResult;
30
- };
31
- "classic.PostToolBatch": {
32
- e: PostToolBatchEvent;
33
- answer: PostToolBatchResult;
34
- };
35
- "classic.UserPromptSubmit": {
36
- e: UserPromptSubmitEvent;
37
- answer: UserPromptSubmitResult;
38
- };
39
- "classic.Stop": {
40
- e: StopEvent;
41
- answer: StopHookResult;
42
- };
43
- "classic.SubagentStop": {
44
- e: StopEvent;
45
- answer: StopHookResult;
46
- };
47
- "classic.StopFailure": {
48
- e: StopFailureEvent;
49
- answer: void;
50
- };
51
- "classic.PreCompact": {
52
- e: PreCompactEvent;
53
- answer: PreCompactResult;
54
- };
55
- "classic.PostCompact": {
56
- e: PostCompactEvent;
57
- answer: void;
58
- };
59
- "classic.PermissionDenied": {
60
- e: PermissionDeniedPayload;
61
- answer: void;
62
- };
63
- }
64
- export type ClassicStation = keyof ClassicStationTypes;
16
+ import type { ClassicEventMap, ClassicEventName, EngineDollar, On } from "@sema-agent/core";
17
+ /** 引擎有站的 `classic.*` 名(core 的 `ClassicEventMap` 键集)。 */
18
+ export type ClassicStation = ClassicEventName;
65
19
  /** 每一站能挂什么:`chain` = 链成员(会作答)与观察者都可;`observe` = 只许观察者。 */
66
20
  export declare const CLASSIC_STATION_ROLE: {
67
21
  readonly "classic.PreToolUse": "chain";
@@ -71,21 +25,25 @@ export declare const CLASSIC_STATION_ROLE: {
71
25
  readonly "classic.UserPromptSubmit": "chain";
72
26
  readonly "classic.Stop": "chain";
73
27
  readonly "classic.SubagentStop": "chain";
28
+ readonly "classic.SubagentStart": "chain";
74
29
  readonly "classic.StopFailure": "observe";
75
30
  readonly "classic.PreCompact": "chain";
76
31
  readonly "classic.PostCompact": "observe";
77
32
  readonly "classic.PermissionDenied": "observe";
78
33
  };
34
+ /** 本仓 handler 体对一站作的答:观察站不作答(`void`);链站 = core 的答案形,去掉本仓从不作的 `null` / `false`(PreToolUse 的两个「不表态」词)。 */
35
+ type StationAnswer<K extends ClassicStation> = (typeof CLASSIC_STATION_ROLE)[K] extends "observe" ? void : Exclude<ClassicEventMap[K]["answer"], null | false>;
79
36
  /**
80
37
  * 一站的 handler 体:读 `e`,答这一站的答案;`undefined` = 无意见(链成员由 {@link hangClassic} 交给 `next(e)`)。
81
38
  * `signal` = 引擎交给这只 handler 的 `next.signal`(预算到 ∪ 派发被取消;见头注 ③)。
82
39
  */
83
- export type ClassicAnswer<K extends ClassicStation> = (e: ClassicStationTypes[K]["e"], signal: AbortSignal) => Promise<ClassicStationTypes[K]["answer"] | undefined>;
40
+ export type ClassicAnswer<K extends ClassicStation> = (e: ClassicEventMap[K]["e"], signal: AbortSignal) => Promise<StationAnswer<K> | undefined>;
84
41
  /**
85
42
  * 按站的角色挂一只 handler:链站 ⇒ 链成员 `(await answer(e)) ?? next(e)`;观察站 ⇒ 观察者(体照跑、恒返回 `undefined`)。
86
- * `e` 的型由 {@link ClassicStationTypes} 给(引擎交来的是本站的 `e`;配对见头注 ①)。
43
+ * `e` 的型由 core 的 `ClassicEventMap` 给(引擎交来的是本站的 `e`;见头注 ①)。
87
44
  */
88
45
  export declare function hangClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, answer: ClassicAnswer<K>): void;
89
46
  /** 挂一只观察者(任何站都可):拿分离副本、不进链、恒返回 `undefined`;`signal` 同 {@link ClassicAnswer}。 */
90
- export declare function observeClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, watch: (e: ClassicStationTypes[K]["e"], signal: AbortSignal) => void | Promise<void>): void;
47
+ export declare function observeClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, watch: (e: ClassicEventMap[K]["e"], signal: AbortSignal) => void | Promise<void>): void;
48
+ export {};
91
49
  //# sourceMappingURL=classic-stations.d.ts.map
@@ -6,6 +6,7 @@ export const CLASSIC_STATION_ROLE = {
6
6
  "classic.UserPromptSubmit": "chain",
7
7
  "classic.Stop": "chain",
8
8
  "classic.SubagentStop": "chain",
9
+ "classic.SubagentStart": "chain",
9
10
  "classic.StopFailure": "observe",
10
11
  "classic.PreCompact": "chain",
11
12
  "classic.PostCompact": "observe",
@@ -26,7 +26,7 @@ export declare function commandLineChars(entry: {
26
26
  export declare function hookPluginEnv(p: HookPluginContext | undefined): Record<string, string>;
27
27
  /**
28
28
  * 起法:shell 形交回命令串(shell 由调用点落定),exec 形交回可执行名与参数,起不来交回真因(进调用点的 `spawnError`)。
29
- * `env` = 这条 hook 的**有效环境层**({@link composeHookEnvLayer} 的产物;调用点铺在基础 allowlist 之上,不再自己合并任何一层)。
29
+ * `env` = 这条 hook 的**有效环境层**({@link composeHookEnvLayer} 的产物;调用点把它作为授予交给宿主子进程的唯一组合,不再自己合并任何一层)。
30
30
  */
31
31
  export type CommandSpawnPlan = {
32
32
  readonly kind: "shell";
@@ -42,7 +42,7 @@ export type CommandSpawnPlan = {
42
42
  readonly error: string;
43
43
  };
44
44
  /**
45
- * 一条 command hook 的**有效环境层**(基础 allowlist 之上的那一层)—— **唯一铺法**,后铺者赢:`CLAUDE_PROJECT_DIR` 的缺省(`cwd`,hook 的工作目录;请求没写它才取)< 请求 `settings.env`(`requestEnv`;
45
+ * 一条 command hook 的**有效环境层**(继承之上的那一层授予)—— **唯一铺法**,后铺者赢:`CLAUDE_PROJECT_DIR` 的缺省(`cwd`,hook 的工作目录;请求没写它才取)< 请求 `settings.env`(`requestEnv`;
46
46
  * 请求自己写了 `CLAUDE_PROJECT_DIR` 就是它,空串也照用)< 条目自己的插件上下文({@link hookPluginEnv})。键的枚举顺序 = 请求的键在前、`CLAUDE_PROJECT_DIR` 缺省时接后、插件键最后。调用点传**原料**(工作目录与请求 env),不预先取舍 `CLAUDE_PROJECT_DIR`。
47
47
  * 「有没有值」的判据、exec 形的占位替换、shell 形子进程的环境都读这一个对象(见文件头);http 条目的 `$NAME` 插值取环境也走这一只(无插件上下文)。
48
48
  */
@@ -32,20 +32,13 @@ export const MAX_HOOK_CONTEXT_TOTAL_CHARS = 10_000;
32
32
  const MIN_HOOK_CONTEXT_PARTIAL_CHARS = 256;
33
33
  const MAX_TOOL_RESPONSE_CHARS = 32_768;
34
34
  const MAX_TOOL_INPUT_CHARS = 262_144;
35
- const HOOK_ENV_ALLOWLIST = [
36
- "PATH", "HOME", "SHELL", "USER", "LOGNAME", "TERM", "TZ",
37
- "LANG", "LC_ALL", "LC_CTYPE", "LC_MESSAGES", "TMPDIR",
38
- ];
39
- function hookBaseEnv(spawning) {
40
- return spawning
41
- ? hostSubprocessEnv({ site: "server.hooks.spawn-env", policy: [...HOOK_ENV_ALLOWLIST], allow: [] })
42
- : composeHostSubprocessEnv({ policy: [...HOOK_ENV_ALLOWLIST], allow: [] });
43
- }
44
- function hookEnvOverBase(layer, spawning) {
45
- return { ...hookBaseEnv(spawning), ...layer };
35
+ const HOOK_ENV_ALLOWLIST = ["PATH", "HOME", "SHELL", "USER", "LOGNAME", "TERM", "TZ", "LANG", "LC_ALL", "LC_CTYPE", "LC_MESSAGES", "TMPDIR"];
36
+ function hookChildEnv(layer, spawning) {
37
+ const o = { policy: [...HOOK_ENV_ALLOWLIST], allow: [], grants: [layer] };
38
+ return spawning ? hostSubprocessEnv({ site: "server.hooks.spawn-env", ...o }) : composeHostSubprocessEnv(o);
46
39
  }
47
40
  function hookEnv(ctx) {
48
- return hookEnvOverBase(composeHookEnvLayer(ctx.shellEnv, ctx.cwd, undefined), false);
41
+ return hookChildEnv(composeHookEnvLayer(ctx.shellEnv, ctx.cwd, undefined), false);
49
42
  }
50
43
  export const SETTINGS_HOOK_STATIONS = {
51
44
  PreToolUse: ["classic.PreToolUse"],
@@ -754,7 +747,7 @@ function buildHookContextField(parts) {
754
747
  return text === undefined ? {} : { additionalContext: text };
755
748
  }
756
749
  function spawnPlannedCommand(plan, ctx, stdio) {
757
- const env = hookEnvOverBase(plan.env, true);
750
+ const env = hookChildEnv(plan.env, true);
758
751
  if (plan.kind === "exec")
759
752
  return spawn(plan.file, [...plan.args], { cwd: ctx.cwd, env, stdio, detached: true });
760
753
  const sh = hostShell();
@@ -1006,7 +999,14 @@ async function runLlmHook(entry, payload, ctx, extra) {
1006
999
  const MAX_BLANKED_REFERENCES_LOGGED = 16;
1007
1000
  async function runHttpHook(entry, payload, ctx, event) {
1008
1001
  const timeoutMs = Math.min(entry.timeout ?? DEFAULT_HOOK_TIMEOUT_SECONDS, MAX_HOOK_TIMEOUT_SECONDS) * 1000;
1009
- const interpolated = interpolateHookEnvVars(entry.headers ?? {}, entry.allowedEnvVars ?? [], hookEnv(ctx));
1002
+ let hookChildVars;
1003
+ try {
1004
+ hookChildVars = hookEnv(ctx);
1005
+ }
1006
+ catch (e) {
1007
+ return { code: null, stdout: "", stderr: "", timedOut: false, spawnError: String(e) };
1008
+ }
1009
+ const interpolated = interpolateHookEnvVars(entry.headers ?? {}, entry.allowedEnvVars ?? [], hookChildVars);
1010
1010
  if (interpolated.blanked.length > 0) {
1011
1011
  ctx.logger.warn("hook_http_header_env_blanked", {
1012
1012
  event,
@@ -12,7 +12,7 @@ import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, fileHisto
12
12
  import * as facts from "../capability-facts.js";
13
13
  import { buildHooksRefusal, buildHooksUrlCredentialRefusal, parseHooksConfig, hooksMatcherIssue, hooksUrlCredentialIssue } from "../hooks/hook-runner.js";
14
14
  import { judgeFreshRequestWebSearch } from "../plugins/web-search.js";
15
- import { normalizeApproachNotice, skillToolListOk, unknownTaskAgentModelRef, validateTaskAgents } from "../spec-fields.js";
15
+ import { ATTACHMENT_BOOLEAN_KEYS, ATTACHMENT_KEYS, normalizeApproachNotice, skillToolListOk, unknownTaskAgentModelRef, validateTaskAgents } from "../spec-fields.js";
16
16
  import { allowSelectorWarningsOf, skillToolListsOverCap } from "../rule-entry-list.js";
17
17
  import { limitFacts, limitRefusal } from "../limit-refusal.js";
18
18
  import { fieldConflictFacts } from "../field-conflict.js";
@@ -78,6 +78,8 @@ function userSkillShapeIssue(item, index) {
78
78
  }
79
79
  if (skillCarriesRetiredManifest(s))
80
80
  return { message: SKILL_MANIFEST_RETIRED };
81
+ if (s["mods"] !== undefined)
82
+ return { message: "skill.mods is not a request key — skill registrations are code the deployment mounts, not request data (this server does not compile skill hooks: GET /v1/capabilities answers mods.skill_seat: false)" };
81
83
  for (const key of ["allowedTools", "disallowedTools"]) {
82
84
  if (s[key] !== undefined && !skillToolListOk(s[key]))
83
85
  return { message: `skill.${key} must be an array of strings (permission-rule spellings: a tool name, mcp__<server> / mcp__<server>__*, Bash(<prefix>:*), Read(//<dir>/**))` };
@@ -457,7 +459,7 @@ export function createAdmission(ctx) {
457
459
  {
458
460
  const inheritEnvIssue = inheritEnvFieldIssue(body);
459
461
  if (inheritEnvIssue) {
460
- sendError(res, 400, "request.field_invalid", inheritEnvIssue);
462
+ sendError(res, 400, "request.field_invalid", inheritEnvIssue.message, inheritEnvIssue.facts);
461
463
  return null;
462
464
  }
463
465
  }
@@ -618,9 +620,9 @@ export function createAdmission(ctx) {
618
620
  }
619
621
  }
620
622
  {
621
- const v = body.promptProfile;
622
- if (v !== undefined && v !== "simple" && v !== "classic") {
623
- sendError(res, 400, "request.field_invalid", 'promptProfile must be "simple" or "classic"');
623
+ const v = body.promptLean;
624
+ if (v !== undefined && typeof v !== "boolean") {
625
+ sendError(res, 400, "request.field_invalid", "promptLean must be a boolean");
624
626
  return null;
625
627
  }
626
628
  }
@@ -687,7 +689,8 @@ export function createAdmission(ctx) {
687
689
  if (body.attachments !== undefined) {
688
690
  const a = body.attachments;
689
691
  if (typeof a !== "object" || a === null || Array.isArray(a)) {
690
- sendError(res, 400, "request.field_invalid", "attachments must be an object { todoReminder?, todoReminderMode?, changedFiles?, budgetUsd?, backgroundTasks?, toolsDelta?, agentListing?, skillsListing?, mcpInstructions? }");
692
+ const attachmentKeyList = ATTACHMENT_KEYS.map((k) => `${k}?`).join(", ");
693
+ sendError(res, 400, "request.field_invalid", `attachments must be an object { ${attachmentKeyList} }`);
691
694
  return null;
692
695
  }
693
696
  const rec = a;
@@ -695,7 +698,7 @@ export function createAdmission(ctx) {
695
698
  sendError(res, 400, "request.field_invalid", 'attachments.planModeReminder was retired in core 7.39.0 — the engine now states plan posture itself whenever the permission mode is "plan" (first request, periodic reminders, exit frame); remove the key (send permissionMode "plan" for plan posture)');
696
699
  return null;
697
700
  }
698
- for (const k of ["todoReminder", "budgetUsd", "backgroundTasks", "toolsDelta", "agentListing", "skillsListing", "mcpInstructions"]) {
701
+ for (const k of ATTACHMENT_BOOLEAN_KEYS) {
699
702
  if (rec[k] !== undefined && typeof rec[k] !== "boolean") {
700
703
  sendError(res, 400, "request.field_invalid", `attachments.${k} must be a boolean`);
701
704
  return null;
@@ -740,10 +743,11 @@ export function createAdmission(ctx) {
740
743
  }
741
744
  }
742
745
  const { body: admitted, entry: entryMode } = stampEntryPermissionMode(body, autonomyModeFloor(deps.config.autonomy));
746
+ const lease = deps.peerDesk.lease("fresh");
743
747
  try {
744
748
  const auth = deps.authorize ? await deps.authorize({ req, body: admitted }) : undefined;
745
749
  const engineNotices = [];
746
- const spec = await deps.resolveSpec(admitted, req, auth, { leg: "fresh", ...(legFacts?.liveStream === true ? { liveStream: true } : {}), onNotice: (n) => engineNotices.push(n) });
750
+ const spec = await deps.resolveSpec(admitted, req, auth, { leg: "fresh", ...(legFacts?.liveStream === true ? { liveStream: true } : {}), onNotice: (n) => engineNotices.push(n), lease });
747
751
  const bindingIntent = await resolveDevicePlacementIntent({
748
752
  config: deps.config,
749
753
  req,
@@ -757,9 +761,10 @@ export function createAdmission(ctx) {
757
761
  const clampNotice = buildEntryModeClampNotice(entryMode, spec.sessionId);
758
762
  const pendingNotices = clampNotice !== undefined ? [clampNotice, ...engineNotices] : engineNotices;
759
763
  const warnings = allowSelectorWarningsOf(admitted, spec.tools ?? []);
760
- return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: admitted.jobId, body: admitted, acceptance, ...(bindingIntent === undefined ? {} : { bindingIntent }), ...(pendingNotices.length > 0 ? { engineNotices: pendingNotices } : {}), ...(warnings.length > 0 ? { warnings } : {}) };
764
+ return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: admitted.jobId, body: admitted, acceptance, peerLease: lease, ...(bindingIntent === undefined ? {} : { bindingIntent }), ...(pendingNotices.length > 0 ? { engineNotices: pendingNotices } : {}), ...(warnings.length > 0 ? { warnings } : {}) };
761
765
  }
762
766
  catch (err) {
767
+ lease.release();
763
768
  if (err instanceof HttpError) {
764
769
  if (onTypedFailure) {
765
770
  onTypedFailure(err);
@@ -1,5 +1,6 @@
1
1
  import { redactHead } from "../observability/run-terminal.js";
2
2
  const errText = (e) => redactHead(e instanceof Error ? e.message : String(e), 2000);
3
+ import { checkpointRevOf } from "@sema-agent/core";
3
4
  import { findParkOrigin } from "../parked-decide.js";
4
5
  import { decodeCheckpointScope } from "../security.js";
5
6
  import { hostDecisionFacts } from "../host-decision.js";
@@ -89,7 +90,7 @@ export function createApprovalSweeps(ctx) {
89
90
  const cp = await cs.get(token);
90
91
  if (!cp)
91
92
  return { token, parked: false, rev: undefined };
92
- const rev = cp.rev ?? 0;
93
+ const rev = checkpointRevOf(cp);
93
94
  if (!parkSources)
94
95
  return { token, parked: false, rev };
95
96
  const origin = await findParkOrigin({
@@ -120,7 +121,7 @@ export function createApprovalSweeps(ctx) {
120
121
  const cp = await cs.get(cardToken);
121
122
  if (!cp)
122
123
  return;
123
- if (cp.status !== "pending" || (cp.rev ?? 0) !== observedRev) {
124
+ if (cp.status !== "pending" || checkpointRevOf(cp) !== observedRev) {
124
125
  deps.logger?.warn?.("deny_sweep_policy_blocked_expire_skipped", { sessionId, skipReason: cp.status !== "pending" ? "not_pending" : "card_changed", ...blockedScalars(body) });
125
126
  return;
126
127
  }
@@ -177,7 +178,7 @@ export function createApprovalSweeps(ctx) {
177
178
  deps.logger?.warn?.("deny_sweep_stored_body_skipped", {
178
179
  count: replaySkipped.length,
179
180
  skipped: replaySkipped,
180
- note: "these expired approvals belong to tasks whose stored request this version does not replay (kind allow_list_reading: settings.permissions.allow written under an earlier reading; kind inert_tool_list: a tool-list entry (a skill disallowedTools, an agent definition's denyTools / allowTools or the request's excludeTools / allowTools) the engine reads as empty), so the SLA deny cannot be delivered. They stay suspended until the terminal backstop reaps them or someone cancels them; nothing was retried",
181
+ note: "these expired approvals belong to tasks whose stored request this version does not replay (skipped[].kind names the rule that refused each one; the resume paths log the same kinds with a reason per kind), so the SLA deny cannot be delivered. They stay suspended until the terminal backstop reaps them or someone cancels them; nothing was retried",
181
182
  });
182
183
  }
183
184
  }
@@ -8,7 +8,8 @@
8
8
  *
9
9
  * · 单用户 turnkey(`requirePrincipal !== true`,本仓 posture 判别式同一只)⇒ `global`:一台机一位超管;
10
10
  * · 多租 · 部署的 service 凭据 ⇒ `global`:部署自己的凭据是运维档(契约给「启动方自己的行为」—— `SETTINGS_SOURCE_CONTRACT.flagSettings` —— 的档),持它的前端为自己转发的内容负责;
11
- * 出示的 Bearer 就是 service 凭据时,哪怕它同时也被鉴权桥验成登录令牌,也按 service 凭据读(与凭据门派 `source` 同序:`dispatch.ts` 先认 service 凭据);
11
+ * 出示的 Bearer 就是 service 凭据时,哪怕它同时也被鉴权桥验成登录令牌,也按 service 凭据读 —— 这不是本表的判:来源只有一只判定次序(`verifiedIdentitySource`,
12
+ * service 凭据先;凭据门的 401 / 归因 / run 行身份元组读同一次的答案),本表只按来源词分档;
12
13
  * · 多租 · 中心登录令牌,scope 角色 ≥ 契约 `domainWriteRole("governance")` ⇒ `global`:能写 scope 治理域(autonomy / commandPolicy / approvalRequire,全组织的免问面)
13
14
  * 的角色,放宽自己这一 run 是它的子集;门槛读契约,不手抄角色词;
14
15
  * · 多租 · 其余(登录令牌角色低于它 / 不带 / 认不出;直连门 principal 令牌只证身份不证角色;没有验过的凭据)⇒ `project`:契约给非运维档作者的仓控来源的档,
@@ -1,7 +1,7 @@
1
1
  import { domainWriteRole, isAtLeast, isRole, memberAdmission, membersOf, roleAtLeast, USER_ROLES, } from "@sema-agent/settings-schema";
2
2
  import { entryProblem, entryProblemsFacts } from "../entry-problems.js";
3
3
  import { ssoVerifiedRole } from "../security.js";
4
- import { systemFor, verifiedIdentitySource } from "./principal-gate.js";
4
+ import { verifiedIdentitySource } from "./principal-gate.js";
5
5
  export function callerTrust(req, config) {
6
6
  if (config.requirePrincipal !== true)
7
7
  return { trust: "global", basis: "single_user" };
@@ -10,8 +10,6 @@ export function callerTrust(req, config) {
10
10
  case "service_token":
11
11
  return { trust: "global", basis: "service_credential" };
12
12
  case "sso": {
13
- if (systemFor(req, config) !== undefined)
14
- return { trust: "global", basis: "service_credential" };
15
13
  const role = ssoVerifiedRole(req);
16
14
  if (role === undefined || !isRole(role))
17
15
  return { trust: "project", basis: "sign_in_role_unrecognized" };
@@ -31,8 +31,14 @@
31
31
  * 不受影响:那两种行在新旧两种读法下答同一个词。出路:作为新任务重提(仍停驻的先取消),或在它们收尾之前把 `AUTONOMY` 设成 `read-only`(按段的只读围栏,
32
32
  * 与 7.121.x 的 `AUTONOMY=plan` 同一个结局,且没有入口地板 ⇒ 不拒)。删除条件登记在 `plugins/one-time-migrations.ts` 的 M12 行。
33
33
  *
34
+ * ## 第四问(7.137.0):体里的退役请求键
35
+ * 请求键退役之后(今天一只:`promptProfile` 换成布尔 `promptLean`,{@link RETIRED_REQUEST_KEYS}),新提交带它在键闭集门 400;存体里的旧键由一次性迁移在起服时原地改写
36
+ * (M30,`stored-request-prompt-profile-m30.ts`,行改写经本模块的 {@link rewriteStoredBodyKeys})。改写不到的残留行(窗内从没起过服的部署;起服扫描之后滚动升级里
37
+ * 旧副本才写下的行)体里仍带旧键 ⇒ 拒({@link retiredRequestKeyRefusal},码同前两只读法拒:`checkpoint.unsupported_version`)。**没有**续跑时按旧键读的第二种读法,
38
+ * 也**没有**「旧键无人读、静默续跑」的臂:旧键还在 = 这份体没被改写过,它当年要的形本版读不出来。
39
+ *
34
40
  * ## 一只判据、五个问点(`http/stored-body-replay.ts` 的 `storedBodyReplayRefusal` / 本模块的 {@link storedBodyReplayAnswer})
35
- * 「这条停驻行的持久化体在本版上能否重放」只有**一个**读法:上面三问合在 `stored-body-replay.ts` 的 `storedBodyReplayRefusal` 一处(前两问的判据在本模块、第三问读请求设置
41
+ * 「这条停驻行的持久化体在本版上能否重放」只有**一个**读法:上面四问合在 `stored-body-replay.ts` 的 `storedBodyReplayRefusal` 一处(前两问的判据在本模块、第三问读请求设置
36
42
  * 与治理两个属主 —— 本模块的值依赖要留在 node 内建 / 引擎包根之内,随包排空脚本经编译产物读它),答复合在 {@link storedBodyReplayAnswer} 一处。
37
43
  * 问点五个,同调同答:续跑驱动段(`resume-legs.ts` `resolveResumeSpecOrBlocked`,另四条腿的唯一判点)· plan_review 的 prepare 段(读类拒,在 nonce 消费之前)·
38
44
  * SLA 拒扫腿的跳过臂(`approval-sweeps.ts`)· 终态 run 的 steer 铸唤醒卡之前(`routes/runs.ts`:铸卡前先证明它赎得回,证不出 ⇒ 不铸、当场同一个拒)·
@@ -110,6 +116,23 @@ export declare function permissionModeReadingStated(ctx: CheckpointCtx): boolean
110
116
  * 🔴 形是给冻结门看的:`status: <三位数>, body: refusalBody({ errorCode: "<码>", message: "<整句双引号字面>"`,中间只许有空白。
111
117
  */
112
118
  export declare function permissionModeReadingRefusal(): ResumeRefusalAnswer;
119
+ /**
120
+ * 第四问:**退役的请求键**闭集(新提交在键闭集门 400;存体里还带着它 = 这份体是更早的写者写下、一次性迁移没改写到的)。加一个 ⇒ 加一行,
121
+ * {@link retiredRequestKeyRefusal} 的 switch 编译红直到给它一句拒句。今天一只:`promptProfile`(7.137.0 起换成布尔 `promptLean`;存体由 M30 起服改写)。
122
+ */
123
+ export declare const RETIRED_REQUEST_KEYS: readonly ["promptProfile"];
124
+ export type RetiredRequestKey = (typeof RETIRED_REQUEST_KEYS)[number];
125
+ /** 存体顶层带的第一只退役请求键(闭集序);没有 ⇒ `undefined`。只看自有键(原型上的同名不算)。 */
126
+ export declare function retiredRequestKeyOf(body: unknown): RetiredRequestKey | undefined;
127
+ /**
128
+ * 第四问的拒答复 —— 码与落点同另两只读法拒(`checkpoint.unsupported_version`,409;卡仍 pending 时的 `retriable:true` 由 {@link resumeRefusalWithCard} 追加,本铸点不带)。
129
+ * 句子说键、它换成了什么、为什么不续跑,与两条出路(运维在一次性迁移的窗内重启本服务 ⇒ 起服改写存体、同一请求可再发;否则作为新任务重提,仍停驻的先取消)。不回显值。
130
+ * 🔴 形是给冻结门看的:`status: <三位数>, body: refusalBody({ errorCode: "<码>", message: <整句双引号字面 或 一只模板串>`,中间只许有空白(模板串形冻结的是骨架,`${…}` 折成一个洞)。
131
+ * **窗的日期不手写**:`rewriteWindowEnd` 由调用方交 —— 判据(`stored-body-replay.ts`)按「退役键 → 改写它的迁移」那张表读登记表该行的 `removableAfter`,窗只写在登记表一处;
132
+ * 句子写绝对日期(过了这一天读句子的人一眼看出出路已关,不靠「本版发布日」这种随版漂的说法)。
133
+ * 删法见登记表 M30 的 `removal`(唯一来源)。
134
+ */
135
+ export declare function retiredRequestKeyRefusal(key: RetiredRequestKey, rewriteWindowEnd: string): ResumeRefusalAnswer;
113
136
  /**
114
137
  * 本行能否被按当前读法重放:体里 `allow` 在生效而行上的记号不是当前这一个词 ⇒ **不能**(`true` = 拒)。
115
138
  * 记号缺席、是旧词(`"statement"`)或认不得(手改 / 将来的写者)⇒ 同样拒:只有当前这个词是「按当前读法写下」的证据。
@@ -127,7 +150,7 @@ export declare function allowListReadingEraOf(ctx: CheckpointCtx): AllowListRead
127
150
  export declare function allowListReadingRefusal(era: AllowListReadingEra): ResumeRefusalAnswer;
128
151
  /**
129
152
  * 一条停驻行的持久化体在本版上**不能**重放时,是哪一条规则拒的(闭集;加一条 ⇒ {@link storedBodyReplayAnswer} 的 switch 编译红)。
130
- * 答 `checkpoint.unsupported_version` 的两臂随带这一行的写者版本(续跑上下文的 `writerVersion`,缺席 = 本版之前写下的行)—— 那一码的两版本键由它铸({@link buildCheckpointVersionKeys})。
153
+ * 答 `checkpoint.unsupported_version` 的三臂随带这一行的写者版本(续跑上下文的 `writerVersion`,缺席 = 本版之前写下的行)—— 那一码的两版本键由它铸({@link buildCheckpointVersionKeys})。
131
154
  */
132
155
  export type StoredBodyReplayRefusal = {
133
156
  readonly kind: "allow_list_reading";
@@ -141,10 +164,16 @@ export type StoredBodyReplayRefusal = {
141
164
  readonly stored: PermissionMode | undefined;
142
165
  readonly floor: PermissionMode;
143
166
  readonly writerVersion?: string;
167
+ } | {
168
+ readonly kind: "retired_request_key";
169
+ readonly key: RetiredRequestKey;
170
+ /** 改写这只退役键的一次性迁移窗的最后一天(UTC 日历日 YYYY-MM-DD)—— 登记表那一行的 `removableAfter`,由判据(`stored-body-replay.ts`)读来:本模块的闭包只许 node 内建 / 引擎包根,读不了登记表,日期只能由调用方交。 */
171
+ readonly rewriteWindowEnd: string;
172
+ readonly writerVersion?: string;
144
173
  };
145
174
  /**
146
- * 🔴 **`checkpoint.unsupported_version` 的 409 体上两个版本键 —— 唯一铸法;本码每一个铸点同一条律**(core 原码镜像 = `resume-legs.ts` 的 catch 臂;本服务自铸的两只拒
147
- * = {@link storedBodyReplayAnswer} 的 allow 读法 / 模式词读法两臂):续跑上下文带写者版本 ⇒ `{ writerVersion, readerVersion }`;不带(本版之前写下的行)⇒ `{}`,不编值。
175
+ * 🔴 **`checkpoint.unsupported_version` 的 409 体上两个版本键 —— 唯一铸法;本码每一个铸点同一条律**(core 原码镜像 = `resume-legs.ts` 的 catch 臂;本服务自铸的三只拒
176
+ * = {@link storedBodyReplayAnswer} 的 allow 读法 / 模式词读法 / 退役请求键三臂):续跑上下文带写者版本 ⇒ `{ writerVersion, readerVersion }`;不带(本版之前写下的行)⇒ `{}`,不编值。
148
177
  * 两值相等也照带 —— 那是事实(不是版本问题,出路照码与报文);写者比读者新才是「回到写它的那一版去决」。`readerVersion` 由调用方传本进程的服务版本
149
178
  * (本模块零值依赖,不自取)。纯数据。
150
179
  */
@@ -201,11 +230,12 @@ export declare function storedBodyReplayLogFields(refusal: StoredBodyReplayRefus
201
230
  layer?: InertToolListEntry["layer"];
202
231
  storedMode?: PermissionMode | null;
203
232
  floor?: PermissionMode;
233
+ key?: RetiredRequestKey;
204
234
  note: string;
205
235
  };
206
236
  /**
207
237
  * `stored-body-replay.ts` `storedBodyReplayRefusal` 的答复:每条规则一只既有铸点(allow 记号 ⇒ {@link allowListReadingRefusal};模式词记号 ⇒ {@link permissionModeReadingRefusal};
208
- * 这两只答 `checkpoint.unsupported_version`,体按那一码的键律补两版本键,`readerVersion` = 调用方传的本进程服务版本;工具名清单 ⇒ {@link resumeBlockedByPolicyAnswer},与提交腿的 400
238
+ * 退役请求键 ⇒ {@link retiredRequestKeyRefusal};这三只答 `checkpoint.unsupported_version`,体按那一码的键律补两版本键,`readerVersion` = 调用方传的本进程服务版本;工具名清单 ⇒ {@link resumeBlockedByPolicyAnswer},与提交腿的 400
209
239
  * (该层的拒码:`request.field_invalid` / `config.agent.unknown_tool` / `config.tool_face_control`)同码同句 —— 体上只有这一个问题时;存量体同时还踩中 `resolveSpec` 更早的拒〔三桶超帽 / 托管姿态〕时,提交侧答更早那条、续跑侧答本句,两边都是拒,指路不同)。
210
240
  *
211
241
  * 🔴 `cardPending` —— **调用方交出的事实**:这一次拒的时候,有没有一张待批卡仍在等。`retriable:true` 说的恰是「卡仍 pending」,所以它只在卡在时在场(经
@@ -356,9 +386,10 @@ export type StoredCheckpointCtx = Omit<CheckpointCtx, "body"> & {
356
386
  };
357
387
  declare const sealedCheckpointCtxBrand: unique symbol;
358
388
  /**
359
- * **封口铸出的**落盘形(品牌型):店的写口(`putCtx`)与一次性迁移 M28 的行改写只收它 ⇒ 「写 ctx 只有封口一个写入面」由型面守,
389
+ * **封口铸出的**落盘形(品牌型):店的写口(`putCtx`)与一次性迁移的 ctx 行改写店腿(`rewriteCtxRows`)只收它 ⇒ 「写 ctx 只有本模块的铸点一个写入面」由型面守,
360
390
  * 不再靠逐个数调用点(把开封形 / 裸对象直接交给写口 = 当场 tsc 红)。铸点闭集(都在本模块,都经 {@link mintSealedCheckpointCtx}):
361
- * {@link sealCheckpointCtx}(新的持久化写经 {@link buildCheckpointCtx} 到它;续跑腿的写回)与 {@link sealStoredCheckpointCtxM28}。零运行期变化。
391
+ * {@link sealCheckpointCtx}(新的持久化写经 {@link buildCheckpointCtx} 到它;续跑腿的写回)、{@link sealStoredCheckpointCtxM28} 与 {@link rewriteStoredBodyKeys}
392
+ * (存量行非凭据顶层体键的改写,凭据位与读法记号原样随行)。零运行期变化。
362
393
  */
363
394
  export type SealedCheckpointCtx = StoredCheckpointCtx & {
364
395
  readonly [sealedCheckpointCtxBrand]: true;
@@ -407,5 +438,15 @@ export declare function sealStoredCheckpointCtxM28(stored: object, sealer: Check
407
438
  readonly ctx: SealedCheckpointCtx;
408
439
  readonly valuesSealed: number;
409
440
  } | undefined;
441
+ /**
442
+ * 🔴 **一次性迁移对存量行非凭据顶层体键的改写**(品牌铸点之三;今天的调用方 = M30 的行改写 `stored-request-prompt-profile-m30.ts`):在一行落盘形的体上删 `drop` 里的顶层键、
443
+ * 设 `set` 里的顶层键,其余一个字节不动 —— 行上的读法记号(凭据封口的 `credentialSeal` / `credentialSlotGeneration` 与另两只记号)与凭据位上的值原样随行:封好的行仍是封好的,
444
+ * 更早写者留下的明文行仍是明文(读口照旧拒 `plaintext`,本口不替它洗白)。`drop` / `set` 碰到凭据位的根键(闭集各行路径的第一段)或 `__proto__` ⇒ 抛(程序错,不是数据错)。
445
+ * 体不是对象 ⇒ 抛(店的判形保证 ctx 是对象;体坏形的行由调用方先判、不交来)。
446
+ */
447
+ export declare function rewriteStoredBodyKeys(stored: object, edit: {
448
+ readonly drop: readonly string[];
449
+ readonly set?: Readonly<Record<string, unknown>>;
450
+ }): SealedCheckpointCtx;
410
451
  export {};
411
452
  //# sourceMappingURL=checkpoint-ctx.d.ts.map
@@ -39,6 +39,28 @@ export function permissionModeReadingRefusal() {
39
39
  }),
40
40
  };
41
41
  }
42
+ export const RETIRED_REQUEST_KEYS = ["promptProfile"];
43
+ export function retiredRequestKeyOf(body) {
44
+ if (body === null || typeof body !== "object" || Array.isArray(body))
45
+ return undefined;
46
+ return RETIRED_REQUEST_KEYS.find((key) => Object.hasOwn(body, key));
47
+ }
48
+ export function retiredRequestKeyRefusal(key, rewriteWindowEnd) {
49
+ switch (key) {
50
+ case "promptProfile":
51
+ return {
52
+ status: 409,
53
+ body: refusalBody({
54
+ errorCode: "checkpoint.unsupported_version",
55
+ message: `this task was suspended by an earlier server version and its stored request still carries promptProfile, a request key this version no longer reads (it was replaced by the boolean promptLean: classic is promptLean: false, simple is leaving promptLean out), so continuing would run the task with a prompt form it was not submitted with. Nothing was decided and nothing was resumed. If whoever operates this deployment restarts this server on or before ${rewriteWindowEnd} (UTC), the stored request is rewritten in place and the same request can be sent again; otherwise submit the work again as a new task with promptLean in place of promptProfile, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel).`,
56
+ }),
57
+ };
58
+ default: {
59
+ const unhandled = key;
60
+ throw new Error(`retired request key ${String(unhandled)} has no refusal sentence`);
61
+ }
62
+ }
63
+ }
42
64
  export function allowListReadingUnstated(ctx) {
43
65
  if (!bodyCarriesAllowList(ctx.body))
44
66
  return false;
@@ -96,6 +118,8 @@ export function storedBodyReplayLogFields(refusal) {
96
118
  return { kind: refusal.kind, layer: refusal.entry.layer, note: "this session's stored request carries a tool-list entry the engine reads as empty (a skill disallowedTools, an agent definition's denyTools / allowTools, the request's excludeTools / allowTools, or the rules in settings.permissions.deny / ask: a retired name, a case twin, a spelling no tool name can have, a rule core's grammar cannot compile, or a ~/ path rule on a lane with no home), or a permission list that is malformed or over the entry cap in either direction; it is not replayed — the task stays suspended until someone cancels it and resubmits with the entry fixed" };
97
119
  case "permission_mode_reading":
98
120
  return { kind: refusal.kind, storedMode: refusal.stored ?? null, floor: refusal.floor, note: "this session's stored request was written before the operator's AUTONOMY plan floor was recorded in the task (earlier versions re-applied it on every resume); replaying it now would run under its submitted permission mode — the task stays suspended until someone cancels it, or AUTONOMY is set to read-only so it can finish with read-only hands" };
121
+ case "retired_request_key":
122
+ return { kind: refusal.kind, key: refusal.key, note: "this session's stored request still carries a request key this version retired, and the one-time rewrite at startup did not reach it (no startup of this version inside its window since the row was written); it is not replayed — the task stays suspended until someone cancels it, or a restart of this version inside the window rewrites the row" };
99
123
  default: {
100
124
  const unhandled = refusal;
101
125
  throw new Error(`stored-body replay refusal ${JSON.stringify(unhandled)} has no log fields`);
@@ -117,6 +141,10 @@ function storedBodyReplayArmAnswer(refusal, readerVersion) {
117
141
  const answer = permissionModeReadingRefusal();
118
142
  return { status: answer.status, body: { ...answer.body, ...buildCheckpointVersionKeys(refusal.writerVersion, readerVersion) } };
119
143
  }
144
+ case "retired_request_key": {
145
+ const answer = retiredRequestKeyRefusal(refusal.key, refusal.rewriteWindowEnd);
146
+ return { status: answer.status, body: { ...answer.body, ...buildCheckpointVersionKeys(refusal.writerVersion, readerVersion) } };
147
+ }
120
148
  default: {
121
149
  const unhandled = refusal;
122
150
  throw new Error(`stored-body replay refusal ${JSON.stringify(unhandled)} has no answer`);
@@ -321,4 +349,16 @@ export function sealStoredCheckpointCtxM28(stored, sealer, sessionId) {
321
349
  ? undefined
322
350
  : { ctx: mintSealedCheckpointCtx({ ...stored, body: sealed, credentialSeal: CHECKPOINT_CTX_SEAL_ALG, credentialSlotGeneration: generation }), valuesSealed };
323
351
  }
352
+ const CREDENTIAL_SLOT_ROOTS = new Set(CHECKPOINT_CTX_CREDENTIAL_SLOTS.map((slot) => slot.path[0]));
353
+ export function rewriteStoredBodyKeys(stored, edit) {
354
+ const touched = [...edit.drop, ...Object.keys(edit.set ?? {})];
355
+ const forbidden = touched.filter((key) => CREDENTIAL_SLOT_ROOTS.has(key) || key === "__proto__");
356
+ if (forbidden.length > 0)
357
+ throw new Error(`rewriteStoredBodyKeys: ${forbidden.join(", ")} is a credential-slot root (or __proto__) — a one-time body-key rewrite never touches those`);
358
+ const body = stored.body;
359
+ if (!isRecord(body))
360
+ throw new Error("rewriteStoredBodyKeys: the stored row's body is not an object");
361
+ const next = Object.fromEntries([...Object.entries(body).filter(([key]) => !edit.drop.includes(key)), ...Object.entries(edit.set ?? {})]);
362
+ return mintSealedCheckpointCtx({ ...stored, body: next });
363
+ }
324
364
  //# sourceMappingURL=checkpoint-ctx.js.map
@@ -18,6 +18,10 @@ import type { IncomingMessage, ServerResponse } from "node:http";
18
18
  import type { ServiceConfig } from "../config-types.js";
19
19
  import type { RouteCtxBase, RunRegistry } from "./route-ctx.js";
20
20
  import type { FlatServiceDeps } from "./server.js";
21
+ /** `/health` 的 `mods` 段(运维声明的 mod 包装上了几只;present-iff 装上了)—— 段的键集属主,自铸 wire 值登记表 `healthModsKey` 绑它。 */
22
+ export interface HealthDeploymentModsSection {
23
+ readonly deploymentPackages: number;
24
+ }
21
25
  /**
22
26
  * 🔴 [ref](test T-72 [ref];主会话裁 ①,分诊 [ref])—— 全局服务凭据门**之前**那几族只读路
23
27
  * (`route-table.ts` 里 `position: "read-credential"` 的行)的**唯一**鉴权谓词:「服务凭据 ∨ 已验 principal」。