@sema-agent/server 7.146.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 (398) hide show
  1. package/MIGRATION.md +384 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +170 -66
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +2 -2
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
  8. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  9. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  10. package/deploy/sema-up/chart/values.yaml +1 -1
  11. package/deploy/sema-up/cluster-up.sh +2 -1
  12. package/deploy/sema-up/lib/flagshape.sh +4 -0
  13. package/deploy/sema-up/lib/lanes.json +2 -5
  14. package/deploy/sema-up/sema-up.sh +12 -9
  15. package/deploy/sema-up/stack/compose.yaml +5 -4
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
  17. package/dist/approval-card.d.ts +4 -4
  18. package/dist/approval.d.ts +3 -3
  19. package/dist/audit.js +2 -2
  20. package/dist/bench/s1/live-deps.js +3 -1
  21. package/dist/boot/crash-last.js +2 -1
  22. package/dist/boot/device-lane.js +5 -5
  23. package/dist/boot/engine-lease.d.ts +12 -11
  24. package/dist/boot/execution-env.d.ts +2 -1
  25. package/dist/boot/execution-env.js +45 -33
  26. package/dist/boot/execution-lane.d.ts +37 -9
  27. package/dist/boot/execution-lane.js +74 -20
  28. package/dist/boot/exit-boundary.d.ts +1 -1
  29. package/dist/boot/exit-last.js +2 -1
  30. package/dist/boot/governance-seams.d.ts +2 -2
  31. package/dist/boot/leader.js +1 -1
  32. package/dist/boot/memory-boundary.d.ts +11 -11
  33. package/dist/boot/memory-boundary.js +3 -3
  34. package/dist/boot/memory-consolidation.d.ts +13 -24
  35. package/dist/boot/memory-consolidation.js +0 -13
  36. package/dist/boot/org-memory.js +3 -2
  37. package/dist/boot/parked-revive-gate.d.ts +1 -1
  38. package/dist/boot/parked-revive-gate.js +1 -1
  39. package/dist/boot/reapers.js +1 -1
  40. package/dist/boot/resolve-spec.js +91 -111
  41. package/dist/boot/retention-lane.d.ts +4 -42
  42. package/dist/boot/session-faces.d.ts +1 -0
  43. package/dist/boot/session-faces.js +8 -2
  44. package/dist/boot/stage-01-config.d.ts +1 -1
  45. package/dist/boot/stage-01-config.js +6 -2
  46. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  47. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  48. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  49. package/dist/boot/stage-04-stores.d.ts +1 -1
  50. package/dist/boot/stage-05-execution-env.d.ts +2 -2
  51. package/dist/boot/stage-05-execution-env.js +3 -3
  52. package/dist/boot/stage-06-runners.d.ts +3 -3
  53. package/dist/boot/stage-06-runners.js +1 -3
  54. package/dist/boot/stage-07-capability-layer.d.ts +3 -3
  55. package/dist/boot/stage-07-capability-layer.js +4 -9
  56. package/dist/boot/stage-08-reapers.d.ts +3 -3
  57. package/dist/boot/stage-09-leader.d.ts +4 -3
  58. package/dist/boot/stage-10-http-server.d.ts +4 -3
  59. package/dist/boot/stage-10-http-server.js +2 -1
  60. package/dist/boot/stores.d.ts +9 -0
  61. package/dist/boot/stores.js +18 -7
  62. package/dist/boot/web-admin.js +3 -3
  63. package/dist/capabilities/center-plugins.d.ts +2 -0
  64. package/dist/capabilities/center-plugins.js +6 -2
  65. package/dist/capabilities/composite-members.d.ts +1 -0
  66. package/dist/capabilities/composite-members.js +1 -0
  67. package/dist/capabilities/execution-lane.d.ts +7 -7
  68. package/dist/capabilities/execution-lane.js +2 -2
  69. package/dist/capabilities/hands-lane.d.ts +1 -1
  70. package/dist/capabilities/scenarios.d.ts +32 -18
  71. package/dist/capabilities/scenarios.js +13 -9
  72. package/dist/capabilities/settings-contract.d.ts +29 -0
  73. package/dist/capabilities/settings-contract.js +14 -0
  74. package/dist/capabilities/skills.d.ts +5 -5
  75. package/dist/capability-facts.d.ts +38 -0
  76. package/dist/capability-facts.js +34 -1
  77. package/dist/center-credential-renewer.js +3 -2
  78. package/dist/config-catalog.js +6 -5
  79. package/dist/config-invariants.d.ts +18 -3
  80. package/dist/config-invariants.js +36 -19
  81. package/dist/config-lkg.d.ts +1 -1
  82. package/dist/config-lkg.js +5 -6
  83. package/dist/config-provider.js +2 -0
  84. package/dist/config-types.d.ts +190 -186
  85. package/dist/config.d.ts +68 -5
  86. package/dist/config.js +80 -54
  87. package/dist/degenerate-instrument.js +1 -1
  88. package/dist/deploy-facts.js +3 -2
  89. package/dist/deployment-shape.d.ts +21 -12
  90. package/dist/deployment-shape.js +24 -6
  91. package/dist/env-facts.d.ts +7 -5
  92. package/dist/env-facts.js +10 -6
  93. package/dist/execution-config-root.d.ts +5 -5
  94. package/dist/execution-config-root.js +5 -5
  95. package/dist/execution-env-purpose.d.ts +14 -0
  96. package/dist/execution-env-purpose.js +29 -0
  97. package/dist/execution-lane-caps.d.ts +49 -86
  98. package/dist/execution-lane-caps.js +52 -62
  99. package/dist/execution-placement.d.ts +18 -2
  100. package/dist/execution-placement.js +19 -0
  101. package/dist/file-history-disclosure.d.ts +2 -2
  102. package/dist/fleet/drain-entry.d.ts +17 -10
  103. package/dist/fleet/drain-entry.js +1 -1
  104. package/dist/fleet/serving-lease.js +3 -4
  105. package/dist/history-anchor.d.ts +22 -0
  106. package/dist/history-anchor.js +14 -0
  107. package/dist/hooks/command-spawn.d.ts +1 -4
  108. package/dist/hooks/command-spawn.js +0 -11
  109. package/dist/hooks/hook-runner.d.ts +52 -8
  110. package/dist/hooks/hook-runner.js +160 -36
  111. package/dist/http/approval-sweeps.d.ts +2 -5
  112. package/dist/http/approval-sweeps.js +3 -2
  113. package/dist/http/checkpoint-ctx.d.ts +17 -0
  114. package/dist/http/checkpoint-ctx.js +6 -0
  115. package/dist/http/claim-latency.d.ts +10 -0
  116. package/dist/http/claim-latency.js +12 -0
  117. package/dist/http/dispatch.js +1 -1
  118. package/dist/http/durable-run-leg.js +2 -1
  119. package/dist/http/execution-context.d.ts +3 -1
  120. package/dist/http/execution-context.js +4 -0
  121. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  122. package/dist/http/memory-compliance-failure-reply.js +3 -0
  123. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  124. package/dist/http/memory-store-refusal-reply.js +3 -0
  125. package/dist/http/owner-access.d.ts +11 -0
  126. package/dist/http/owner-access.js +7 -4
  127. package/dist/http/principal-gate.d.ts +3 -14
  128. package/dist/http/principal-gate.js +0 -13
  129. package/dist/http/request-guards.d.ts +1 -1
  130. package/dist/http/resume-legs.d.ts +7 -10
  131. package/dist/http/resume-legs.js +79 -50
  132. package/dist/http/rewind-files-reply.d.ts +34 -0
  133. package/dist/http/rewind-files-reply.js +36 -0
  134. package/dist/http/route-ctx.d.ts +32 -16
  135. package/dist/http/route-table.js +2 -0
  136. package/dist/http/routes/approvals-assistant.js +5 -25
  137. package/dist/http/routes/capabilities.js +8 -2
  138. package/dist/http/routes/devices.js +1 -1
  139. package/dist/http/routes/memory-origin.d.ts +1 -1
  140. package/dist/http/routes/notify-wake.js +2 -1
  141. package/dist/http/routes/projects.d.ts +70 -0
  142. package/dist/http/routes/projects.js +86 -0
  143. package/dist/http/routes/rules.js +30 -2
  144. package/dist/http/routes/runs.js +8 -8
  145. package/dist/http/routes/session-sync.js +27 -10
  146. package/dist/http/routes/sessions.d.ts +7 -1
  147. package/dist/http/routes/sessions.js +104 -2
  148. package/dist/http/routes/tasks.js +9 -3
  149. package/dist/http/server.d.ts +24 -10
  150. package/dist/http/server.js +17 -6
  151. package/dist/http/stored-body-replay.d.ts +5 -3
  152. package/dist/http/stored-body-replay.js +10 -1
  153. package/dist/http/wire-types.d.ts +19 -10
  154. package/dist/index.d.ts +2 -2
  155. package/dist/index.js +1 -1
  156. package/dist/instruction-source-notice.d.ts +1 -1
  157. package/dist/memory-embedder-reembed.d.ts +38 -0
  158. package/dist/memory-embedder-reembed.js +20 -0
  159. package/dist/memory-incident-sink.d.ts +0 -28
  160. package/dist/memory-incident-sink.js +5 -0
  161. package/dist/memory-scope.d.ts +2 -2
  162. package/dist/memory-scope.js +1 -1
  163. package/dist/memory-store-refusal.d.ts +17 -4
  164. package/dist/memory-store-refusal.js +1 -1
  165. package/dist/memory-sync-client.d.ts +2 -0
  166. package/dist/memory-sync-client.js +13 -11
  167. package/dist/memory-sync.js +1 -1
  168. package/dist/model-compat.d.ts +35 -21
  169. package/dist/model-compat.js +49 -21
  170. package/dist/model-entry-refusal.d.ts +11 -1
  171. package/dist/model-entry-refusal.js +7 -0
  172. package/dist/namespaced-rule-name.d.ts +18 -1
  173. package/dist/namespaced-rule-name.js +12 -0
  174. package/dist/observability/fail-open.d.ts +17 -9
  175. package/dist/observability/fail-open.js +17 -9
  176. package/dist/observability/metrics.d.ts +2 -0
  177. package/dist/observability/metrics.js +2 -0
  178. package/dist/observability/secret-env-scrub.d.ts +30 -4
  179. package/dist/observability/secret-env-scrub.js +15 -3
  180. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  181. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  182. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  183. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  184. package/dist/org-memory-admission.d.ts +5 -2
  185. package/dist/org-memory-admission.js +25 -10
  186. package/dist/parked-decide.d.ts +33 -26
  187. package/dist/parked-decide.js +36 -44
  188. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  189. package/dist/plugins/approval-ask-store-file.js +37 -4
  190. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  191. package/dist/plugins/approval-ask-store-memory.js +11 -2
  192. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  193. package/dist/plugins/approval-ask-store-sql.js +3 -1
  194. package/dist/plugins/blob-backend.d.ts +38 -195
  195. package/dist/plugins/blob-backend.js +33 -229
  196. package/dist/plugins/caching-session-store.d.ts +9 -4
  197. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  198. package/dist/plugins/checkpoint-index-columns.js +3 -2
  199. package/dist/plugins/checkpoint-store-face.d.ts +1 -1
  200. package/dist/plugins/device-store-sql.d.ts +2 -2
  201. package/dist/plugins/device-store-sql.js +5 -10
  202. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  203. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  204. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  205. package/dist/plugins/execution-placement-sql.js +94 -54
  206. package/dist/plugins/file-run-store.d.ts +26 -12
  207. package/dist/plugins/file-run-store.js +63 -63
  208. package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
  209. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  210. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  211. package/dist/plugins/inbox-payload-column.js +13 -0
  212. package/dist/plugins/local-checkpoint-store.d.ts +5 -0
  213. package/dist/plugins/local-checkpoint-store.js +11 -7
  214. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  215. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  216. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  217. package/dist/plugins/local-engine-high-water.js +59 -0
  218. package/dist/plugins/local-session-store.d.ts +91 -25
  219. package/dist/plugins/local-session-store.js +124 -45
  220. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  221. package/dist/plugins/local-task-attachment-store.js +10 -11
  222. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  223. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  224. package/dist/plugins/memory-embedder.d.ts +1 -1
  225. package/dist/plugins/memory-embedder.js +2 -2
  226. package/dist/plugins/memory-engine-pg.d.ts +4 -3
  227. package/dist/plugins/memory-engine-pg.js +4 -4
  228. package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
  229. package/dist/plugins/memory-engine-sql-apply.js +1 -1
  230. package/dist/plugins/memory-engine-tidb.d.ts +8 -5
  231. package/dist/plugins/memory-engine-tidb.js +7 -8
  232. package/dist/plugins/one-time-migrations.d.ts +145 -35
  233. package/dist/plugins/one-time-migrations.js +272 -120
  234. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  235. package/dist/plugins/owner-only-file-mode.js +141 -0
  236. package/dist/plugins/permission-rule-store-file.d.ts +8 -8
  237. package/dist/plugins/permission-rule-store-file.js +14 -2
  238. package/dist/plugins/pg-pool.d.ts +2 -1
  239. package/dist/plugins/pg-pool.js +11 -4
  240. package/dist/plugins/release-version.d.ts +20 -0
  241. package/dist/plugins/release-version.js +28 -0
  242. package/dist/plugins/remote-env-adb.d.ts +20 -4
  243. package/dist/plugins/remote-env-adb.js +39 -11
  244. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  245. package/dist/plugins/remote-env-e2b.js +6 -4
  246. package/dist/plugins/remote-env-host.d.ts +9 -1
  247. package/dist/plugins/remote-env-host.js +6 -5
  248. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  249. package/dist/plugins/remote-env-k8s.js +15 -4
  250. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  251. package/dist/plugins/remote-env-local-docker.js +3 -3
  252. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  253. package/dist/plugins/remote-env-ssh.js +26 -24
  254. package/dist/plugins/remote-shell.d.ts +59 -30
  255. package/dist/plugins/remote-shell.js +175 -62
  256. package/dist/plugins/retention-declaration.d.ts +37 -0
  257. package/dist/plugins/retention-declaration.js +9 -0
  258. package/dist/plugins/retention-deployment.d.ts +126 -0
  259. package/dist/plugins/retention-deployment.js +88 -0
  260. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  261. package/dist/plugins/retention-lane-store-sql.js +103 -1
  262. package/dist/plugins/retention-sql.d.ts +29 -0
  263. package/dist/plugins/retention-sql.js +8 -0
  264. package/dist/plugins/schema-consistency.d.ts +0 -6
  265. package/dist/plugins/schema-consistency.js +1 -2
  266. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  267. package/dist/plugins/schema-ensure-legs.js +11 -1
  268. package/dist/plugins/session-ext-table.d.ts +74 -0
  269. package/dist/plugins/session-ext-table.js +121 -0
  270. package/dist/plugins/session-fork.d.ts +1 -1
  271. package/dist/plugins/session-row-sql.d.ts +8 -7
  272. package/dist/plugins/session-row-sql.js +15 -7
  273. package/dist/plugins/session-store-sql.d.ts +131 -0
  274. package/dist/plugins/session-store-sql.js +298 -0
  275. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  276. package/dist/plugins/session-workspace-cell.js +2 -2
  277. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  278. package/dist/plugins/shared-memory-store-sql.js +13 -13
  279. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  280. package/dist/plugins/sql-driver.d.ts +23 -7
  281. package/dist/plugins/sql-driver.js +41 -8
  282. package/dist/plugins/sql-errors.d.ts +5 -2
  283. package/dist/plugins/sql-errors.js +4 -0
  284. package/dist/plugins/store-backend.d.ts +35 -8
  285. package/dist/plugins/store-backend.js +184 -62
  286. package/dist/plugins/store-contracts.d.ts +9 -2
  287. package/dist/plugins/store-contracts.js +1 -0
  288. package/dist/plugins/task-attachment-store.d.ts +6 -8
  289. package/dist/plugins/task-attachment-store.js +15 -10
  290. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  291. package/dist/plugins/text-column-capacity.d.ts +21 -0
  292. package/dist/plugins/text-column-capacity.js +5 -0
  293. package/dist/plugins/tidb-pool.d.ts +3 -2
  294. package/dist/plugins/tidb-pool.js +19 -31
  295. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  296. package/dist/read-face-posture.d.ts +6 -6
  297. package/dist/read-face-posture.js +2 -2
  298. package/dist/request-value-closure.d.ts +5 -5
  299. package/dist/request-value-closure.js +1 -1
  300. package/dist/rules-consent.d.ts +41 -13
  301. package/dist/rules-consent.js +101 -53
  302. package/dist/run-local.js +17 -13
  303. package/dist/runs.d.ts +48 -30
  304. package/dist/runs.js +26 -16
  305. package/dist/runtime-caps-resolver.d.ts +15 -8
  306. package/dist/runtime-caps-resolver.js +14 -10
  307. package/dist/sealed-key-layout.d.ts +2 -3
  308. package/dist/sealed-key-layout.js +0 -1
  309. package/dist/sealed-key.js +7 -5
  310. package/dist/security.d.ts +5 -3
  311. package/dist/sema-config-dir.js +2 -2
  312. package/dist/server-secret-env.d.ts +2 -0
  313. package/dist/service-version.d.ts +2 -1
  314. package/dist/service-version.js +2 -2
  315. package/dist/session-error-wire.d.ts +1 -1
  316. package/dist/session-incarnation.d.ts +8 -5
  317. package/dist/session-resident-background.d.ts +85 -32
  318. package/dist/session-resident-background.js +75 -7
  319. package/dist/session-row.d.ts +1 -1
  320. package/dist/session-sync-kernel.d.ts +1 -1
  321. package/dist/session-workspace.d.ts +11 -2
  322. package/dist/session-workspace.js +5 -0
  323. package/dist/sighup-idle.d.ts +1 -1
  324. package/dist/store-posture.d.ts +2 -1
  325. package/dist/stored-request-hooks-m20.d.ts +3 -2
  326. package/dist/stored-request-hooks-m20.js +19 -14
  327. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  328. package/dist/stores-sql/blob-index-sql.js +154 -0
  329. package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
  330. package/dist/stores-sql/checkpoint-store-sql.js +11 -27
  331. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  332. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  333. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
  334. package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
  335. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  336. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  337. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  338. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  339. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  340. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  341. package/dist/stores-sql/session-write-hooks.js +2 -0
  342. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  343. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  344. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
  345. package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
  346. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  347. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  348. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  349. package/dist/stores-sql/windowed-session-storage.js +61 -0
  350. package/dist/task-a2a.d.ts +7 -1
  351. package/dist/task-a2a.js +15 -14
  352. package/dist/task-cwd.d.ts +11 -3
  353. package/dist/task-cwd.js +17 -1
  354. package/dist/task-mcp.d.ts +10 -2
  355. package/dist/task-mcp.js +13 -16
  356. package/dist/task-settings.d.ts +9 -4
  357. package/dist/task-settings.js +17 -6
  358. package/dist/tool-approval.d.ts +21 -8
  359. package/dist/tool-approval.js +10 -6
  360. package/dist/trace/core-keyset-guard.d.ts +9 -3
  361. package/dist/trace/engine-notice-wire.d.ts +1 -1
  362. package/dist/trace/engine-notice-wire.js +2 -0
  363. package/dist/trace/exit-seat.d.ts +23 -1
  364. package/dist/trace/exit-seat.js +3 -0
  365. package/dist/trace/project.d.ts +33 -16
  366. package/dist/trace/project.js +12 -9
  367. package/dist/trace/redact.d.ts +1 -1
  368. package/dist/trace/redact.js +61 -73
  369. package/dist/trace/self-minted-wire.d.ts +263 -10
  370. package/dist/trace/self-minted-wire.js +90 -2
  371. package/dist/trace/sema-provenance.d.ts +45 -41
  372. package/dist/trace/sema-provenance.js +81 -10
  373. package/dist/trace/task-notification-facets.d.ts +70 -2
  374. package/dist/trace/task-notification-facets.js +71 -1
  375. package/dist/trace/wire-projection-faces.d.ts +38 -2
  376. package/dist/trace/wire-projection-faces.js +26 -1
  377. package/dist/unread-request-members.d.ts +66 -0
  378. package/dist/unread-request-members.js +41 -0
  379. package/dist/user-input-ledger.d.ts +2 -2
  380. package/dist/web-admin-client/apply-effective.js +22 -26
  381. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  382. package/dist/web-admin-client/candidate-gate.js +53 -5
  383. package/dist/web-admin-client/center-request.d.ts +4 -1
  384. package/dist/web-admin-client/center-request.js +2 -1
  385. package/dist/web-admin-client/effective-keys.js +0 -1
  386. package/dist/web-admin-client/facade.d.ts +1 -1
  387. package/dist/web-admin-client/http-client.d.ts +1 -0
  388. package/dist/web-admin-client/http-client.js +17 -9
  389. package/dist/web-admin-client/restart-signal.js +5 -2
  390. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  391. package/dist/web-admin-client/skills-mcp.js +26 -21
  392. package/dist/web-admin-client/types.d.ts +34 -49
  393. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  394. package/package.json +13 -12
  395. package/scripts/drain-check-local.mjs +2 -28
  396. package/scripts/drain-check.mysql.sql +2 -18
  397. package/scripts/drain-check.pg.sql +2 -18
  398. package/wire-changes/server@7.147.0.json +813 -0
@@ -20,7 +20,7 @@ import { ccAgentHookSystemFor } from "./cc-agent-hook-prompt.js";
20
20
  import { renderBranchTranscript } from "./branch-transcript.js";
21
21
  import { buildRequestUrlCredentialRefusal, urlCredentialHeaderExit } from "../url-credential-refusal.js";
22
22
  import { HOOK_PHASES, HOOK_SOURCE_VOCABULARY_SENTENCE, hookLaneOf, hookPhaseOf, readHookGroupSource } from "./hook-source.js";
23
- import { commandLineChars, composeHookEnvLayer, hookPluginChars, planCommandSpawn, readHookArgs, readHookPlugin } from "./command-spawn.js";
23
+ import { commandLineChars, composeHookEnvLayer, hookPluginChars, planCommandSpawn, readHookPlugin } from "./command-spawn.js";
24
24
  export const MAX_HOOK_ENTRIES_PER_EVENT = 32;
25
25
  export const MAX_HOOK_COMMAND_CHARS = 8_192;
26
26
  export const MAX_HOOK_TIMEOUT_SECONDS = 600;
@@ -235,7 +235,6 @@ const HOOKS_WIRE_KEY_SHAPE = {
235
235
  source: `source must be one of ${HOOK_SOURCE_VOCABULARY_SENTENCE}`,
236
236
  plugin: "plugin must be { name, root, dataDir?, options? } — name a non-empty string, root and dataDir absolute paths with no \"..\" segment and no NUL byte, " +
237
237
  "options an object of string values whose keys are identifiers ([A-Za-z_][A-Za-z0-9_]*); nothing else",
238
- args: "args must be an array of strings without NUL bytes (exec form: command is the executable, args its arguments)",
239
238
  };
240
239
  function hooksCapIssue(limit, event, path, count) {
241
240
  const c = HOOKS_CAPS[limit];
@@ -432,16 +431,12 @@ export function parseHooksConfig(raw) {
432
431
  return hooksRefused({ reason: "unsupported_entry_type", path: [...at, "type"], type: contractEntry.type });
433
432
  let entry = contractEntry;
434
433
  if (entry.type === "command") {
435
- const rawEntry = rawMember(rawMember(rawGroup, "hooks"), entryIndex);
436
- const rawArgs = rawMember(rawEntry, "args");
437
- const rawPlugin = rawMember(rawEntry, "plugin");
438
- const args = rawArgs === undefined ? undefined : readHookArgs(rawArgs);
439
- if (rawArgs !== undefined && args === undefined)
440
- return hooksRefused({ reason: "wire_key_invalid", path: [...at, "args"], key: "args" });
434
+ const rawPlugin = rawMember(rawMember(rawMember(rawGroup, "hooks"), entryIndex), "plugin");
441
435
  const plugin = rawPlugin === undefined ? undefined : readHookPlugin(rawPlugin);
442
436
  if (rawPlugin !== undefined && plugin === undefined)
443
437
  return hooksRefused({ reason: "wire_key_invalid", path: [...at, "plugin"], key: "plugin" });
444
- entry = { ...entry, ...(args !== undefined ? { args } : {}), ...(plugin !== undefined ? { plugin } : {}) };
438
+ if (plugin !== undefined)
439
+ entry = { ...entry, plugin };
445
440
  const line = commandLineChars(entry);
446
441
  if (line > MAX_HOOK_COMMAND_CHARS)
447
442
  return hooksRefused(hooksCapIssue("command", event, [...at, "command"], line));
@@ -600,7 +595,7 @@ function noteMatcherOverBudget(ctx, args) {
600
595
  detail: `${what} \`${expression}\` did not finish within ${budgetMs} ms on \`${value}\`; treated as selected (${count} ${count === 1 ? "entry" : "entries"})`,
601
596
  });
602
597
  }
603
- function matcherGroupSelected(ctx, event, group, value, toolName) {
598
+ function matcherGroupSelected(ctx, event, group, value, toolName, entries) {
604
599
  const answer = hookMatcherMatches(group.matcher, value);
605
600
  switch (answer) {
606
601
  case true:
@@ -611,7 +606,7 @@ function matcherGroupSelected(ctx, event, group, value, toolName) {
611
606
  ctx.logger.warn("hook_matcher_invalid", { event, matcher: echoCallerText(group.matcher ?? "", { maxChars: MATCHER_ECHO_CHARS }) });
612
607
  return "invalid";
613
608
  case "over_budget":
614
- noteMatcherOverBudget(ctx, { event, scope: "matcher", expression: group.matcher ?? "", value, entries: group.hooks, ...(toolName !== undefined ? { toolName } : {}) });
609
+ noteMatcherOverBudget(ctx, { event, scope: "matcher", expression: group.matcher ?? "", value, entries, ...(toolName !== undefined ? { toolName } : {}) });
615
610
  return "over_budget";
616
611
  default: {
617
612
  const unreachable = answer;
@@ -654,6 +649,41 @@ export const PERMISSIVE_VERDICT_EVENTS = {
654
649
  PreModelSwitch: false,
655
650
  PostModelSwitch: false,
656
651
  };
652
+ export const ON_FAILURE_BLOCK_EVENTS = {
653
+ PreToolUse: true,
654
+ PostToolUse: true,
655
+ PostToolUseFailure: true,
656
+ PostToolBatch: true,
657
+ Notification: true,
658
+ UserPromptSubmit: true,
659
+ UserPromptExpansion: true,
660
+ SessionStart: true,
661
+ SessionEnd: true,
662
+ Stop: false,
663
+ StopFailure: false,
664
+ SubagentStart: true,
665
+ SubagentStop: false,
666
+ PreCompact: true,
667
+ PostCompact: false,
668
+ PermissionRequest: true,
669
+ PermissionDenied: true,
670
+ Setup: true,
671
+ TeammateIdle: false,
672
+ TaskCreated: true,
673
+ TaskCompleted: false,
674
+ Elicitation: true,
675
+ ElicitationResult: true,
676
+ ConfigChange: true,
677
+ WorktreeCreate: true,
678
+ WorktreeRemove: true,
679
+ InstructionsLoaded: true,
680
+ CwdChanged: true,
681
+ FileChanged: true,
682
+ MessageDisplay: true,
683
+ DirectoryAdded: true,
684
+ PreModelSwitch: true,
685
+ PostModelSwitch: true,
686
+ };
657
687
  const DISTRUST_DETAIL = {
658
688
  input_truncated: `the hook did not receive the whole payload (tool_input over ${MAX_TOOL_INPUT_CHARS} characters was replaced by a truncation marker, or a prompt / agent entry's payload text was clipped at that size); its allow / updatedInput are not honored`,
659
689
  matcher_over_budget: "the matcher (or the if condition's tool-name part) did not finish within its budget; the entry ran as selected, so its allow / updatedInput are not honored",
@@ -800,6 +830,9 @@ function withBelowContext(parts, below) {
800
830
  const tail = belowString(below, "additionalContext");
801
831
  return tail === undefined ? [...parts] : [...parts, tail];
802
832
  }
833
+ function alsoAsks(below, own) {
834
+ return below === undefined || below === own ? own : `${below} (a managed PreToolUse hook also asks: ${own})`;
835
+ }
803
836
  function readBelowPreToolUse(below) {
804
837
  const action = belowString(below, "action");
805
838
  const message = belowString(below, "message") ?? "a PreToolUse hook requires approval";
@@ -1190,18 +1223,39 @@ function boundedToolInputPayload(payload) {
1190
1223
  return bounded === p.tool_input ? payload : { ...p, tool_input: bounded };
1191
1224
  }
1192
1225
  function readHookStdout(ran, event, ctx, payload, ledger) {
1193
- const { run, entry } = ran;
1194
- const out = parseHookStdout(run.stdout);
1226
+ const out = parseHookStdout(ran.run.stdout);
1195
1227
  if (out !== undefined)
1196
1228
  return out;
1197
- const t = run.stdout.trim();
1198
- if (t.startsWith("{") || t.startsWith("[")) {
1199
- ctx.logger.warn("hook_bad_json_output", { event, type: entry.type, preview: seatText("operator-log-text", t) });
1200
- noteHookFailure(ctx, { event, entry, reason: "bad_json", exitCode: run.code, stderr: run.stderr, toolName: toolNameOf(payload) });
1201
- ledger.unrun(ran.source, entry, "bad_json");
1202
- }
1229
+ if (stdoutVerdictUnreadable(ran.run.stdout))
1230
+ noteBadJson(ctx, ledger, event, ran, toolNameOf(payload));
1203
1231
  return undefined;
1204
1232
  }
1233
+ function stdoutVerdictUnreadable(stdout) {
1234
+ if (parseHookStdout(stdout) !== undefined)
1235
+ return false;
1236
+ const t = stdout.trim();
1237
+ return t.startsWith("{") || t.startsWith("[");
1238
+ }
1239
+ function noteBadJson(ctx, ledger, event, ran, toolName) {
1240
+ const { run, entry } = ran;
1241
+ ctx.logger.warn("hook_bad_json_output", { event, type: entry.type, preview: seatText("operator-log-text", run.stdout.trim()) });
1242
+ noteHookFailure(ctx, { event, entry, reason: "bad_json", exitCode: run.code, stderr: run.stderr, toolName });
1243
+ ledger.unrun(ran.source, entry, "bad_json");
1244
+ }
1245
+ const PERMISSION_DECISION_WORDS = new Set(["allow", "deny", "ask"]);
1246
+ function preToolUseDecisionOf(out) {
1247
+ const hso = out?.hookSpecificOutput;
1248
+ return hso !== null && typeof hso === "object" && hso.hookEventName === "PreToolUse" ? hso.permissionDecision : undefined;
1249
+ }
1250
+ function noteDecisionOutOfSet(ctx, ledger, ran, decision, toolName, effect) {
1251
+ ctx.logger.warn("hook_permission_decision_unknown", {
1252
+ event: "PreToolUse",
1253
+ decision: seatText("operator-log-text", typeof decision === "string" ? decision : typeof decision),
1254
+ tool: toolName,
1255
+ effect,
1256
+ });
1257
+ ledger.unrun(ran.source, ran.entry, "decision_out_of_set");
1258
+ }
1205
1259
  function parseHookStdout(stdout) {
1206
1260
  const t = stdout.trim();
1207
1261
  if (!t.startsWith("{"))
@@ -1234,12 +1288,68 @@ function runRunnableEntry(entry, payload, ctx, event, llmExtra, halt) {
1234
1288
  function isSyncEntry(entry) {
1235
1289
  return !(entry.type === "command" && (entry.async === true || entry.asyncRewake === true));
1236
1290
  }
1291
+ function blocksOnFailure(entry, event) {
1292
+ if (!ON_FAILURE_BLOCK_EVENTS[event] || !isSyncEntry(entry))
1293
+ return false;
1294
+ if (entry.type !== "command" && entry.type !== "http")
1295
+ return false;
1296
+ const word = entry.onFailure;
1297
+ switch (word) {
1298
+ case "block":
1299
+ return true;
1300
+ case "continue":
1301
+ case undefined:
1302
+ return false;
1303
+ default: {
1304
+ const unreachable = word;
1305
+ void unreachable;
1306
+ return true;
1307
+ }
1308
+ }
1309
+ }
1310
+ function blockingFailureRun(event, cause) {
1311
+ return { code: 2, stdout: "", stderr: `${event} hook did not reach a verdict (${cause}); blocking because onFailure is "block"`, timedOut: false };
1312
+ }
1313
+ function ranVerdictFlaw(event, run) {
1314
+ if (run.code === 2)
1315
+ return undefined;
1316
+ if (run.code !== 0)
1317
+ return { reason: "exit_nonzero" };
1318
+ if (stdoutVerdictUnreadable(run.stdout))
1319
+ return { reason: "bad_json" };
1320
+ if (event !== "PreToolUse")
1321
+ return undefined;
1322
+ const out = parseHookStdout(run.stdout);
1323
+ if (out?.continue === false || out?.decision === "block")
1324
+ return undefined;
1325
+ const decision = preToolUseDecisionOf(out);
1326
+ return decision !== undefined && !PERMISSION_DECISION_WORDS.has(decision) ? { reason: "decision_out_of_set", decision } : undefined;
1327
+ }
1328
+ function noteRanVerdictFlaw(ctx, ledger, event, ran, flaw, toolName) {
1329
+ switch (flaw.reason) {
1330
+ case "exit_nonzero":
1331
+ noteExitNonzero(ctx, ledger, event, ran, toolName);
1332
+ return;
1333
+ case "bad_json":
1334
+ noteBadJson(ctx, ledger, event, ran, toolName);
1335
+ return;
1336
+ case "decision_out_of_set":
1337
+ noteDecisionOutOfSet(ctx, ledger, ran, flaw.decision, toolName, 'hook ruling not honored (closed word set is allow|deny|ask); the entry\'s onFailure is "block", so this call is denied');
1338
+ return;
1339
+ default: {
1340
+ const unreachable = flaw;
1341
+ void unreachable;
1342
+ }
1343
+ }
1344
+ }
1237
1345
  async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceFired, halt, deadlineAt, ledger, llmExtra) {
1238
1346
  const results = [];
1239
1347
  let llmEntries = 0;
1240
1348
  const toolName = toolNameOf(payload);
1241
1349
  const inputTruncated = boundedToolInputPayload(payload) !== payload;
1242
1350
  const truncatedFor = (entry) => (entry.type === "prompt" || entry.type === "agent" ? llmHookArguments(payload).truncated : inputTruncated);
1351
+ const blockedBy = (entry, source, cause) => ({ entry, run: blockingFailureRun(event, cause), source });
1352
+ let laneSpent = false;
1243
1353
  const settle = async (entry, onceKey) => {
1244
1354
  if (halt.signal.aborted)
1245
1355
  return { kind: "halted" };
@@ -1288,8 +1398,9 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1288
1398
  void fireAsyncCommandHook(entry, payload, ctx, event, halt.signal);
1289
1399
  return { kind: "passed" };
1290
1400
  }
1291
- if (Date.now() > deadlineAt) {
1292
- ctx.logger.warn("hook_event_deadline_exceeded", { event, budgetSec: MAX_HOOK_EVENT_TOTAL_SECONDS });
1401
+ if (laneSpent || Date.now() > deadlineAt) {
1402
+ if (!laneSpent)
1403
+ ctx.logger.warn("hook_event_deadline_exceeded", { event, budgetSec: MAX_HOOK_EVENT_TOTAL_SECONDS });
1293
1404
  return { kind: "unrun", reason: "budget_exhausted" };
1294
1405
  }
1295
1406
  if (entry.once)
@@ -1327,19 +1438,35 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1327
1438
  return ifOverBudget ? { kind: "ran", run, overBudget: true } : { kind: "ran", run };
1328
1439
  };
1329
1440
  for (const { group, index } of groups) {
1330
- const selected = matcherGroupSelected(ctx, event, group, matchValue, toolName);
1441
+ const pending = laneSpent ? group.hooks.filter((entry) => blocksOnFailure(entry, event)) : group.hooks;
1442
+ if (laneSpent && pending.length === 0)
1443
+ continue;
1444
+ const selected = matcherGroupSelected(ctx, event, group, matchValue, toolName, pending);
1331
1445
  if (selected === "invalid") {
1332
- for (const entry of group.hooks)
1333
- if (isSyncEntry(entry))
1446
+ for (const entry of pending) {
1447
+ if (!isSyncEntry(entry))
1448
+ continue;
1449
+ if (!laneSpent)
1334
1450
  ledger.unrun(group.source, entry, "matcher_invalid");
1451
+ if (blocksOnFailure(entry, event))
1452
+ results.push(blockedBy(entry, group.source, "matcher_invalid"));
1453
+ }
1335
1454
  continue;
1336
1455
  }
1337
1456
  if (selected === false)
1338
1457
  continue;
1339
1458
  for (const [ei, entry] of group.hooks.entries()) {
1459
+ if (laneSpent && !blocksOnFailure(entry, event))
1460
+ continue;
1340
1461
  const fate = await settle(entry, `${event}:${index}:${ei}`);
1341
1462
  switch (fate.kind) {
1342
1463
  case "ran": {
1464
+ const flaw = blocksOnFailure(entry, event) ? ranVerdictFlaw(event, fate.run) : undefined;
1465
+ if (flaw !== undefined) {
1466
+ noteRanVerdictFlaw(ctx, ledger, event, { entry, run: fate.run, source: group.source }, flaw, toolName);
1467
+ results.push(blockedBy(entry, group.source, flaw.reason));
1468
+ break;
1469
+ }
1343
1470
  const distrust = !PERMISSIVE_VERDICT_EVENTS[event]
1344
1471
  ? undefined
1345
1472
  : truncatedFor(entry)
@@ -1353,9 +1480,12 @@ async function runMatchingEntries(event, groups, matchValue, payload, ctx, onceF
1353
1480
  break;
1354
1481
  }
1355
1482
  case "unrun":
1356
- ledger.unrun(group.source, entry, fate.reason);
1483
+ if (!laneSpent)
1484
+ ledger.unrun(group.source, entry, fate.reason);
1485
+ if (blocksOnFailure(entry, event))
1486
+ results.push(blockedBy(entry, group.source, fate.reason));
1357
1487
  if (fate.reason === "budget_exhausted")
1358
- return results;
1488
+ laneSpent = true;
1359
1489
  break;
1360
1490
  case "passed":
1361
1491
  break;
@@ -1521,7 +1651,7 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1521
1651
  contexts[phase].push(clipDataText(h.additionalContext, MAX_HOOK_FEEDBACK_CHARS));
1522
1652
  spoke = true;
1523
1653
  }
1524
- const decision = h.permissionDecision;
1654
+ const decision = preToolUseDecisionOf(out);
1525
1655
  if (decision === "deny") {
1526
1656
  const reason = clipDataText(typeof h.permissionDecisionReason === "string" ? h.permissionDecisionReason : "denied by a PreToolUse hook", MAX_HOOK_FEEDBACK_CHARS);
1527
1657
  return { deny: { action: "deny", message: reason, ...contextField() } };
@@ -1532,7 +1662,7 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1532
1662
  return { deny: { action: "deny", message: proposesRewrite ? MANAGED_REWRITE_UNSHOWN_REASON : MANAGED_ALLOW_UNJUDGED_REASON, ...contextField() } };
1533
1663
  }
1534
1664
  if (decision === "ask") {
1535
- asked = clipDataText(typeof h.permissionDecisionReason === "string" ? h.permissionDecisionReason : "a PreToolUse hook requires approval", MAX_HOOK_FEEDBACK_CHARS);
1665
+ asked = alsoAsks(prior.asked ?? prior.unreadable?.message, clipDataText(typeof h.permissionDecisionReason === "string" ? h.permissionDecisionReason : "a PreToolUse hook requires approval", MAX_HOOK_FEEDBACK_CHARS));
1536
1666
  spoke = true;
1537
1667
  }
1538
1668
  if (decision === "allow" || decision === undefined) {
@@ -1552,16 +1682,10 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1552
1682
  spoke = true;
1553
1683
  }
1554
1684
  }
1555
- else if (decision !== "deny" && decision !== "ask") {
1685
+ else if (!PERMISSION_DECISION_WORDS.has(decision)) {
1556
1686
  unknownDecision = true;
1557
1687
  spoke = true;
1558
- ctx.logger.warn("hook_permission_decision_unknown", {
1559
- event: "PreToolUse",
1560
- decision: seatText("operator-log-text", typeof decision === "string" ? decision : typeof decision),
1561
- tool: toolName,
1562
- effect: "hook ruling not honored (closed word set is allow|deny|ask); this call falls back to the engine gate",
1563
- });
1564
- ledger.unrun(ran.source, entry, "decision_out_of_set");
1688
+ noteDecisionOutOfSet(ctx, ledger, ran, decision, toolName, "hook ruling not honored (closed word set is allow|deny|ask); this call falls back to the engine gate");
1565
1689
  }
1566
1690
  }
1567
1691
  }
@@ -6,16 +6,13 @@
6
6
  * 不是请求流水线。`createWallClockJumpGuard` 建的 `denySweepClockGuard` 是 ① 的私有件,随它同居。
7
7
  * ctx 字段 3 只(`deps` / `resumeCheckpoint` / `mayDiscloseRowError`),机器算(closure-free-vars)与手抄一致。
8
8
  */
9
- import { type ParkedAskRedeemRequest } from "../tool-approval.js";
9
+ import { type ParkedAskRedeemRequest, type ParkedAskRedeemResult } from "../tool-approval.js";
10
10
  import type { createResumeLegs } from "./resume-legs.js";
11
11
  import type { FlatServiceDeps } from "./server.js";
12
12
  export declare function createApprovalSweeps(ctx: {
13
13
  deps: FlatServiceDeps;
14
14
  } & Pick<ReturnType<typeof createResumeLegs>, "resumeCheckpoint" | "mayDiscloseRowError">): {
15
15
  denyExpiredApprovals: (now: number) => Promise<void>;
16
- redeemParkedAsk: (req: ParkedAskRedeemRequest) => Promise<{
17
- status: number;
18
- body: Record<string, unknown>;
19
- }>;
16
+ redeemParkedAsk: (req: ParkedAskRedeemRequest) => Promise<ParkedAskRedeemResult>;
20
17
  };
21
18
  //# sourceMappingURL=approval-sweeps.d.ts.map
@@ -231,8 +231,9 @@ export function createApprovalSweeps(ctx) {
231
231
  ...(req.gateBoundInputHash !== null ? { boundInputHash: req.gateBoundInputHash } : {}),
232
232
  ...(req.updatedInput !== undefined ? { updatedInput: req.updatedInput } : {}),
233
233
  };
234
- const out = await resumeCheckpoint(cp.sessionId, req.decision, req.note, hostDecisionFacts(req.decider, req.principal), req.httpReq, undefined, binding, undefined, true, { principal: req.principal, explicitOperator: false });
235
- return { status: out.status, body: out.body };
234
+ const remember = req.remember === "session" ? { grantedBy: req.principal ?? null, laneCannotRecord: "decide_once" } : undefined;
235
+ const out = await resumeCheckpoint(cp.sessionId, req.decision, req.note, hostDecisionFacts(req.decider, req.principal), req.httpReq, undefined, binding, remember, true, { principal: req.principal, explicitOperator: false });
236
+ return { status: out.status, body: out.body, ...(remember !== undefined ? { rememberApplied: out.rememberApplied === true } : {}) };
236
237
  }
237
238
  return { denyExpiredApprovals, redeemParkedAsk };
238
239
  }
@@ -157,6 +157,14 @@ export type StoredBodyReplayRefusal =
157
157
  | {
158
158
  readonly kind: "settings_env_credential";
159
159
  readonly refusal: Refusal;
160
+ }
161
+ /** 存体里有本版读者读不出、而本部署会采纳的成员(hooks / settings.env / permissions / MCP transport / A2A headers …;判据 `unread-request-members.ts`):`refusal` = 拒点 `resolveSpec` 抛的那只 400
162
+ * (`request.field_invalid`,`field` = 第一个坐标,句子点名全部坐标)的码、句子与机读位,答复折成 409 `resume_blocked_by_policy`;`members` = 判据交回的坐标(键路径与下标,不带值;与拒句同一个上限,截断由问点做),`memberCount` = 总数 —— 运维行读这两格。 */
163
+ | {
164
+ readonly kind: "unread_members";
165
+ readonly refusal: Refusal;
166
+ readonly members: readonly string[];
167
+ readonly memberCount: number;
160
168
  } | {
161
169
  readonly kind: "permission_mode_reading";
162
170
  readonly stored: PermissionMode | undefined;
@@ -202,6 +210,13 @@ export interface ResumeRefusalAnswer {
202
210
  * · (`retriable`,卡在才在)。
203
211
  */
204
212
  export declare function resumeBlockedByPolicyAnswer(inner: Refusal): ResumeRefusalAnswer;
213
+ /**
214
+ * 续跑腿上认领之前一只 typed 拒的**唯一折法**(`resume-legs.ts` 的两处折叠口同调:装配 `resolveResumeSpec` 与停驻赎回的执行上下文)。一条律:
215
+ * 拒体自报这一拍答不出(`permanence: "transient"` —— 依赖此刻不可用,不是政策:今天 = 中心答不出场景裁定)⇒ 原码原状态原体(同一张卡在依赖恢复后可再决;
216
+ * SLA 拒扫腿按「其余 ≥400」逐拍重试,不把它当确定性拒过期掉);其余 ⇒ {@link resumeBlockedByPolicyAnswer}(准入策略挡住,`blockedBy` = 原码)。
217
+ * 两形之后都由调用方经 {@link resumeRefusalWithCard} 追加 `retriable`(卡仍 pending)。
218
+ */
219
+ export declare function resumeAssemblyRefusalAnswer(status: number, inner: Refusal): ResumeRefusalAnswer;
205
220
  /**
206
221
  * 一次续跑的答复是不是 {@link resumeBlockedByPolicyAnswer} 铸的那一只(409 `resume_blocked_by_policy`)—— SLA 拒扫腿据此区分「同一份字节在本版永远被拒」与别的 ≥400
207
222
  * (后者可能是瞬时的,照旧逐拍重试)。码的写端与读端住在同一个模块,读端不在别处第二次手拼这个字面。
@@ -229,6 +244,8 @@ export declare function storedBodyReplayLogFields(refusal: StoredBodyReplayRefus
229
244
  storedMode?: PermissionMode | null;
230
245
  floor?: PermissionMode;
231
246
  key?: ReplayRefusedRetiredKey;
247
+ members?: readonly string[];
248
+ memberCount?: number;
232
249
  note: string;
233
250
  };
234
251
  /**
@@ -97,6 +97,9 @@ export function resumeBlockedByPolicyAnswer(inner) {
97
97
  body: refusalBody({ errorCode: "resume_blocked_by_policy", message: `resume blocked by an admission policy change: ${inner.message} — nothing was resumed; if the task is still suspended on its approval, cancel it (POST /v1/runs/:id/cancel) to end it without another model turn`, facts: { blockedBy: inner.errorCode, ...inner.facts } }),
98
98
  };
99
99
  }
100
+ export function resumeAssemblyRefusalAnswer(status, inner) {
101
+ return inner.facts?.permanence === "transient" ? { status, body: refusalBody(inner) } : resumeBlockedByPolicyAnswer(inner);
102
+ }
100
103
  export function isResumeBlockedByPolicy(answer) {
101
104
  return answer.status === 409 && typeof answer.body === "object" && answer.body !== null && answer.body.errorCode === "resume_blocked_by_policy";
102
105
  }
@@ -111,6 +114,8 @@ export function storedBodyReplayLogFields(refusal) {
111
114
  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" };
112
115
  case "settings_env_credential":
113
116
  return { kind: refusal.kind, note: "this session's stored request carries credentials in settings.env (a credential variable name of this engine, or a value shaped like a secret) and the one-time window that dropped them on resume has closed; it is not replayed — the task stays suspended until someone cancels it and resubmits with the credentials moved into the engine's environment" };
117
+ case "unread_members":
118
+ return { kind: refusal.kind, members: refusal.members, memberCount: refusal.memberCount, note: "this session's stored request carries members this version's readers cannot take as written (named in the refusal: settings.hooks / settings.env / an MCP server's transport / an A2A peer's headers …) and this deployment would apply them; replaying it would run without them, so it is not replayed — the task stays suspended until someone cancels it and resubmits with those members in the current form" };
114
119
  case "permission_mode_reading":
115
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" };
116
121
  case "retired_request_key":
@@ -133,6 +138,7 @@ function storedBodyReplayArmAnswer(refusal, readerVersion) {
133
138
  case "inert_tool_list":
134
139
  return resumeBlockedByPolicyAnswer(refusal.entry.extra === undefined ? { errorCode: refusal.entry.code, message: refusal.entry.message } : { errorCode: refusal.entry.code, message: refusal.entry.message, facts: refusal.entry.extra });
135
140
  case "settings_env_credential":
141
+ case "unread_members":
136
142
  return resumeBlockedByPolicyAnswer(refusal.refusal);
137
143
  case "permission_mode_reading": {
138
144
  const answer = permissionModeReadingRefusal();
@@ -0,0 +1,10 @@
1
+ /** `step` 标签的闭集:一个往返一个词。 */
2
+ export declare const EXECUTION_CLAIM_STEPS: readonly ["run_claim", "placement_commit"];
3
+ export type ExecutionClaimStep = (typeof EXECUTION_CLAIM_STEPS)[number];
4
+ /** 计时落点:`Metrics` 的 `observe` 子集(deps 上没有指标注册表、或只带计数的桩 ⇒ 不计,行为逐字不变)。 */
5
+ export interface ClaimLatencySink {
6
+ observe?(name: string, value: number, labels?: Record<string, string>): void;
7
+ }
8
+ /** 量一次认领往返(秒)。`claim` 是刚发出的往返(调用点在实参位置发起它,时钟随即起);抛也计、上抛原错。 */
9
+ export declare function timeClaim<T>(sink: ClaimLatencySink | undefined, step: ExecutionClaimStep, claim: Promise<T>): Promise<T>;
10
+ //# sourceMappingURL=claim-latency.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { EXECUTION_CLAIM_METRIC } from "../observability/metrics.js";
2
+ export const EXECUTION_CLAIM_STEPS = ["run_claim", "placement_commit"];
3
+ export async function timeClaim(sink, step, claim) {
4
+ const started = performance.now();
5
+ try {
6
+ return await claim;
7
+ }
8
+ finally {
9
+ sink?.observe?.(EXECUTION_CLAIM_METRIC, (performance.now() - started) / 1000, { step });
10
+ }
11
+ }
12
+ //# sourceMappingURL=claim-latency.js.map
@@ -131,7 +131,7 @@ export function createDispatch(ctx) {
131
131
  const engineSignal = buildEngineSignal(signal);
132
132
  const declaredMods = deploymentModPackagesFact(deps);
133
133
  const configHash = createHash("sha256")
134
- .update(JSON.stringify({ model: deps.config.model.id, sessionBackend: deps.config.sessionBackend, dbBackend: deps.config.dbBackend, dataRoot: deps.config.localDataRoot, configProvider: deps.config.configProvider, remoteExec: deps.config.remoteExec?.provider, port: deps.config.port }))
134
+ .update(JSON.stringify({ model: deps.config.model.id, sessionBackend: deps.config.sessionBackend, dbBackend: deps.config.dbBackend, dataRoot: deps.config.localDataRoot, configProvider: deps.config.configProvider, remoteExec: deps.config.remoteExec.provider, port: deps.config.port }))
135
135
  .digest("hex")
136
136
  .slice(0, 16);
137
137
  sendJson(res, 200, {
@@ -8,6 +8,7 @@ import { declaredApprovalFrameFamilies, resolveStreamApprovalGate } from "../too
8
8
  import { buildActiveRunConflict } from "./active-run-conflict.js";
9
9
  import { commitExecutionContext } from "./execution-context.js";
10
10
  import { rootSessionAbsentAnswer } from "./execution-context.js";
11
+ import { timeClaim } from "./claim-latency.js";
11
12
  import { commitSessionInheritEnv } from "./session-inherit-env.js";
12
13
  import { clearTurnActivity, readTurnActivityMs } from "../turn-activity.js";
13
14
  import { recordResourceWindow } from "../resource-window.js";
@@ -21,7 +22,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
21
22
  const sessionId = args.prepared.spec.sessionId;
22
23
  const taskId = args.clientTaskId ?? uuidv7();
23
24
  const trustedInternals = await heldWorkflowParkDecisions(deps, sessionId, args.workflowDecision?.carried);
24
- const created = await runStore.createRun(taskId, sessionId, args.prepared.auth?.principal ?? null, deps.instanceId ?? "default", { ...runMeta(args.prepared, args.source), identity: args.identity, idem: args.idem ?? null });
25
+ const created = await timeClaim(deps.metrics, "run_claim", runStore.createRun(taskId, sessionId, args.prepared.auth?.principal ?? null, deps.instanceId ?? "default", { ...runMeta(args.prepared, args.source), identity: args.identity, idem: args.idem ?? null }));
25
26
  if (created.ok)
26
27
  clearTurnActivity(taskId);
27
28
  if (created.ok)
@@ -19,7 +19,8 @@
19
19
  * ④ 只 fresh:设备准入链(体 `deviceId` 只在 device 车道收;准入链三步 + 首绑目标三读,全读;判的是步 ① 那一读)。
20
20
  *
21
21
  * 入口三形(判别联合,{@link ExecutionEntry}):`fresh`(提交腿:根 = authorizer 交出的 `auth.sessionId`,`judged` = authorizer 判过的头)·
22
- * `continuation`(续跑家族与停驻赎回:根 = checkpoint / 停驻行的根;不带 `judged` —— 步 ① 那一读就是这条执行对根的唯一一读,认领之后由写口按它判)·
22
+ * `continuation`(续跑家族与停驻赎回:根 = checkpoint / 停驻行的根;不带 `judged` —— 步 ① 那一读就是这条执行对根的唯一一读,认领之后由写口按它判;
23
+ * run 外回退口 `POST /v1/sessions/:id/rewind-files` 同形:根 = 路径上的会话,它不认领、不提交放置,只取步 ①–③ 的拒)·
23
24
  * `service`(服务 run:没有会话根)。
24
25
  * `fresh` / `continuation` 两形型上恒带 `root: string`,`service` 形没有 `root` 键 —— 「按一只缺席的根去读行」在型上不可表达。
25
26
  *
@@ -202,6 +203,7 @@ export interface ExecutionCommitDeps {
202
203
  } | undefined;
203
204
  readonly metrics?: {
204
205
  inc(name: string, labels?: Record<string, string>): void;
206
+ observe?(name: string, value: number, labels?: Record<string, string>): void;
205
207
  } | undefined;
206
208
  }
207
209
  /**
@@ -8,6 +8,7 @@ import { gateExecutionLane } from "../runtime-caps-resolver.js";
8
8
  import { releaseClaimedRun } from "./claimed-run.js";
9
9
  import { sessionIdRetiredFor } from "../deleted-session-ids.js";
10
10
  import { refusalBody } from "./refusal-body.js";
11
+ import { timeClaim } from "./claim-latency.js";
11
12
  export async function resolveExecutionContext(deps, entry) {
12
13
  const lanes = deployedExecutionLanes(deps.config);
13
14
  switch (entry.kind) {
@@ -203,6 +204,9 @@ export async function commitExecutionContext(deps, claim, ctx) {
203
204
  if (ctx.occupant === undefined || seat === undefined)
204
205
  return null;
205
206
  const occupant = ctx.occupant;
207
+ return timeClaim(deps.metrics, "placement_commit", commitPlacement(deps, claim, ctx, seat, occupant));
208
+ }
209
+ async function commitPlacement(deps, claim, ctx, seat, occupant) {
206
210
  const release = (why) => releaseClaim(deps, claim, why);
207
211
  const deadlineMs = placementWriteDeadlineMs(deps.config?.runStaleSec);
208
212
  const withDeadline = async (work) => {
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * ## 规则(三层,与 operator 面既有层序逐字同序)
12
12
  * ① core 的**本口专属**码(闭集穷举 `switch`,见 {@link sentCoreCode})—— 码与状态两面同;文案按受众(下一节,一条规则);
13
- * ② **店形拒**两码 `memory.target_outside_store`(core 7.31.1 [ref])/ `memory.scope_home_not_directory`(core 7.44.0 [ref])—— 跨面 store 状态码,409、码原样
13
+ * ② **店形拒**一族(按族表读;成员举例 `memory.target_outside_store` / `memory.scope_home_not_directory` / 引擎 7.65.0 起 `memory.control_plane_links_unsupported`)—— 跨面 store 状态码,409、码原样
14
14
  * (判据 `memory-store-refusal.ts` 一只;运维行 `memory_store_form_refused { code, path?, form? }` 两受众同一只铸点,路径只在那里);
15
15
  * ③ `ControlPlaneCorruptError` —— typed 500 `internal.memory_control_plane_corrupt`(fail-closed 信号,一码两义;映射本体在 `memory-control-plane-corrupt-reply.ts` 那一只,导出导入 / 外源 / 整理 / 合规各口同调);
16
16
  * 其余 ⇒ `false`(未分类,调用方发它自己那句 500 且**不回显**内部文本)。
@@ -63,6 +63,9 @@ export function sentMemoryComplianceFailure(res, err, audience, logger) {
63
63
  case "memory.scope_home_not_directory":
64
64
  sendError(res, 409, "memory.scope_home_not_directory", "session memory erasure refused — a scope directory in this deployment's memory store is not a real directory (it was replaced by a link or a file), so this erasure did not complete; ask the operator to put the real directory back, then resend with the same requestId");
65
65
  return true;
66
+ case "memory.control_plane_links_unsupported":
67
+ sendError(res, 409, "memory.control_plane_links_unsupported", "session memory erasure refused — this deployment's memory control plane is on a file system that cannot make hard links, so its memory store does not open and this erasure changed nothing; ask the operator to move the control plane to a volume that supports hard links, then resend with the same requestId");
68
+ return true;
66
69
  default:
67
70
  return assertNever(storeForm.code);
68
71
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
- * **店形拒**两码(`memory.target_outside_store` / `memory.scope_home_not_directory`,判据在 `src/memory-store-refusal.ts`)的
3
- * **operator 面 HTTP 映射** + 两受众共用的**运维行** —— 唯一一处码字面量。挂在每一个触 store 树的 operator 记忆口的已分类收尾上:
2
+ * **店形拒**一族(`memory.target_outside_store` / `memory.scope_home_not_directory` / `memory.control_plane_links_unsupported`,族表与判据在 `src/memory-store-refusal.ts`)的
3
+ * **operator 面 HTTP 映射** + 两受众共用的**运维行** —— operator 面唯一一处码字面量(会话所有者面的逐码臂在 `http/memory-compliance-failure-reply.ts`;引擎加码 ⇒ 两处各补一臂)。挂在每一个触 store 树的 operator 记忆口的已分类收尾上:
4
4
  * `routes/memory-compliance.ts`(出处 / 抹除;经 `http/memory-compliance-failure-reply.ts` 的 operator 受众臂)· `routes/memory-origin.ts`(外源列表 / 清标;**不含**只读控制面的清标账列表 ——
5
5
  * core 的 wire 表逐字:只碰控制面的面不判,给它挂一条永远收不到的码路径正是附录 A 活触发门要防的形)·
6
6
  * `routes/memory-bundle.ts`(导出 / 导入)。会话所有者的自助抹除口**不走这里的 wire 句**(经 `http/memory-compliance-failure-reply.ts` 的会话所有者受众臂:同码、固定文案),
@@ -8,7 +8,7 @@
8
8
  * `POST /v1/admin/memory/consolidation/run` 也不走这里:那口把 core 的**任何**有码拒一律收成 409 `memory.consolidation_refused`
9
9
  * (码进文案,附录 A 该行),这一族已在那条臂上,不再给它第二个码。
10
10
  *
11
- * ## 为什么 409(两码同一条)
11
+ * ## 为什么 409(一族同一条)
12
12
  * core 的读法:operator 要处置的盘形(去掉 store 里那只通到外面的目录链 / 把 scope home 放回真目录),不是可重试的 IO 故障,也不是对调用方的裁决。与
13
13
  * `memory.erasure_census_incomplete` 同一类(**当前 store 状态**下这次做不了;状态修好后重发即改判)⇒ 409,不 500(服务器没坏)、
14
14
  * 不 4xx 请求族(请求没写错)。抹除面:链先于请求在场 ⇒ core 在提交点之前拒,零删除、零 journal(真 core 格钉在
@@ -12,6 +12,9 @@ export function sentMemoryStoreRefusal(res, err, logger) {
12
12
  case "memory.scope_home_not_directory":
13
13
  sendError(res, 409, "memory.scope_home_not_directory", refusal.message);
14
14
  return true;
15
+ case "memory.control_plane_links_unsupported":
16
+ sendError(res, 409, "memory.control_plane_links_unsupported", refusal.message);
17
+ return true;
15
18
  default: {
16
19
  const unhandled = refusal.code;
17
20
  throw new Error(`unhandled store-form refusal word: ${String(unhandled)}`);
@@ -16,6 +16,7 @@
16
16
  import type { ServiceConfig } from "../config-types.js";
17
17
  import type { Logger } from "../observability/logger.js";
18
18
  import type { RunRecord } from "../plugins/store-contracts.js";
19
+ import type { SessionHead } from "@sema-agent/core";
19
20
  import { type OwnerAwareSessionStore, type Principal, type SessionCaller, type SessionOwnerCell } from "../security.js";
20
21
  import { type IdentityWiring, type OperatorRoster } from "./principal-gate.js";
21
22
  /** 调用点挂哪条臂(闭集):`owner` = 只有属主判官;`owner_or_operator` = 属主判官 ∨ 显式运维(`explicitOperatorOk`,唯一读法)。 */
@@ -46,6 +47,16 @@ export declare function readOwnedRun(config: OwnerAccessConfig, runStore: {
46
47
  export declare function readOwnedSession(w: IdentityWiring & {
47
48
  readonly config: OwnerAccessConfig;
48
49
  }, store: Pick<OwnerAwareSessionStore, "placementOf"> & Required<Pick<OwnerAwareSessionStore, "headOf">>, caller: SessionCaller, sessionId: string, arm: OwnerArm): Promise<SessionOwnerCell | undefined>;
50
+ /**
51
+ * 同一只读口,连头一起交回:门过了的调用点还要读这只会话的**内容**(坏档判据 `leafOfAdmittedHead` 读头的叶子;门之前不许读)或头上的属主原值时用它 ——
52
+ * 一次头读、一只判官,与 {@link readOwnedSession} 是同一读(那一只就是本函数取 `cell`)。`undefined` 的读法同上。
53
+ */
54
+ export declare function readOwnedSessionHead(w: IdentityWiring & {
55
+ readonly config: OwnerAccessConfig;
56
+ }, store: Pick<OwnerAwareSessionStore, "placementOf"> & Required<Pick<OwnerAwareSessionStore, "headOf">>, caller: SessionCaller, sessionId: string, arm: OwnerArm): Promise<{
57
+ readonly cell: SessionOwnerCell;
58
+ readonly head: SessionHead;
59
+ } | undefined>;
49
60
  /**
50
61
  * 🔴 **会话读面的属主读的第三个结局**:有主 / 无此行 / **属主读不出**(店交出具名拒 {@link SessionOwnerUnreadableError} —— 会话的行事实没有落下,补铸它要读的存档又用不了;
51
62
  * 谁也判不了「这是不是你的会话」)。第三个读作第二个:**与「没有这一行」同一个值**(`undefined`),调用点落的就是它们对「不存在 / 非属主」的那一臂 ——
@@ -32,11 +32,14 @@ export async function readOwnedRun(config, runStore, principal, taskId, arm) {
32
32
  return row !== undefined && runRowReadable(config, principal, row.owner, arm) ? row : undefined;
33
33
  }
34
34
  export async function readOwnedSession(w, store, caller, sessionId, arm) {
35
- const owner = (await store.headOf(sessionId))?.owner;
36
- if (owner === undefined)
35
+ return (await readOwnedSessionHead(w, store, caller, sessionId, arm))?.cell;
36
+ }
37
+ export async function readOwnedSessionHead(w, store, caller, sessionId, arm) {
38
+ const head = await store.headOf(sessionId);
39
+ if (head === undefined || head.owner === undefined)
37
40
  return undefined;
38
- const cell = await sessionOwnerCellOf(store, sessionId, owner);
39
- return operatorArmHolds(w.config, caller.principal, arm) || sessionOwnerReadable(caller, cell, w) ? cell : undefined;
41
+ const cell = await sessionOwnerCellOf(store, sessionId, head.owner);
42
+ return operatorArmHolds(w.config, caller.principal, arm) || sessionOwnerReadable(caller, cell, w) ? { cell, head } : undefined;
40
43
  }
41
44
  export async function foldOwnerUnreadable(logger, face, sessionId, read) {
42
45
  try {