@sema-agent/server 7.145.0 → 7.147.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 (526) hide show
  1. package/MIGRATION.md +876 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +374 -99
  5. package/deploy/facts/CHANGES.json +25 -0
  6. package/deploy/facts/README.md +57 -0
  7. package/deploy/facts/lanes.json +61 -0
  8. package/deploy/facts/lanes.schema.json +57 -0
  9. package/deploy/facts/sandbox-rbac.json +113 -0
  10. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  11. package/deploy/facts/sealed-key.json +9 -0
  12. package/deploy/facts/sealed-key.schema.json +52 -0
  13. package/deploy/sema-up/README.md +2 -2
  14. package/deploy/sema-up/chart/templates/_helpers.tpl +41 -0
  15. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  16. package/deploy/sema-up/chart/templates/server-v4pro.yaml +9 -4
  17. package/deploy/sema-up/chart/templates/server.yaml +9 -4
  18. package/deploy/sema-up/chart/values.yaml +8 -1
  19. package/deploy/sema-up/cluster-up.sh +2 -1
  20. package/deploy/sema-up/lib/flagshape.sh +4 -0
  21. package/deploy/sema-up/lib/lanes.json +2 -5
  22. package/deploy/sema-up/sema-up.sh +12 -9
  23. package/deploy/sema-up/stack/compose.yaml +5 -4
  24. package/deploy/sema-up/stack/sema-stack-cluster.yaml +34 -17
  25. package/dist/adoption/import-limits.d.ts +6 -0
  26. package/dist/adoption/import-limits.js +7 -0
  27. package/dist/adoption/import.d.ts +62 -0
  28. package/dist/adoption/import.js +107 -0
  29. package/dist/adoption/wire.d.ts +52 -0
  30. package/dist/adoption/wire.js +9 -0
  31. package/dist/approval-ask-machine.d.ts +2 -2
  32. package/dist/approval-card.d.ts +7 -16
  33. package/dist/approval-card.js +0 -4
  34. package/dist/approval-gate-currency.d.ts +1 -1
  35. package/dist/approval-gate-currency.js +1 -1
  36. package/dist/approval-reconciler.d.ts +1 -1
  37. package/dist/approval.d.ts +3 -3
  38. package/dist/audit.js +2 -2
  39. package/dist/bench/s1/live-deps.js +3 -1
  40. package/dist/boot/crash-last.js +2 -1
  41. package/dist/boot/deployment-mods.d.ts +11 -1
  42. package/dist/boot/deployment-mods.js +15 -2
  43. package/dist/boot/device-lane.js +7 -5
  44. package/dist/boot/engine-lease.d.ts +195 -22
  45. package/dist/boot/engine-lease.js +146 -20
  46. package/dist/boot/execution-env.d.ts +5 -0
  47. package/dist/boot/execution-env.js +57 -33
  48. package/dist/boot/execution-lane.d.ts +37 -9
  49. package/dist/boot/execution-lane.js +74 -20
  50. package/dist/boot/exit-boundary.d.ts +50 -0
  51. package/dist/boot/exit-boundary.js +32 -0
  52. package/dist/boot/exit-last.d.ts +20 -4
  53. package/dist/boot/exit-last.js +23 -5
  54. package/dist/boot/governance-seams.d.ts +2 -2
  55. package/dist/boot/governance-seams.js +1 -0
  56. package/dist/boot/leader.js +1 -1
  57. package/dist/boot/memory-boundary.d.ts +11 -11
  58. package/dist/boot/memory-boundary.js +3 -3
  59. package/dist/boot/memory-consolidation.d.ts +42 -41
  60. package/dist/boot/memory-consolidation.js +26 -28
  61. package/dist/boot/org-memory.js +3 -2
  62. package/dist/boot/parked-revive-gate.d.ts +1 -1
  63. package/dist/boot/parked-revive-gate.js +1 -1
  64. package/dist/boot/reapers.d.ts +12 -4
  65. package/dist/boot/reapers.js +40 -16
  66. package/dist/boot/resolve-spec.d.ts +2 -0
  67. package/dist/boot/resolve-spec.js +126 -123
  68. package/dist/boot/retention-lane.d.ts +4 -42
  69. package/dist/boot/runner-deps.js +1 -1
  70. package/dist/boot/session-faces.d.ts +1 -0
  71. package/dist/boot/session-faces.js +11 -3
  72. package/dist/boot/shutdown.js +27 -9
  73. package/dist/boot/stage-01-config.d.ts +1 -1
  74. package/dist/boot/stage-01-config.js +7 -3
  75. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  76. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  77. package/dist/boot/stage-03-store-backend.d.ts +2 -1
  78. package/dist/boot/stage-03-store-backend.js +2 -2
  79. package/dist/boot/stage-04-stores.d.ts +2 -1
  80. package/dist/boot/stage-05-execution-env.d.ts +4 -1
  81. package/dist/boot/stage-05-execution-env.js +6 -6
  82. package/dist/boot/stage-06-runners.d.ts +5 -2
  83. package/dist/boot/stage-06-runners.js +12 -13
  84. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  85. package/dist/boot/stage-07-capability-layer.js +7 -7
  86. package/dist/boot/stage-08-reapers.d.ts +5 -2
  87. package/dist/boot/stage-08-reapers.js +3 -3
  88. package/dist/boot/stage-09-leader.d.ts +6 -2
  89. package/dist/boot/stage-10-http-server.d.ts +6 -2
  90. package/dist/boot/stage-10-http-server.js +5 -3
  91. package/dist/boot/stores.d.ts +10 -0
  92. package/dist/boot/stores.js +53 -26
  93. package/dist/boot/web-admin.js +3 -3
  94. package/dist/boot/workflow-orchestration.d.ts +1 -1
  95. package/dist/boot/workflow-orchestration.js +2 -1
  96. package/dist/capabilities/center-plugins.d.ts +2 -0
  97. package/dist/capabilities/center-plugins.js +6 -2
  98. package/dist/capabilities/composite-members.d.ts +4 -1
  99. package/dist/capabilities/composite-members.js +4 -1
  100. package/dist/capabilities/execution-lane.d.ts +7 -7
  101. package/dist/capabilities/execution-lane.js +2 -2
  102. package/dist/capabilities/hands-lane.d.ts +1 -1
  103. package/dist/capabilities/scenarios.d.ts +34 -20
  104. package/dist/capabilities/scenarios.js +13 -9
  105. package/dist/capabilities/settings-contract.d.ts +29 -0
  106. package/dist/capabilities/settings-contract.js +14 -0
  107. package/dist/capabilities/skills.d.ts +5 -5
  108. package/dist/capability-facts.d.ts +56 -1
  109. package/dist/capability-facts.js +59 -8
  110. package/dist/center-credential-renewer.js +3 -2
  111. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  112. package/dist/config-catalog.js +19 -9
  113. package/dist/config-invariants.d.ts +18 -3
  114. package/dist/config-invariants.js +36 -19
  115. package/dist/config-lkg.d.ts +1 -1
  116. package/dist/config-lkg.js +5 -6
  117. package/dist/config-provider.d.ts +2 -2
  118. package/dist/config-provider.js +2 -0
  119. package/dist/config-types.d.ts +228 -185
  120. package/dist/config.d.ts +74 -6
  121. package/dist/config.js +146 -64
  122. package/dist/degenerate-instrument.js +1 -1
  123. package/dist/deleted-session-ids.d.ts +19 -0
  124. package/dist/deleted-session-ids.js +26 -0
  125. package/dist/deploy-facts.d.ts +155 -0
  126. package/dist/deploy-facts.js +95 -0
  127. package/dist/deployment-shape.d.ts +21 -12
  128. package/dist/deployment-shape.js +24 -6
  129. package/dist/device-ws-hub.d.ts +48 -3
  130. package/dist/device-ws-hub.js +48 -2
  131. package/dist/env-facts.d.ts +7 -5
  132. package/dist/env-facts.js +10 -6
  133. package/dist/error-code-family.d.ts +35 -0
  134. package/dist/error-code-family.js +26 -0
  135. package/dist/execution-config-root.d.ts +5 -5
  136. package/dist/execution-config-root.js +5 -5
  137. package/dist/execution-env-purpose.d.ts +14 -0
  138. package/dist/execution-env-purpose.js +29 -0
  139. package/dist/execution-lane-caps.d.ts +49 -86
  140. package/dist/execution-lane-caps.js +52 -62
  141. package/dist/execution-placement.d.ts +18 -2
  142. package/dist/execution-placement.js +19 -0
  143. package/dist/file-history-disclosure.d.ts +2 -2
  144. package/dist/fleet/drain-entry.d.ts +46 -3
  145. package/dist/fleet/drain-entry.js +6 -0
  146. package/dist/fleet/fleet-bus.d.ts +2 -1
  147. package/dist/fleet/serving-lease.js +3 -4
  148. package/dist/history-anchor.d.ts +22 -0
  149. package/dist/history-anchor.js +14 -0
  150. package/dist/hooks/branch-transcript.d.ts +1 -1
  151. package/dist/hooks/branch-transcript.js +1 -0
  152. package/dist/hooks/classic-stations.d.ts +25 -8
  153. package/dist/hooks/classic-stations.js +29 -3
  154. package/dist/hooks/command-spawn.d.ts +1 -4
  155. package/dist/hooks/command-spawn.js +0 -11
  156. package/dist/hooks/hook-runner.d.ts +85 -24
  157. package/dist/hooks/hook-runner.js +326 -109
  158. package/dist/hooks/hook-source.d.ts +14 -2
  159. package/dist/hooks/hook-source.js +8 -0
  160. package/dist/http/active-run-conflict.d.ts +1 -1
  161. package/dist/http/active-run-conflict.js +1 -1
  162. package/dist/http/admission.js +11 -1
  163. package/dist/http/approval-sweeps.d.ts +2 -5
  164. package/dist/http/approval-sweeps.js +3 -2
  165. package/dist/http/checkpoint-ctx.d.ts +76 -71
  166. package/dist/http/checkpoint-ctx.js +40 -40
  167. package/dist/http/claim-latency.d.ts +10 -0
  168. package/dist/http/claim-latency.js +12 -0
  169. package/dist/http/dispatch.js +19 -3
  170. package/dist/http/durable-run-leg.d.ts +5 -0
  171. package/dist/http/durable-run-leg.js +3 -1
  172. package/dist/http/execution-context.d.ts +7 -1
  173. package/dist/http/execution-context.js +13 -0
  174. package/dist/http/health-self-report.d.ts +6 -2
  175. package/dist/http/health-self-report.js +3 -2
  176. package/dist/http/memory-compliance-failure-reply.d.ts +2 -2
  177. package/dist/http/memory-compliance-failure-reply.js +5 -15
  178. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  179. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  180. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  181. package/dist/http/memory-store-refusal-reply.js +3 -0
  182. package/dist/http/owner-access.d.ts +11 -0
  183. package/dist/http/owner-access.js +7 -4
  184. package/dist/http/principal-gate.d.ts +28 -16
  185. package/dist/http/principal-gate.js +10 -19
  186. package/dist/http/request-guards.d.ts +2 -2
  187. package/dist/http/request-guards.js +5 -5
  188. package/dist/http/resume-legs.d.ts +29 -10
  189. package/dist/http/resume-legs.js +94 -56
  190. package/dist/http/rewind-files-reply.d.ts +34 -0
  191. package/dist/http/rewind-files-reply.js +36 -0
  192. package/dist/http/route-ctx.d.ts +43 -26
  193. package/dist/http/route-table.js +4 -0
  194. package/dist/http/routes/adoption.d.ts +11 -0
  195. package/dist/http/routes/adoption.js +80 -6
  196. package/dist/http/routes/agents-roster.js +1 -0
  197. package/dist/http/routes/approvals-assistant.js +7 -26
  198. package/dist/http/routes/background.js +1 -0
  199. package/dist/http/routes/capabilities.js +12 -3
  200. package/dist/http/routes/devices.js +1 -1
  201. package/dist/http/routes/diagnostics.d.ts +9 -14
  202. package/dist/http/routes/diagnostics.js +10 -20
  203. package/dist/http/routes/engine.d.ts +31 -0
  204. package/dist/http/routes/engine.js +81 -0
  205. package/dist/http/routes/memory-bundle.js +3 -0
  206. package/dist/http/routes/memory-consolidation.js +3 -5
  207. package/dist/http/routes/memory-origin.d.ts +2 -2
  208. package/dist/http/routes/memory-origin.js +2 -4
  209. package/dist/http/routes/memory-policy.js +5 -1
  210. package/dist/http/routes/notify-wake.js +2 -1
  211. package/dist/http/routes/observability.js +3 -6
  212. package/dist/http/routes/projects.d.ts +70 -0
  213. package/dist/http/routes/projects.js +86 -0
  214. package/dist/http/routes/rules.js +30 -2
  215. package/dist/http/routes/runs.js +15 -11
  216. package/dist/http/routes/session-sync.js +39 -35
  217. package/dist/http/routes/sessions-list.d.ts +1 -1
  218. package/dist/http/routes/sessions.d.ts +7 -1
  219. package/dist/http/routes/sessions.js +108 -2
  220. package/dist/http/routes/tasks.js +32 -8
  221. package/dist/http/routes/trace-usage.js +1 -1
  222. package/dist/http/run-concurrency-cap.d.ts +86 -0
  223. package/dist/http/run-concurrency-cap.js +54 -0
  224. package/dist/http/server.d.ts +31 -14
  225. package/dist/http/server.js +29 -3
  226. package/dist/http/stored-body-replay.d.ts +12 -7
  227. package/dist/http/stored-body-replay.js +28 -5
  228. package/dist/http/wire-types.d.ts +27 -13
  229. package/dist/index.d.ts +2 -2
  230. package/dist/index.js +1 -1
  231. package/dist/instruction-source-notice.d.ts +1 -1
  232. package/dist/json-body-limit.d.ts +8 -0
  233. package/dist/json-body-limit.js +2 -0
  234. package/dist/leader/diffout.d.ts +1 -1
  235. package/dist/local-data-root.d.ts +2 -2
  236. package/dist/memory-embedder-reembed.d.ts +38 -0
  237. package/dist/memory-embedder-reembed.js +20 -0
  238. package/dist/memory-incident-sink.d.ts +0 -28
  239. package/dist/memory-incident-sink.js +5 -0
  240. package/dist/memory-operator-faces.d.ts +9 -4
  241. package/dist/memory-scope-stores.d.ts +9 -7
  242. package/dist/memory-scope-stores.js +3 -14
  243. package/dist/memory-scope.d.ts +38 -2
  244. package/dist/memory-scope.js +33 -2
  245. package/dist/memory-store-refusal.d.ts +17 -4
  246. package/dist/memory-store-refusal.js +1 -1
  247. package/dist/memory-sync-client.d.ts +2 -0
  248. package/dist/memory-sync-client.js +13 -11
  249. package/dist/memory-sync.js +1 -1
  250. package/dist/model-compat.d.ts +35 -21
  251. package/dist/model-compat.js +49 -21
  252. package/dist/model-entry-refusal.d.ts +11 -1
  253. package/dist/model-entry-refusal.js +7 -0
  254. package/dist/namespaced-rule-name.d.ts +18 -1
  255. package/dist/namespaced-rule-name.js +12 -0
  256. package/dist/net-address.d.ts +53 -0
  257. package/dist/net-address.js +111 -0
  258. package/dist/observability/fail-open.d.ts +29 -17
  259. package/dist/observability/fail-open.js +29 -17
  260. package/dist/observability/metrics.d.ts +2 -0
  261. package/dist/observability/metrics.js +2 -0
  262. package/dist/observability/secret-env-scrub.d.ts +30 -4
  263. package/dist/observability/secret-env-scrub.js +15 -3
  264. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  265. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  266. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  267. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  268. package/dist/orchestration/workflow-notify-journal.js +2 -3
  269. package/dist/org-delivery-gate.js +1 -1
  270. package/dist/org-memory-admission.d.ts +5 -2
  271. package/dist/org-memory-admission.js +25 -10
  272. package/dist/parked-decide.d.ts +33 -26
  273. package/dist/parked-decide.js +36 -44
  274. package/dist/peer-directory.d.ts +6 -12
  275. package/dist/peer-directory.js +5 -1
  276. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  277. package/dist/plugins/approval-ask-store-file.js +37 -4
  278. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  279. package/dist/plugins/approval-ask-store-memory.js +11 -2
  280. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  281. package/dist/plugins/approval-ask-store-sql.js +3 -1
  282. package/dist/plugins/blob-backend.d.ts +38 -195
  283. package/dist/plugins/blob-backend.js +33 -229
  284. package/dist/plugins/caching-session-store.d.ts +12 -5
  285. package/dist/plugins/caching-session-store.js +3 -0
  286. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  287. package/dist/plugins/checkpoint-index-columns.js +3 -2
  288. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  289. package/dist/plugins/checkpoint-store-face.js +152 -0
  290. package/dist/plugins/device-store-sql.d.ts +2 -2
  291. package/dist/plugins/device-store-sql.js +5 -10
  292. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  293. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  294. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  295. package/dist/plugins/execution-placement-sql.js +94 -54
  296. package/dist/plugins/file-run-store.d.ts +26 -18
  297. package/dist/plugins/file-run-store.js +64 -75
  298. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  299. package/dist/plugins/fork-routing-session-store.js +2 -2
  300. package/dist/plugins/imported-layer-root-retirement.d.ts +22 -11
  301. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  302. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  303. package/dist/plugins/inbox-payload-column.js +13 -0
  304. package/dist/plugins/local-checkpoint-store.d.ts +7 -2
  305. package/dist/plugins/local-checkpoint-store.js +13 -8
  306. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  307. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  308. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  309. package/dist/plugins/local-engine-high-water.js +59 -0
  310. package/dist/plugins/local-session-store.d.ts +119 -30
  311. package/dist/plugins/local-session-store.js +156 -53
  312. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  313. package/dist/plugins/local-task-attachment-store.js +10 -11
  314. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  315. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  316. package/dist/plugins/memory-embedder.d.ts +1 -1
  317. package/dist/plugins/memory-embedder.js +2 -2
  318. package/dist/plugins/memory-engine-pg.d.ts +30 -6
  319. package/dist/plugins/memory-engine-pg.js +96 -214
  320. package/dist/plugins/memory-engine-sql-apply.d.ts +130 -0
  321. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  322. package/dist/plugins/memory-engine-tidb.d.ts +38 -9
  323. package/dist/plugins/memory-engine-tidb.js +99 -230
  324. package/dist/plugins/memory-key-guards.d.ts +1 -1
  325. package/dist/plugins/memory-origin-law.d.ts +3 -3
  326. package/dist/plugins/one-time-migrations.d.ts +169 -83
  327. package/dist/plugins/one-time-migrations.js +295 -235
  328. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  329. package/dist/plugins/owner-only-file-mode.js +141 -0
  330. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  331. package/dist/plugins/permission-rule-store-file.js +20 -1
  332. package/dist/plugins/pg-pool.d.ts +2 -1
  333. package/dist/plugins/pg-pool.js +12 -5
  334. package/dist/plugins/release-version.d.ts +20 -0
  335. package/dist/plugins/release-version.js +28 -0
  336. package/dist/plugins/remote-env-adb.d.ts +20 -4
  337. package/dist/plugins/remote-env-adb.js +39 -11
  338. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  339. package/dist/plugins/remote-env-e2b.js +6 -4
  340. package/dist/plugins/remote-env-host.d.ts +9 -1
  341. package/dist/plugins/remote-env-host.js +6 -5
  342. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  343. package/dist/plugins/remote-env-k8s.js +15 -4
  344. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  345. package/dist/plugins/remote-env-local-docker.js +3 -3
  346. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  347. package/dist/plugins/remote-env-ssh.js +26 -24
  348. package/dist/plugins/remote-shell.d.ts +59 -30
  349. package/dist/plugins/remote-shell.js +175 -62
  350. package/dist/plugins/retention-declaration.d.ts +37 -0
  351. package/dist/plugins/retention-declaration.js +9 -0
  352. package/dist/plugins/retention-deployment.d.ts +126 -0
  353. package/dist/plugins/retention-deployment.js +88 -0
  354. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  355. package/dist/plugins/retention-lane-store-sql.js +103 -1
  356. package/dist/plugins/retention-sql.d.ts +29 -0
  357. package/dist/plugins/retention-sql.js +8 -0
  358. package/dist/plugins/run-store-sql.js +2 -2
  359. package/dist/plugins/schema-consistency.d.ts +0 -6
  360. package/dist/plugins/schema-consistency.js +1 -2
  361. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  362. package/dist/plugins/schema-ensure-legs.js +13 -3
  363. package/dist/plugins/session-ext-table.d.ts +74 -0
  364. package/dist/plugins/session-ext-table.js +121 -0
  365. package/dist/plugins/session-fork.d.ts +31 -9
  366. package/dist/plugins/session-fork.js +3 -2
  367. package/dist/plugins/session-placement.d.ts +4 -2
  368. package/dist/plugins/session-row-sql.d.ts +8 -7
  369. package/dist/plugins/session-row-sql.js +15 -7
  370. package/dist/plugins/session-store-sql.d.ts +131 -0
  371. package/dist/plugins/session-store-sql.js +298 -0
  372. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  373. package/dist/plugins/session-workspace-cell.js +2 -2
  374. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  375. package/dist/plugins/shared-memory-store-sql.js +13 -13
  376. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  377. package/dist/plugins/sql-driver.d.ts +23 -7
  378. package/dist/plugins/sql-driver.js +41 -8
  379. package/dist/plugins/sql-errors.d.ts +5 -2
  380. package/dist/plugins/sql-errors.js +4 -0
  381. package/dist/plugins/sql-json-column.d.ts +5 -1
  382. package/dist/plugins/store-backend.d.ts +46 -16
  383. package/dist/plugins/store-backend.js +192 -69
  384. package/dist/plugins/store-contracts.d.ts +10 -13
  385. package/dist/plugins/store-contracts.js +1 -9
  386. package/dist/plugins/store-sweep.d.ts +63 -0
  387. package/dist/plugins/store-sweep.js +48 -0
  388. package/dist/plugins/task-attachment-store.d.ts +6 -8
  389. package/dist/plugins/task-attachment-store.js +15 -10
  390. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  391. package/dist/plugins/text-column-capacity.d.ts +21 -0
  392. package/dist/plugins/text-column-capacity.js +5 -0
  393. package/dist/plugins/tidb-pool.d.ts +3 -2
  394. package/dist/plugins/tidb-pool.js +20 -32
  395. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  396. package/dist/prompt-screen.d.ts +6 -9
  397. package/dist/prompt-screen.js +2 -5
  398. package/dist/read-face-posture.d.ts +6 -6
  399. package/dist/read-face-posture.js +2 -2
  400. package/dist/request-value-closure.d.ts +5 -5
  401. package/dist/request-value-closure.js +1 -1
  402. package/dist/rules-consent.d.ts +48 -27
  403. package/dist/rules-consent.js +147 -23
  404. package/dist/run-cancel-context.d.ts +4 -1
  405. package/dist/run-cancel-context.js +2 -1
  406. package/dist/run-local.js +17 -13
  407. package/dist/runs.d.ts +48 -30
  408. package/dist/runs.js +27 -17
  409. package/dist/runtime-caps-resolver.d.ts +15 -8
  410. package/dist/runtime-caps-resolver.js +14 -10
  411. package/dist/sandbox-egress-policy.js +6 -11
  412. package/dist/sandbox-rbac-rules.d.ts +88 -0
  413. package/dist/sandbox-rbac-rules.js +80 -0
  414. package/dist/sealed-key-layout.d.ts +16 -0
  415. package/dist/sealed-key-layout.js +3 -0
  416. package/dist/sealed-key.js +8 -6
  417. package/dist/security.d.ts +43 -9
  418. package/dist/security.js +9 -2
  419. package/dist/sema-config-dir.js +2 -2
  420. package/dist/server-secret-env.d.ts +2 -0
  421. package/dist/service-version.d.ts +2 -1
  422. package/dist/service-version.js +2 -2
  423. package/dist/session-error-wire.d.ts +1 -1
  424. package/dist/session-incarnation.d.ts +8 -5
  425. package/dist/session-notify-door.d.ts +5 -3
  426. package/dist/session-resident-background.d.ts +110 -0
  427. package/dist/session-resident-background.js +88 -0
  428. package/dist/session-row.d.ts +1 -1
  429. package/dist/session-sync-kernel.d.ts +53 -14
  430. package/dist/session-sync-kernel.js +70 -1
  431. package/dist/session-sync.d.ts +5 -3
  432. package/dist/session-workspace.d.ts +12 -2
  433. package/dist/session-workspace.js +6 -0
  434. package/dist/sighup-idle.d.ts +9 -7
  435. package/dist/sighup-idle.js +4 -5
  436. package/dist/spec-fields.d.ts +16 -0
  437. package/dist/spec-fields.js +7 -0
  438. package/dist/store-posture.d.ts +2 -1
  439. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  440. package/dist/stored-request-env-credentials-m38.js +8 -0
  441. package/dist/stored-request-hooks-m20.d.ts +3 -2
  442. package/dist/stored-request-hooks-m20.js +19 -14
  443. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  444. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  445. package/dist/stores-sql/blob-index-sql.js +154 -0
  446. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +14 -428
  447. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +43 -220
  448. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  449. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  450. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  451. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  452. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +27 -67
  453. package/dist/{plugins → stores-sql}/pg-session-storage.js +82 -207
  454. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  455. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  456. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  457. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  458. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  459. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  460. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  461. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  462. package/dist/stores-sql/session-write-hooks.js +2 -0
  463. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  464. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  465. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +35 -112
  466. package/dist/{plugins → stores-sql}/tidb-session-store.js +73 -169
  467. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +3 -3
  468. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  469. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  470. package/dist/stores-sql/windowed-session-storage.js +61 -0
  471. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  472. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  473. package/dist/task-a2a.d.ts +7 -1
  474. package/dist/task-a2a.js +15 -14
  475. package/dist/task-cwd.d.ts +11 -3
  476. package/dist/task-cwd.js +17 -1
  477. package/dist/task-mcp.d.ts +10 -2
  478. package/dist/task-mcp.js +13 -16
  479. package/dist/task-settings.d.ts +68 -8
  480. package/dist/task-settings.js +63 -6
  481. package/dist/tool-approval.d.ts +23 -10
  482. package/dist/tool-approval.js +10 -6
  483. package/dist/trace/core-keyset-guard.d.ts +17 -10
  484. package/dist/trace/engine-notice-wire.d.ts +1 -1
  485. package/dist/trace/engine-notice-wire.js +4 -0
  486. package/dist/trace/exit-seat.d.ts +29 -1
  487. package/dist/trace/exit-seat.js +4 -0
  488. package/dist/trace/project.d.ts +33 -16
  489. package/dist/trace/project.js +21 -9
  490. package/dist/trace/redact.d.ts +13 -2
  491. package/dist/trace/redact.js +347 -78
  492. package/dist/trace/self-minted-wire.d.ts +587 -16
  493. package/dist/trace/self-minted-wire.js +215 -9
  494. package/dist/trace/sema-provenance.d.ts +45 -41
  495. package/dist/trace/sema-provenance.js +81 -10
  496. package/dist/trace/task-notification-facets.d.ts +70 -2
  497. package/dist/trace/task-notification-facets.js +71 -1
  498. package/dist/trace/wire-projection-faces.d.ts +39 -3
  499. package/dist/trace/wire-projection-faces.js +27 -2
  500. package/dist/unread-request-members.d.ts +66 -0
  501. package/dist/unread-request-members.js +41 -0
  502. package/dist/usage-analytics.d.ts +4 -0
  503. package/dist/user-input-ledger.d.ts +2 -2
  504. package/dist/web-admin-client/apply-effective.js +22 -26
  505. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  506. package/dist/web-admin-client/candidate-gate.js +53 -5
  507. package/dist/web-admin-client/center-request.d.ts +4 -1
  508. package/dist/web-admin-client/center-request.js +2 -1
  509. package/dist/web-admin-client/effective-keys.js +0 -1
  510. package/dist/web-admin-client/facade.d.ts +1 -1
  511. package/dist/web-admin-client/http-client.d.ts +1 -0
  512. package/dist/web-admin-client/http-client.js +17 -9
  513. package/dist/web-admin-client/restart-signal.js +5 -2
  514. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  515. package/dist/web-admin-client/skills-mcp.js +26 -21
  516. package/dist/web-admin-client/types.d.ts +34 -49
  517. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  518. package/package.json +22 -13
  519. package/scripts/drain-check-local.mjs +8 -55
  520. package/scripts/drain-check.mysql.sql +3 -40
  521. package/scripts/drain-check.pg.sql +3 -40
  522. package/skills/update-config.md +1 -1
  523. package/wire-changes/server@7.146.0.json +3221 -0
  524. package/wire-changes/server@7.147.0.json +813 -0
  525. package/dist/approval-batch-census.d.ts +0 -27
  526. package/dist/approval-batch-census.js +0 -27
@@ -1,13 +1,13 @@
1
1
  import { homedir } from "node:os";
2
2
  import { StubExecutionEnv } from "@sema-agent/core";
3
- import { EXECUTION_LANE_WORDS as DECLARABLE_LANE_WORDS, EXECUTION_LANES, isBlankCoordinate, retiredLaneWordRefusal } from "@sema-agent/settings-schema/execution-lanes";
3
+ import { EXECUTION_LANE_WORDS as DECLARABLE_LANE_WORDS, EXECUTION_LANES, LANE_SET_RULE, isBlankCoordinate, laneSetFlaws, retiredLaneWordRefusal } from "@sema-agent/settings-schema/execution-lanes";
4
4
  import { DECLARE_HOME_REMEDY, LANE_HOME_UNDECLARED_EVENT, LANE_HOME_UNMEASURED_EVENT, buildHomeAbsentNote, buildHomeUnmeasuredNote } from "./lane-home-probe.js";
5
5
  const NO = "unsupported";
6
6
  const YES = "supported";
7
7
  const SU = "single-user-only";
8
8
  export function executionLaneCaps(lane) {
9
9
  switch (lane) {
10
- case "in-process":
10
+ case "none":
11
11
  return {
12
12
  callerCwd: NO,
13
13
  backgroundShell: NO,
@@ -16,7 +16,7 @@ export function executionLaneCaps(lane) {
16
16
  sandboxSendUserFile: NO,
17
17
  remoteScratchpad: NO,
18
18
  worktreeIsolation: NO,
19
- tenantSeparation: YES,
19
+ tenantSeparation: executionLaneRow(lane).tenantSeparation,
20
20
  };
21
21
  case "host":
22
22
  return {
@@ -119,7 +119,7 @@ export function sandboxReadFloorState(lane, knob) {
119
119
  return readFloorStateOf(k, false);
120
120
  }
121
121
  }
122
- const IN_PROCESS_BLOCK = new StubExecutionEnv().capabilities;
122
+ const NONE_BLOCK = new StubExecutionEnv().capabilities;
123
123
  const HOST_BLOCK = Object.freeze({ isolation: false, suspendable: false, sharesProcessTable: true, canonicalPathAuthoritative: true, hostLocalPaths: true, externalContentTarget: false, io: true, keepsReadFloor: false });
124
124
  const E2B_SHAPE = Object.freeze({ isolation: true, suspendable: true, sharesProcessTable: false, canonicalPathAuthoritative: true, hostLocalPaths: false, externalContentTarget: false, io: true });
125
125
  const K8S_SHAPE = Object.freeze({ isolation: true, suspendable: false, sharesProcessTable: false, canonicalPathAuthoritative: true, hostLocalPaths: false, externalContentTarget: false, io: true });
@@ -144,8 +144,8 @@ const DEVICE_BLOCK = Object.freeze({ isolation: false, suspendable: false, share
144
144
  const NO_SUB_KNOBS = Object.freeze({ snapshotStore: false, sandboxReadFloor: undefined });
145
145
  function laneBlock(lane, sub) {
146
146
  switch (lane) {
147
- case "in-process":
148
- return IN_PROCESS_BLOCK;
147
+ case "none":
148
+ return NONE_BLOCK;
149
149
  case "host":
150
150
  return HOST_BLOCK;
151
151
  case "e2b":
@@ -161,13 +161,13 @@ function laneBlock(lane, sub) {
161
161
  }
162
162
  }
163
163
  export function capabilitiesFor(deployment) {
164
- const lane = executionLaneOf(deployment.remoteExec?.provider);
164
+ const lane = executionLaneOf(deployment.remoteExec.provider);
165
165
  if (lane === undefined)
166
166
  return undefined;
167
- return laneBlock(lane, { snapshotStore: lane === "k8s" && Boolean(deployment.remoteExec?.s3Snapshot), sandboxReadFloor: deployment.sandboxReadFloor });
167
+ return laneBlock(lane, { snapshotStore: lane === "k8s" && Boolean(deployment.remoteExec.s3Snapshot), sandboxReadFloor: deployment.sandboxReadFloor });
168
168
  }
169
169
  export function laneSandboxReadFloorState(deployment) {
170
- const lane = executionLaneOf(deployment.remoteExec?.provider);
170
+ const lane = executionLaneOf(deployment.remoteExec.provider);
171
171
  if (lane === undefined)
172
172
  return undefined;
173
173
  switch (lane) {
@@ -175,7 +175,7 @@ export function laneSandboxReadFloorState(deployment) {
175
175
  case "k8s":
176
176
  case "local-docker":
177
177
  return sandboxReadFloorState(lane, deployment.sandboxReadFloor);
178
- case "in-process":
178
+ case "none":
179
179
  case "host":
180
180
  case "ssh":
181
181
  case "adb":
@@ -183,12 +183,11 @@ export function laneSandboxReadFloorState(deployment) {
183
183
  return undefined;
184
184
  }
185
185
  }
186
- export const ALL_EXECUTION_LANES = Object.freeze(["in-process", ...DECLARABLE_LANE_WORDS]);
186
+ export const ALL_EXECUTION_LANES = Object.freeze([...DECLARABLE_LANE_WORDS]);
187
187
  const EXECUTION_LANE_SET = new Set(ALL_EXECUTION_LANES);
188
188
  export function isExecutionLane(word) {
189
189
  return EXECUTION_LANE_SET.has(word);
190
190
  }
191
- export const REMOTE_EXEC_PROVIDER_WORDS = Object.freeze([...DECLARABLE_LANE_WORDS]);
192
191
  const LANE_ROWS = (() => {
193
192
  const rows = new Map();
194
193
  for (const row of EXECUTION_LANES) {
@@ -217,53 +216,48 @@ export function isBlankRequiredEnvValue(value) {
217
216
  export function laneMissingEnv(lane, env) {
218
217
  return laneRequiredEnv(lane).filter((name) => isBlankRequiredEnvValue(env[name]));
219
218
  }
219
+ const LANE_ROW_OF_WORD = LANE_ROWS;
220
+ function laneSetFlawPhrase(flaw) {
221
+ switch (flaw.kind) {
222
+ case "empty_set":
223
+ return "it has no entries";
224
+ case "blank_entry":
225
+ return `entry ${flaw.at + 1} is empty or whitespace-only`;
226
+ case "unknown":
227
+ return `"${String(flaw.word)}" (entry ${flaw.at + 1}) is not an execution lane`;
228
+ case "retired":
229
+ return retiredLaneWordRefusal(flaw.word) ?? `"${flaw.word}" (entry ${flaw.at + 1}) is a retired execution lane`;
230
+ case "duplicate":
231
+ return `"${flaw.lane}" is listed twice (again at entry ${flaw.at + 1})`;
232
+ case "not_alone":
233
+ return `"${flaw.lane}" (no execution environment for the agent's tools) must be the only entry`;
234
+ }
235
+ }
220
236
  export function readDeclaredLaneTable(raw) {
221
237
  const segments = raw.split(",");
222
- const lanes = [];
223
- for (const [i, segment] of segments.entries()) {
224
- if (segment === "") {
225
- return { refusal: `REMOTE_EXEC="${raw}" has an empty entry at position ${i + 1} — it is an ordered, comma-separated list of execution lanes (the first is the default) with no blank entries; valid lanes: ${REMOTE_EXEC_PROVIDER_WORDS.join(" | ")}.` };
226
- }
227
- const lane = REMOTE_EXEC_PROVIDER_WORDS.find((w) => w === segment);
228
- const retired = lane === undefined ? retiredLaneWordRefusal(segment) : undefined;
229
- if (retired !== undefined)
230
- return { refusal: `REMOTE_EXEC="${raw}": ${retired}.` };
231
- if (lane === undefined) {
232
- return {
233
- refusal: `REMOTE_EXEC="${raw}"${segments.length > 1 ? ` lists "${segment}", which` : ""} is not an execution lane — valid: ${REMOTE_EXEC_PROVIDER_WORDS.join(" | ")}. ` +
234
- `An unrecognized value used to fall through to the host/in-process lane silently; refusing to start instead (#157).`,
235
- };
236
- }
237
- if (lanes.includes(lane))
238
- return { refusal: `REMOTE_EXEC="${raw}" lists "${lane}" twice — each execution lane appears once (the first one is the default).` };
239
- lanes.push(lane);
238
+ const flaws = laneSetFlaws(segments);
239
+ if (flaws.length > 0) {
240
+ return {
241
+ refusal: `REMOTE_EXEC="${raw}" is not a valid execution lane set: ${flaws.map(laneSetFlawPhrase).join("; ")}. ` +
242
+ `REMOTE_EXEC (the lane set, comma-separated) ${LANE_SET_RULE}. Refusing to start rather than guessing a lane (#157).`,
243
+ };
240
244
  }
245
+ const lanes = segments.map((segment) => {
246
+ const row = LANE_ROW_OF_WORD.get(segment);
247
+ if (row === undefined)
248
+ throw new Error(`readDeclaredLaneTable: the lane-set judge accepted "${segment}" but the lane table has no row for it`);
249
+ return row.lane;
250
+ });
241
251
  const [first, ...rest] = lanes;
242
252
  if (first === undefined)
243
253
  throw new Error(`readDeclaredLaneTable: "${raw}" split into no segments`);
244
254
  return { lanes: [first, ...rest] };
245
255
  }
246
- export function executionLaneRequiredRefusal(deployment) {
247
- if (!deployment.requireExecutionLane || executionLaneOf(deployment.remoteExec?.provider) !== "in-process")
248
- return undefined;
249
- return (`REQUIRE_EXECUTION_LANE=true but NO execution lane is named on this deployment — refusing to start. ` +
250
- `With no lane the engine falls back to its in-process stub environment: the hands band (the roster entries whose ` +
251
- `wiring_manifest mountedBy is "hands", Bash among them) is not mounted, while the rest of the roster still executes, ` +
252
- `and every task still returns status=completed — for any request that needs a hand, indistinguishable from "the model ` +
253
- `chose not to use its tools". (How much of the roster is mounted is a per-run fact: read the wiring_manifest event and ` +
254
- `count entries whose mountedBy is "hands" — never judge by tool names.) ` +
255
- `Cause: REMOTE_EXEC is unset/empty AND CONFIG_PROVIDER is not "local". ` +
256
- `Fix: set REMOTE_EXEC to one of ${REMOTE_EXEC_PROVIDER_WORDS.join(" | ")} (and that lane's required env), ` +
257
- `or set CONFIG_PROVIDER=local to take the single-machine \`host\` default, ` +
258
- `or unset REQUIRE_EXECUTION_LANE to keep running without hands on purpose.`);
259
- }
260
256
  export function executionLaneOf(provider) {
261
- if (provider === undefined)
262
- return "in-process";
263
257
  return isExecutionLane(provider) ? provider : undefined;
264
258
  }
265
259
  export function deployedExecutionLanes(config) {
266
- return [executionLaneOf(config.remoteExec?.provider)];
260
+ return [config.remoteExec.provider];
267
261
  }
268
262
  export function handsOnWorkerFilePlane(lane) {
269
263
  const block = laneBlock(lane, NO_SUB_KNOBS);
@@ -273,7 +267,7 @@ export function laneBindsReads(lane) {
273
267
  switch (lane) {
274
268
  case "host":
275
269
  return true;
276
- case "in-process":
270
+ case "none":
277
271
  case "e2b":
278
272
  case "k8s":
279
273
  case "ssh":
@@ -293,7 +287,7 @@ export function laneMeasuresHome(lane) {
293
287
  case "host":
294
288
  return true;
295
289
  case "device":
296
- case "in-process":
290
+ case "none":
297
291
  return false;
298
292
  }
299
293
  }
@@ -304,7 +298,7 @@ export function laneReadFaceDefault(lane) {
304
298
  case "local-docker":
305
299
  return "open";
306
300
  case "host":
307
- case "in-process":
301
+ case "none":
308
302
  case "ssh":
309
303
  case "adb":
310
304
  case "device":
@@ -324,11 +318,8 @@ export function executionLaneHomeDir(deployment) {
324
318
  const declared = deployment.remoteExecHomeDir;
325
319
  if (declared !== undefined)
326
320
  return declared;
327
- const lane = executionLaneOf(deployment.remoteExec?.provider);
328
- if (lane === undefined)
329
- return undefined;
330
- switch (lane) {
331
- case "in-process":
321
+ switch (deployment.remoteExec.provider) {
322
+ case "none":
332
323
  case "host":
333
324
  return homedir();
334
325
  case "e2b":
@@ -348,23 +339,22 @@ export function buildLaneHomeClaim(deployment) {
348
339
  return { homeDir: home, homeDirSource: deployment.remoteExecHomeDir !== undefined ? "declared" : "lane" };
349
340
  }
350
341
  export function buildLaneHomeBootNote(deployment) {
351
- const lane = executionLaneOf(deployment.remoteExec?.provider);
352
- if (lane === undefined || !laneWiresExecutionEnv(lane))
342
+ const homeLane = deployment.remoteExec.provider;
343
+ if (!laneWiresExecutionEnv(homeLane))
353
344
  return undefined;
354
- if (laneMeasuresHome(lane))
345
+ if (laneMeasuresHome(homeLane))
355
346
  return undefined;
356
347
  const home = executionLaneHomeDir(deployment);
357
348
  if (home === undefined)
358
- return { event: LANE_HOME_UNDECLARED_EVENT, note: buildHomeAbsentNote(lane, "REMOTE_EXEC_HOME_DIR is unset, and this lane cannot read its execution environment's home", DECLARE_HOME_REMEDY) };
359
- return { event: LANE_HOME_UNMEASURED_EVENT, note: buildHomeUnmeasuredNote(lane, home) };
349
+ return { event: LANE_HOME_UNDECLARED_EVENT, note: buildHomeAbsentNote(homeLane, "REMOTE_EXEC_HOME_DIR is unset, and this lane cannot read its execution environment's home", DECLARE_HOME_REMEDY) };
350
+ return { event: LANE_HOME_UNMEASURED_EVENT, note: buildHomeUnmeasuredNote(homeLane, home) };
360
351
  }
361
352
  export function buildReadDenyFloorUnkeptNote(deployment) {
362
353
  if (!deployment.readDenyFloorRequired)
363
354
  return undefined;
364
355
  if (capabilitiesFor(deployment)?.keepsReadFloor === true)
365
356
  return undefined;
366
- const lane = executionLaneOf(deployment.remoteExec?.provider) ?? String(deployment.remoteExec?.provider);
367
- return (`READ_DENY_FLOOR_REQUIRED=true, but the "${lane}" execution lane does not keep the read-deny byte floor (a program its commands run can open a path ` +
357
+ return (`READ_DENY_FLOOR_REQUIRED=true, but the "${deployment.remoteExec.provider}" execution lane does not keep the read-deny byte floor (a program its commands run can open a path ` +
368
358
  `the read-deny table refuses). Every run whose read-deny table has rows — the shipped default tiers put rows there unless READ_DENY_BUILTIN_TIERS=none — ` +
369
359
  `is refused before any command starts (config.read_deny_floor_unkept; a synchronous submit answers 409). ` +
370
360
  `Either run on a lane that keeps the floor, or unset READ_DENY_FLOOR_REQUIRED to run with one operator notice per run instead.`);
@@ -162,8 +162,9 @@ export declare class SessionForkInProgressError extends Error {
162
162
  constructor(sessionId: string);
163
163
  }
164
164
  /**
165
- * 写事务内的认领读命中(读写序律,`plugins/execution-placement-sql.ts` 的 `lockRootAndReadClaim`):改根住客 / 放置的写者在自己的事务里先锁根
166
- * `session_meta` 行、再锁定读 `task_active(root)`,读到认领 ⇒ 回滚、一个字节不写、抛它。只 SQL 后端(local 不立此律:没有 device 工厂)。
165
+ * 写口在写事务 / 写锁内的认领读命中:SQL = 读写序律(`plugins/execution-placement-sql.ts` 的 `lockRootAndReadClaim`:改根住客 / 放置的写者在自己的事务里先锁根
166
+ * `session_meta` 行、再锁定读 `task_active(root)`,读到认领 ⇒ 回滚、一个字节不写、抛它);local = 这只会话的写锁内读 run 店的认领(`markMirror` 返回 `active` 臂;
167
+ * 三个导入写口经 {@link judgeImportWrite} 抛它)—— 删除终刀与 device 首绑在写事务内的认领读仍只在 SQL 后端(local 没有 device 工厂)。
167
168
  * 具名类型、**不带 wire 码**:各门按自己的既有码答(导入 409 `session_active`、删除 409 `conflict.session_active_run`),体带 `activeTaskId`。
168
169
  */
169
170
  export declare class SessionActiveRunError extends Error {
@@ -181,6 +182,21 @@ export declare const WRITABLE: "writable";
181
182
  export declare function settledPlaceOutcome(root: string, reading: ExecutionPlacementReading | undefined, occupant: SessionFace, wanted: ExecutionWriterCell): PlaceOutcome | typeof WRITABLE;
182
183
  /** markMirror 的唯一判官(认领那一半在本判官之后,SQL 与 local 各在自己的写事务 / 写锁内判):行不在 / 住客不同 ⇒ `gone`;writer ⇒ `writer`;mirror ⇒ `mirrored`(幂等,零写);absent ⇒ {@link WRITABLE};forking ⇒ 抛。 */
183
184
  export declare function settledMirrorOutcome(root: string, reading: ExecutionPlacementReading | undefined, occupant: SessionFace): MarkMirrorOutcome | typeof WRITABLE;
185
+ /** {@link judgeImportWrite} 的判:放行,或拒(拒的载荷是写口抛的那只 typed 错;SQL 的事务内钩原样交给店,local 直接抛)。 */
186
+ export type ImportWriteVerdict = "proceed" | {
187
+ readonly refuse: SessionActiveRunError | SessionWriterPresentError | SessionForkInProgressError;
188
+ };
189
+ /**
190
+ * 三个导入写口(整段 `importEntries` / `replaceEntries` / 暂存提交)落定这一行**之前**的唯一判官,**连序**在内(SQL 的事务内钩 `import` 臂与 local 的写锁内同调,两店不各抄一份):
191
+ * 先读认领 —— 在 ⇒ {@link SessionActiveRunError};再读这一格 —— `writer` ⇒ {@link SessionWriterPresentError}(带车道)、`forking` ⇒ {@link SessionForkInProgressError};
192
+ * `absent` / `mirror` ⇒ 放行(落 mirror 由调用方写)。读口由调用方给、**按需读**:认领在 ⇒ 不读格(SQL:不发格那一句锁定读;local:不探存档)。
193
+ * 读与判必须在写者独占的同一刻里:SQL = 锁根行之后、同一连接;local = 这只会话的写锁内、写格之前(取锁 → 读认领 → 判 → 写)。
194
+ * 返回判、不抛:拒之后一个字节不写由调用方保证(SQL 回滚,local 判在第一笔写之前)。
195
+ */
196
+ export declare function judgeImportWrite(root: string, read: {
197
+ readonly claim: () => Promise<string | null | undefined>;
198
+ readonly cell: () => Promise<ExecutionPlacementCell>;
199
+ }): Promise<ImportWriteVerdict>;
184
200
  /** device 车道首绑(absent → writer(device, D) 或 writer(device, ∅) → writer(device, D))的结果(设备店的事务 / 内存参照实现同调)。 */
185
201
  export type DeviceBindOutcome = {
186
202
  readonly outcome: "bound";
@@ -94,6 +94,25 @@ export function settledMirrorOutcome(root, reading, occupant) {
94
94
  }
95
95
  }
96
96
  }
97
+ export async function judgeImportWrite(root, read) {
98
+ const claim = await read.claim();
99
+ if (claim !== null && claim !== undefined)
100
+ return { refuse: new SessionActiveRunError(root, claim) };
101
+ const cell = await read.cell();
102
+ switch (cell.role) {
103
+ case "writer":
104
+ return { refuse: new SessionWriterPresentError(root, cell.lane) };
105
+ case "forking":
106
+ return { refuse: new SessionForkInProgressError(root) };
107
+ case "absent":
108
+ case "mirror":
109
+ return "proceed";
110
+ default: {
111
+ const unknownRole = cell;
112
+ throw new Error(`judgeImportWrite: no arm for ${JSON.stringify(unknownRole)}`);
113
+ }
114
+ }
115
+ }
97
116
  export function settledDeviceBindOutcome(root, reading, occupant, deviceId) {
98
117
  if (reading === undefined || !sameOccupant(reading.occupant, occupant))
99
118
  return { outcome: "gone" };
@@ -2,9 +2,9 @@
2
2
  * [ref]④ —— SQL file-history 店的 **typed 永久失败**披露座:散文一个铸点 + 机器面一只 sink。
3
3
  *
4
4
  * ## 病(基线 v7.79.0 逐行亲核 + 亲跑)
5
- * `plugins/blob-backend.ts:55` 的 `BlobTooLargeError` 带 typed 判别码 `blob_too_large_for_sql`,头注
5
+ * `stores-sql/blob-index-sql.ts` 的 `BlobTooLargeError` 带 typed 判别码 `blob_too_large_for_sql`,头注
6
6
  * 原话「绝不能与 transient 写失败混在一类(那类是可重试的 502;这类重试永远不会成功)」。可它一旦被
7
- * `plugins/file-history-store-sql.ts` 的任何一条 `catch` 折进 `FileHistoryResult.error.message`,判别码
7
+ * `stores-sql/file-history-store-sql.ts` 的任何一条 `catch` 折进 `FileHistoryResult.error.message`,判别码
8
8
  * 就只剩散文,**机器一位都读不到**。两条腿各自的后果:
9
9
  *
10
10
  * · **snapshot(边界捕获)腿**:引擎把失败包成一句散文交给 `RunnerDeps.onError({phase:"rewind"})`
@@ -30,7 +30,7 @@
30
30
  * 纯类型 + 纯函数叶(值 import 只有 scope 读法叶与 run 行判词叶)。
31
31
  */
32
32
  import type { DrainReceipt, DrainRequest, EngineDraining } from "@sema-agent/settings-schema/fleet";
33
- import type { EngineLeaseFacts } from "../boot/engine-lease.js";
33
+ import type { EngineHandoverDoor, EngineLeaseFacts } from "../boot/engine-lease.js";
34
34
  /**
35
35
  * 引擎自铸的动作号 —— **一张表**(排空事实与回执里不来自请求体的全部拼法;请求体的 `actionId` 由调用方自取):
36
36
  * · {@link ENGINE_DRAIN_CAUSES}:没有请求承载的排空成因(停止信号 / SIGHUP 升级 / 附着租约自退);
@@ -68,6 +68,36 @@ export interface DrainDeadlineRefusal {
68
68
  }
69
69
  /** 入口的答:契约回执(进入 / 已在排空),或期限越界的拒(只在调用方声明了上界时出现)。按 `state` 穷举。 */
70
70
  export type DrainEntryAnswer = DrainReceipt | DrainDeadlineRefusal;
71
+ /**
72
+ * 在飞数的**分项**(`GET /health` 的 `inflightBreakdown`)—— 同一份分项派生**两个事实**,不是两份计数(计法表全文 = 契约 `docs/ASSISTANT-WIRE-CONTRACT.md` 的 `/health` 节):
73
+ * · **总数**(可观测事实,{@link inflightTotal} = `/health.inflight`):这台引擎此刻托管着多少活 = `http + leader + backgroundAgents + sessionResident`;
74
+ * · **阻断集**(判据,{@link blockingInflightOf} = `drainState.blockingInflight`):还有没有**必须等完**的活 = `http + leader + backgroundAgents`。
75
+ * 排空等的、孤儿窗 / 附着租约自退 / SIGHUP 空闲窗判「可以停了吗」读它。`sessionResident` 不在其内。
76
+ * 四项:
77
+ * · `http` —— 本副本的 HTTP 腿:在飞 run 集(`inflightRuns ∪ steerableRuns`)+ 没有登记身份的同步计费腿(`/v1/tasks` 的同步腿)+ admission 期的非探针请求;
78
+ * · `leader` —— leader 口的后台 run(`leaderEndpoint.inflight()`);
79
+ * · `backgroundAgents` —— 活过起它的那一条腿、仍在跑的后台子代理(core `backgroundScope:"session"`;`session-resident-background.ts` 的读法:停驻的不计)。
80
+ * 它进阻断集:它是一条在干活的模型腿,干完自己收尾(在审批 / 问答卡上等人时行仍是 `running`、照计;窗满转成耐久停驻后不再计);不等 = 受控退把还在干活的子代理中断。
81
+ * 上界 = 停滞收割窗 `BG_AGENT_STALL_MS`:读口每读一次先让引擎收掉静默满窗的子代理(挂死的,或收尾时 core 等的那次账本写挂住的)再数 —— 判停窗不再被一只僵尸无界地撑着;
82
+ * SIGTERM 排空另以期限为界;
83
+ * · `sessionResident` —— 会话驻留的后台 shell / monitor(同一读法:不含 retain 行)。
84
+ * 它只进总数、不进阻断集:一只不退出的驻留 shell(`while true`)若阻断,崩溃孤儿引擎就永生、排空每次等满窗;窗到 / 排空完成即由退出边界的后台收割收掉
85
+ * (retain 行按 retain 既有语义,活过受控退)。
86
+ * 不进任何一项的(计法表成文的行):停驻待赎回的 run 与停驻的后台子代理(耐久,不占执行座)· 活过起它的腿的 workflow(任务表分不出它在干活还是在等人,见
87
+ * `session-resident-background.ts` 头注)· retain 的后台 shell · 只读订阅流(只进 `attachedStreams`)。
88
+ * 四项在同一次读里求出(`http/server.ts` 的 `inflightBreakdown` 是唯一的分项函数,两个和都读它),`/health` 的 `inflight` 与 `inflightBreakdown` 因此永远自洽,
89
+ * 判停与 `/health` 也不会各有一份算法。只有这两个函数各写一次这两个和,没有第三张计法表。
90
+ */
91
+ export interface InflightBreakdown {
92
+ readonly http: number;
93
+ readonly leader: number;
94
+ readonly backgroundAgents: number;
95
+ readonly sessionResident: number;
96
+ }
97
+ /** 阻断集 = 必须等完的活 = `drainState.blockingInflight()`(`sessionResident` 不在内)。 */
98
+ export declare function blockingInflightOf(b: InflightBreakdown): number;
99
+ /** 总数 = 引擎此刻托管的全部活 = `/health.inflight`(= 阻断集 + 会话驻留的 shell / monitor 项)。 */
100
+ export declare function inflightTotal(b: InflightBreakdown): number;
71
101
  /**
72
102
  * 引擎与 HTTP 面共享的排空盒子(装配层建一只,`createHttpServer` 与收尾链各自往上装读口 / 入口)。
73
103
  * · `draining` / `since` / `actionId` / `deadlineAt` —— **只由** {@link enter} 整组写入(排空事实 = 契约 `EngineDraining`);
@@ -75,8 +105,8 @@ export type DrainEntryAnswer = DrainReceipt | DrainDeadlineRefusal;
75
105
  * · `yieldInflight` —— 让出本副本在飞的可抢占腿(`createHttpServer` 装);
76
106
  * · `endSubscriptions` —— 关掉本副本打开着的只读订阅流(发一帧 `draining` 终帧再关;`createHttpServer` 装,[ref])。订阅流不是在飞的工作
77
107
  * (不进 `inflight`),排空不等它;收尾链在排空进入那一拍与硬停起点各调一次(排空期间新开的订阅在硬停那一拍收);
78
- * · 其余四只是既有的读口(在飞数 / 活性时钟 / 附着流),语义见 `http/server.ts`。`inflight` 只数**工作**(run 腿 / 计费提交 / HITL 应答 /
79
- * admission 期的普通请求),只读订阅只进 `attachedStreams`([ref])。
108
+ * · 其余五只是既有的读口(在飞数 / 活性时钟两只〔最近一次 / 首次〕/ 附着流两只),语义见 `http/server.ts`。在飞数只数**工作**(run 腿 / 计费提交 / HITL 应答 /
109
+ * admission 期的普通请求),只读订阅只进 `attachedStreams`([ref]);在飞数分两个读口 —— 总数 `inflight`(事实)与阻断集 `blockingInflight`(判据),见 {@link InflightBreakdown}。
80
110
  */
81
111
  export interface DrainState {
82
112
  draining: boolean;
@@ -86,12 +116,25 @@ export interface DrainState {
86
116
  enter?: (entry: DrainEntry) => DrainEntryAnswer;
87
117
  yieldInflight?: () => void;
88
118
  endSubscriptions?: () => void;
119
+ /** **总数**读口(`createHttpServer` 装):引擎此刻托管的全部活 = `inflightTotal(inflightBreakdown())`。可观测事实 —— 只有 `/health` 与崩溃遗言读它;
120
+ * **没有任何「停不停」的判据读它**(判据读 {@link DrainState.blockingInflight})。 */
89
121
  inflight?: () => number;
122
+ /** 分项读口(`createHttpServer` 装,与 `inflight` / `blockingInflight` 同一次装、同一份求值)。`/health` 读它一次,同时出 `inflight` 与 `inflightBreakdown` 两键。 */
123
+ inflightBreakdown?: () => InflightBreakdown;
124
+ /** **阻断集**读口(`createHttpServer` 装):还有没有必须等完的活 = `blockingInflightOf(inflightBreakdown())` = `http + leader + backgroundAgents`。排空等的(`boot/shutdown.ts` 的排空驱动表)、
125
+ * 孤儿窗 / 附着租约自退(`boot/engine-lease.ts`)、SIGHUP 空闲窗(`sighup-idle.ts`)的「可以停了吗」都读它;会话驻留的后台 shell / monitor 不在内。 */
126
+ blockingInflight?: () => number;
90
127
  lastActivityAt?: () => number;
128
+ /** [ref]:首个**非探针**请求的单调时刻(`null` = 还没有过)。与 `lastActivityAt` 同一个写者(`http/server.ts` 的活性打点)、写一次就定;
129
+ * 读者 = 租约腿的候首触态(`boot/engine-lease.ts`)与 `/health.engineLease.firstAttach.attachedAt`。 */
130
+ firstActivityAt?: () => number | null;
91
131
  attachedStreams?: () => number;
92
132
  lastAttachEndedAt?: () => number;
93
133
  /** [ref]:附着租约窗的读口(`/health.engineLease`)。收尾链在**装了租约腿**时才装它,读口现读租约腿的把手 —— 腿还在观察才有读数,未装配的盒子里根本没有这只口。 */
94
134
  engineLease?: () => EngineLeaseFacts | undefined;
135
+ /** [ref]:附着租约的交接门(`POST /v1/engine/handover` · `POST /v1/engine/attach` 与能力位 `engine.handover` 读它)。收尾链在**装了交接车道**时才装
136
+ * (租约腿已装配 ∧ 非多租户);`observing` = 腿还在观察。 */
137
+ engineHandover?: EngineHandoverDoor;
95
138
  }
96
139
  /** 排空盒子里的排空事实(三键齐才是;入口整组写,所以「缺一」只出现在手搭的夹具上)。 */
97
140
  export declare function drainingFactOf(s: Pick<DrainState, "draining" | "since" | "actionId" | "deadlineAt">): EngineDraining | undefined;
@@ -10,6 +10,12 @@ export const DRAIN_CAUSE_COUNTS_AS_FIRST_STOP_SIGNAL = {
10
10
  "signal:SIGHUP": true,
11
11
  "self-exit:attachment": false,
12
12
  };
13
+ export function blockingInflightOf(b) {
14
+ return b.http + b.leader + b.backgroundAgents;
15
+ }
16
+ export function inflightTotal(b) {
17
+ return blockingInflightOf(b) + b.sessionResident;
18
+ }
13
19
  export function drainingFactOf(s) {
14
20
  return s.draining && s.actionId !== undefined && s.since !== undefined && s.deadlineAt !== undefined ? { actionId: s.actionId, since: s.since, deadlineAt: s.deadlineAt } : undefined;
15
21
  }
@@ -396,7 +396,8 @@ export interface HookManagedUnrun {
396
396
  * · `llm_carrier_unavailable` / `llm_cap` —— prompt / agent 条目没有模型载体 / 超出每事件的 LLM 条目数;
397
397
  * · `powershell_unsupported` —— `shell:"powershell"` 条目(本服务不跑);
398
398
  * · `if_unevaluable` —— 条目的 `if` 条件评不出;
399
- * · `budget_exhausted` —— 托管车道的事件墙钟耗尽:撞上的那一条记一帧,同一次执行里其后的条目不再起、不逐条记(PreToolUse 逐组执行 ⇒ 至多每组一帧);
399
+ * · `budget_exhausted` —— 托管车道的预算耗尽:本服务的事件墙钟到点(不再起下一条),或托管车道那张注册的**引擎 handler 预算**(`HOOKS_TIMEOUT_MS`)用尽、被引擎叫停(`detail` 点名这一种);
400
+ * 撞上的那一条记一帧,同一次执行里其后的条目不再起、不逐条记(墙钟:每一相、PreToolUse 每一组至多一帧;引擎预算:每个事件恰一帧);任务取消叫停不记;
400
401
  * · `spawn_failed` / `timeout` —— 起不来 / 超时被收;
401
402
  * · `exit_nonzero` —— 退出码非 0 非 2;`bad_json` —— 看着是 JSON 却读不成(含 http 条目 2xx 回了非 JSON 体、Stop × prompt 的判词读不出);`decision_out_of_set` —— `permissionDecision` 不在 allow / deny / ask 里;
402
403
  * · `evidence_unavailable` —— Stop × prompt 条目因会话证据面不足(或运维关了 transcript)被滤掉没跑;
@@ -1,5 +1,6 @@
1
- import { readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
1
+ import { readFileSync, rmSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ import { atomicWriteFileSync } from "../plugins/owner-only-file-mode.js";
3
4
  import { SERVING_LEASE_TTL_DEFAULT_MS, readServingLeaseResponse } from "@sema-agent/settings-schema/fleet";
4
5
  import { centerFetch } from "../web-admin-client/center-request.js";
5
6
  import { recordFailOpen } from "../observability/fail-open.js";
@@ -66,10 +67,8 @@ export function createServingLeaseClient(o) {
66
67
  return false;
67
68
  }
68
69
  const record = { worker: o.center.worker, generation: o.generation, reason, at: epoch() };
69
- const tmp = `${stickyPath}.tmp-${process.pid}`;
70
70
  try {
71
- writeFileSync(tmp, `${JSON.stringify(record)}\n`, { mode: 0o600 });
72
- renameSync(tmp, stickyPath);
71
+ atomicWriteFileSync(stickyPath, `${JSON.stringify(record)}\n`, { durability: "best-effort" });
73
72
  return true;
74
73
  }
75
74
  catch (err) {
@@ -0,0 +1,22 @@
1
+ import type { ResumeAnchorStore } from "./plugins/store-backend.js";
2
+ /** 两族:码与句尾(出路)。键 = 族名;加一族 = 加一行(两只调用方按族名取,不手写码)。 */
3
+ declare const HISTORY_ANCHOR_FAMILIES: {
4
+ /** 分叉式回卷(会话在那条消息处分叉)。 */
5
+ readonly resumeAt: {
6
+ readonly code: "resume_at.unknown_event";
7
+ readonly wayOut: "give an explicit resumeAt";
8
+ };
9
+ /** 只恢复代码(提交体 `rewindFilesTo` 与 run 外口的 `to` 同族同码)。 */
10
+ readonly rewindFilesTo: {
11
+ readonly code: "rewind_files_to.unknown_event";
12
+ readonly wayOut: "name another prompt";
13
+ };
14
+ };
15
+ export type HistoryAnchorFamily = keyof typeof HISTORY_ANCHOR_FAMILIES;
16
+ /**
17
+ * 手柄 → entry id;未知 ⇒ 抛 404(族码 + 共用半句)。`owner` = 锚行的属主键(锚店的 null-safe 属主守卫):提交面传提交者,run 外口传会话属主
18
+ * (门已证调用方读得到这只会话;锚由这只会话的提交落下,属主键就是会话属主 —— 运维代人回退读的是同一把键)。`field` = 句首点名的请求字段。
19
+ */
20
+ export declare function resolveHistoryAnchor(family: HistoryAnchorFamily, store: Pick<ResumeAnchorStore, "resolve">, sessionId: string, handle: string, owner: string | null, field: string): Promise<string>;
21
+ export {};
22
+ //# sourceMappingURL=history-anchor.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { HttpError } from "./security.js";
2
+ const NO_ANCHOR_HINT = "no rewind anchor is recorded under that handle (a prompt that carried attachments records none when its attachment frames were interrupted or their count did not match)";
3
+ const HISTORY_ANCHOR_FAMILIES = {
4
+ resumeAt: { code: "resume_at.unknown_event", wayOut: "give an explicit resumeAt" },
5
+ rewindFilesTo: { code: "rewind_files_to.unknown_event", wayOut: "name another prompt" },
6
+ };
7
+ export async function resolveHistoryAnchor(family, store, sessionId, handle, owner, field) {
8
+ const entryId = await store.resolve(sessionId, handle, owner);
9
+ if (entryId !== undefined)
10
+ return entryId;
11
+ const { code, wayOut } = HISTORY_ANCHOR_FAMILIES[family];
12
+ throw new HttpError(404, `${field}: no such message in this session (${code}) — ${NO_ANCHOR_HINT}; ${wayOut}`, { code });
13
+ }
14
+ //# sourceMappingURL=history-anchor.js.map
@@ -19,7 +19,7 @@ export declare const RENDERED_ENTRY_TYPES: readonly ["message", "compaction", "c
19
19
  * custom —— data-only(session.js 折 messages 只认 message/custom_message 两型),模型看不见它的
20
20
  * data;把它渲出来反而是把模型没见过的东西冒充成证据,与 [ref] 是同一判据的反方向。
21
21
  */
22
- export declare const SKIPPED_ENTRY_TYPES: readonly ["thinking_level_change", "model_change", "label", "session_info", "leaf", "prompt_epoch", "announced_listing", "workspace_state", "git_announcement", "reminder_mark", "custom"];
22
+ export declare const SKIPPED_ENTRY_TYPES: readonly ["thinking_level_change", "model_change", "label", "session_info", "leaf", "prompt_epoch", "announced_listing", "workspace_state", "git_announcement", "reminder_mark", "session_checkout", "custom"];
23
23
  /** 渲染结果。**判别式**:证据不足时调用方拿不到 `text`,想用也用不了(见顶注)。 */
24
24
  export type BranchTranscript = {
25
25
  sufficient: true;
@@ -11,6 +11,7 @@ export const SKIPPED_ENTRY_TYPES = [
11
11
  "workspace_state",
12
12
  "git_announcement",
13
13
  "reminder_mark",
14
+ "session_checkout",
14
15
  "custom",
15
16
  ];
16
17
  export const BRANCH_TRANSCRIPT_MAX_CHARS = 60_000;
@@ -7,8 +7,11 @@
7
7
  * ② **handler 怎么挂**:链成员「无意见 ⇒ `next(e)`」(链 handler 返回 `undefined` 是站点违约,refuse 站上即 fail-closed 拒),
8
8
  * 观察者「恒返回 `undefined`」(观察者的判词不采纳、被引擎报告)。两条都在 {@link hangClassic} / {@link observeClassic} 里成形,
9
9
  * 调用方只写「这一站我答什么」或「这一站我看什么」,不再各自记得这两条。
10
- * ③ **信号**:引擎交给每只 handler 的 `next.signal` 是「这只 handler 的预算 ∪ 这次派发被取消」的合成(core 的派发器自合成,本仓不另合成第二份)。
11
- * 它是 handler 体的第二个入参 —— 触发之后 handler 不再起新事、在飞的子进程要叫停(`hooks/hook-runner.ts` 的命令钩子腿)。
10
+ * ③ **停表**:引擎交给每只 handler 的 `next.signal` 是「这只 handler 的预算 ∪ 这次派发结束 / 被取消」的合成(core 的派发器自合成,本仓不另合成第二份);
11
+ * 成因只读引擎的读数 `next.budget.remainingMs`(用尽 = 0),不解析信号的文案。两样一起是 handler 体的第二个入参 {@link HandlerHalt} ——
12
+ * 触发之后 handler 不再起新事、在飞的子进程要叫停(`hooks/hook-runner.ts` 的命令钩子腿);是自己的预算用尽,托管车道把撞上的条目记成未跑成。
13
+ * ④ **两种链上挂法**:内层「先答,无意见再 `next(e)`」({@link hangClassic});外层「先 `next(e)`,在答回来的答案上再答」({@link wrapClassic})——
14
+ * 外层 handler 等 `next` 的那段引擎停它的表(core `SelfBudget` 的暂停),所以外层的预算只算它自己的时间。
12
15
  *
13
16
  * 站的集合 = 引擎事件表里有站的 `classic.*` 名(一条钉从 `MOD_EVENT_TABLE` 派生对拍,不手抄第二份)。
14
17
  * 观察站(`StopFailure` / `PostCompact` / `PermissionDenied` / `SessionStart` / `SessionEnd`)只许观察者:答案形是「无」,core 的迁移配方要求挂 `{ observe: true }`。
@@ -36,16 +39,30 @@ export declare const CLASSIC_STATION_ROLE: {
36
39
  /** 本仓 handler 体对一站作的答:观察站不作答(`void`);链站 = core 的答案形,去掉本仓从不作的 `null` / `false`(PreToolUse 的两个「不表态」词)。 */
37
40
  type StationAnswer<K extends ClassicStation> = (typeof CLASSIC_STATION_ROLE)[K] extends "observe" ? void : Exclude<ClassicEventMap[K]["answer"], null | false>;
38
41
  /**
39
- * 一站的 handler 体:读 `e`,答这一站的答案;`undefined` = 无意见(链成员由 {@link hangClassic} 交给 `next(e)`)。
40
- * `signal` = 引擎交给这只 handler 的 `next.signal`(预算到 ∪ 派发被取消;见头注 ③)。
42
+ * 引擎交给一只 handler 的停表(头注 ③):`signal` 触发 = 引擎不再等它;`budgetSpent()` = 触发的是不是它**自己的预算**用尽(派发结束 / 任务取消 ⇒ `false`;
43
+ * 信号还没触发 ⇒ `false`)。
41
44
  */
42
- export type ClassicAnswer<K extends ClassicStation> = (e: ClassicEventMap[K]["e"], signal: AbortSignal) => Promise<StationAnswer<K> | undefined>;
45
+ export interface HandlerHalt {
46
+ readonly signal: AbortSignal;
47
+ budgetSpent(): boolean;
48
+ }
43
49
  /**
44
- * 按站的角色挂一只 handler:链站 ⇒ 链成员 `(await answer(e)) ?? next(e)`;观察站 ⇒ 观察者(体照跑、恒返回 `undefined`)。
50
+ * 一站的 handler 体:读 `e`,答这一站的答案;`undefined` = 无意见。`halt` 见 {@link HandlerHalt}。
51
+ * `below` = 外层挂法下(见 {@link wrapClassic})链下方答回来的那份答案(接收后冻结的数据;下方都无意见时是引擎核心的空答案)—— 内层挂法与观察站恒 `undefined`。
52
+ * 外层体答 `undefined` = 下方的答案原样作数;要换掉它就交一份新答案(把下方的成员并进去是体自己的事)。
53
+ */
54
+ export type ClassicAnswer<K extends ClassicStation> = (e: ClassicEventMap[K]["e"], halt: HandlerHalt, below: unknown) => Promise<StationAnswer<K> | undefined>;
55
+ /**
56
+ * 内层挂法:链站 ⇒ 链成员 `(await answer(e)) ?? next(e)`;观察站 ⇒ 观察者(体照跑、恒返回 `undefined`)。
45
57
  * `e` 的型由 core 的 `ClassicEventMap` 给(引擎交来的是本站的 `e`;见头注 ①)。
46
58
  */
47
59
  export declare function hangClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, answer: ClassicAnswer<K>): void;
48
- /** 挂一只观察者(任何站都可):拿分离副本、不进链、恒返回 `undefined`;`signal` 同 {@link ClassicAnswer}。 */
49
- export declare function observeClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, watch: (e: ClassicEventMap[K]["e"], signal: AbortSignal) => void | Promise<void>): void;
60
+ /**
61
+ * 外层挂法:链站 ⇒ 先 `next(e)`(下方的链成员与引擎核心先跑完,这一只的表在等的那段停着),再拿答回来的答案作答 —— 体答 `undefined` ⇒ 下方的答案原样作数;
62
+ * 下方在拒站上失败 ⇒ 派发已 fail-closed 终局,`next` 抛,体不跑。观察站 ⇒ 与 {@link hangClassic} 同(观察者不进链,没有「下方」)。
63
+ */
64
+ export declare function wrapClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, answer: ClassicAnswer<K>): void;
65
+ /** 挂一只观察者(任何站都可):拿分离副本、不进链、恒返回 `undefined`;`halt` 同 {@link ClassicAnswer}。 */
66
+ export declare function observeClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, watch: (e: ClassicEventMap[K]["e"], halt: HandlerHalt) => void | Promise<void>): void;
50
67
  export {};
51
68
  //# sourceMappingURL=classic-stations.d.ts.map
@@ -14,16 +14,42 @@ export const CLASSIC_STATION_ROLE = {
14
14
  "classic.SessionStart": "observe",
15
15
  "classic.SessionEnd": "observe",
16
16
  };
17
+ async function withHalt(next, body) {
18
+ const { signal } = next;
19
+ const readCause = () => next.budget.remainingMs === 0;
20
+ let spent = signal.aborted ? readCause() : undefined;
21
+ const latch = () => {
22
+ spent = readCause();
23
+ };
24
+ if (spent === undefined)
25
+ signal.addEventListener("abort", latch, { once: true });
26
+ try {
27
+ return await body({ signal, budgetSpent: () => spent === true });
28
+ }
29
+ finally {
30
+ signal.removeEventListener("abort", latch);
31
+ }
32
+ }
17
33
  export function hangClassic(on, station, answer) {
18
34
  if (CLASSIC_STATION_ROLE[station] === "observe") {
19
- observeClassic(on, station, async (e, signal) => void (await answer(e, signal)));
35
+ observeClassic(on, station, async (e, halt) => void (await answer(e, halt, undefined)));
36
+ return;
37
+ }
38
+ on(station, async (_$, e, next) => (await withHalt(next, (halt) => answer(e, halt, undefined))) ?? next(e));
39
+ }
40
+ export function wrapClassic(on, station, answer) {
41
+ if (CLASSIC_STATION_ROLE[station] === "observe") {
42
+ hangClassic(on, station, answer);
20
43
  return;
21
44
  }
22
- on(station, async (_$, e, next) => (await answer(e, next.signal)) ?? next(e));
45
+ on(station, async (_$, e, next) => {
46
+ const below = await next(e);
47
+ return (await withHalt(next, (halt) => answer(e, halt, below))) ?? below;
48
+ });
23
49
  }
24
50
  export function observeClassic(on, station, watch) {
25
51
  on(station, async (_$, e, next) => {
26
- await watch(e, next.signal);
52
+ await withHalt(next, async (halt) => watch(e, halt));
27
53
  return undefined;
28
54
  }, { observe: true });
29
55
  }
@@ -6,13 +6,10 @@ export interface HookPluginContext {
6
6
  readonly dataDir?: string;
7
7
  readonly options?: Readonly<Record<string, string>>;
8
8
  }
9
- /** 本仓会跑的 command 条目:契约形 + 本仓读的两只 wire 键。 */
9
+ /** 本仓会跑的 command 条目:契约形(含 `args` / `onFailure`)+ 本仓先于契约读的 wire 键 `plugin`(契约包不承运它;收口票 [ref])。 */
10
10
  export type RunnableCommandHookEntry = CommandHookEntry & {
11
- readonly args?: readonly string[];
12
11
  readonly plugin?: HookPluginContext;
13
12
  };
14
- /** 受理面:`args` 合形(串数组、元素无 NUL)⇒ 拷贝;否则 `undefined`。 */
15
- export declare function readHookArgs(raw: unknown): string[] | undefined;
16
13
  /** 受理面:`plugin` 合形 ⇒ 拷贝;否则 `undefined`。路径与 `skills[i].baseDir` 同一只判(契约包 `isAbsoluteHostPath`:绝对、无 `..` 段、无 NUL、有长度上限);不做存在性检查(那是执行面的事)。 */
17
14
  export declare function readHookPlugin(raw: unknown): HookPluginContext | undefined;
18
15
  /** 插件上下文的总字符数(服务侧上限 `plugin` 帽的量):名 + 根 + 数据目录 + 各选项的键与值。 */