@sema-agent/server 7.132.0 → 7.133.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 (402) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +174 -55
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +79 -19
  24. package/dist/approval-card.js +44 -13
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +27 -10
  29. package/dist/audit.js +12 -16
  30. package/dist/bake-runner/main.js +3 -2
  31. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  32. package/dist/boot/execution-env.js +9 -7
  33. package/dist/boot/execution-lane.js +11 -0
  34. package/dist/boot/leader.js +2 -0
  35. package/dist/boot/memory-boundary.js +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +5 -4
  37. package/dist/boot/memory-consolidation.js +7 -6
  38. package/dist/boot/org-delivery.d.ts +28 -0
  39. package/dist/boot/org-delivery.js +20 -0
  40. package/dist/boot/reapers.d.ts +3 -0
  41. package/dist/boot/reapers.js +21 -1
  42. package/dist/boot/resolve-spec.d.ts +3 -0
  43. package/dist/boot/resolve-spec.js +60 -81
  44. package/dist/boot/runner-deps.js +1 -0
  45. package/dist/boot/session-faces.d.ts +1 -0
  46. package/dist/boot/session-faces.js +4 -2
  47. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  48. package/dist/boot/stage-06-runners.d.ts +2 -0
  49. package/dist/boot/stage-06-runners.js +6 -3
  50. package/dist/boot/stage-07-capability-layer.d.ts +2 -0
  51. package/dist/boot/stage-07-capability-layer.js +24 -3
  52. package/dist/boot/stage-08-reapers.d.ts +2 -0
  53. package/dist/boot/stage-08-reapers.js +2 -2
  54. package/dist/boot/stage-09-leader.d.ts +3 -0
  55. package/dist/boot/stage-10-http-server.d.ts +3 -0
  56. package/dist/boot/stage-10-http-server.js +5 -6
  57. package/dist/boot/stores.js +2 -2
  58. package/dist/boot/web-admin.d.ts +4 -0
  59. package/dist/boot/web-admin.js +151 -63
  60. package/dist/boot/workflow-orchestration.d.ts +2 -0
  61. package/dist/boot/workflow-orchestration.js +2 -1
  62. package/dist/brain.js +8 -3
  63. package/dist/breaker-key.d.ts +6 -0
  64. package/dist/breaker-key.js +29 -0
  65. package/dist/caller-text-echo.d.ts +9 -6
  66. package/dist/caller-text-echo.js +8 -11
  67. package/dist/capabilities/center-plugins.d.ts +7 -0
  68. package/dist/capabilities/center-plugins.js +1 -1
  69. package/dist/capabilities/composite-members.d.ts +1 -1
  70. package/dist/capabilities/composite-members.js +1 -1
  71. package/dist/capabilities/execution-lane.js +2 -2
  72. package/dist/capabilities/hands-lane.d.ts +21 -0
  73. package/dist/capabilities/hands-lane.js +10 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -4
  75. package/dist/capabilities/mcp-probe.js +27 -4
  76. package/dist/capabilities/scenarios.d.ts +63 -7
  77. package/dist/capabilities/scenarios.js +39 -7
  78. package/dist/capability-facts.d.ts +34 -4
  79. package/dist/capability-facts.js +28 -2
  80. package/dist/center-config-tier.d.ts +69 -0
  81. package/dist/center-config-tier.js +42 -0
  82. package/dist/checkpoint-identity.d.ts +16 -0
  83. package/dist/checkpoint-identity.js +19 -0
  84. package/dist/config-catalog.d.ts +17 -10
  85. package/dist/config-catalog.js +43 -28
  86. package/dist/config-d-migration.d.ts +3 -1
  87. package/dist/config-d-migration.js +2 -2
  88. package/dist/config-dir-trust.d.ts +114 -0
  89. package/dist/config-dir-trust.js +388 -0
  90. package/dist/config-invariants.d.ts +18 -5
  91. package/dist/config-invariants.js +35 -3
  92. package/dist/config-provider.d.ts +6 -1
  93. package/dist/config-provider.js +6 -2
  94. package/dist/config-types.d.ts +71 -14
  95. package/dist/config-types.js +8 -0
  96. package/dist/config.d.ts +13 -0
  97. package/dist/config.js +121 -59
  98. package/dist/delegated-session-owner.d.ts +185 -0
  99. package/dist/delegated-session-owner.js +119 -0
  100. package/dist/device-protocol.d.ts +5 -3
  101. package/dist/device-protocol.js +1 -1
  102. package/dist/device-ws-hub.js +21 -2
  103. package/dist/device-ws-protocol.d.ts +70 -6
  104. package/dist/device-ws-protocol.js +50 -23
  105. package/dist/elicitation.js +3 -2
  106. package/dist/entry-problems.d.ts +34 -0
  107. package/dist/entry-problems.js +14 -0
  108. package/dist/execution-lane-caps.d.ts +49 -10
  109. package/dist/execution-lane-caps.js +43 -4
  110. package/dist/field-conflict.d.ts +43 -0
  111. package/dist/field-conflict.js +20 -0
  112. package/dist/fleet/fleet-bus.d.ts +80 -6
  113. package/dist/fleet/fleet-bus.js +41 -9
  114. package/dist/hooks/classic-stations.d.ts +10 -5
  115. package/dist/hooks/classic-stations.js +4 -4
  116. package/dist/hooks/command-spawn.d.ts +57 -0
  117. package/dist/hooks/command-spawn.js +139 -0
  118. package/dist/hooks/hook-llm.js +2 -2
  119. package/dist/hooks/hook-runner.d.ts +127 -25
  120. package/dist/hooks/hook-runner.js +668 -287
  121. package/dist/hooks/hook-source.d.ts +44 -0
  122. package/dist/hooks/hook-source.js +40 -0
  123. package/dist/http/active-run-conflict.d.ts +5 -13
  124. package/dist/http/active-run-conflict.js +17 -27
  125. package/dist/http/admission.js +103 -60
  126. package/dist/http/approval-sweeps.js +55 -18
  127. package/dist/http/caller-trust.d.ts +77 -0
  128. package/dist/http/caller-trust.js +143 -0
  129. package/dist/http/checkpoint-ctx.d.ts +16 -16
  130. package/dist/http/checkpoint-ctx.js +13 -10
  131. package/dist/http/claimed-run.d.ts +4 -3
  132. package/dist/http/device-placement.d.ts +2 -4
  133. package/dist/http/device-placement.js +2 -1
  134. package/dist/http/dispatch.js +10 -4
  135. package/dist/http/durable-run-leg.d.ts +4 -32
  136. package/dist/http/durable-run-leg.js +34 -10
  137. package/dist/http/owner-access.d.ts +56 -0
  138. package/dist/http/owner-access.js +42 -0
  139. package/dist/http/principal-gate.d.ts +48 -23
  140. package/dist/http/principal-gate.js +39 -12
  141. package/dist/http/readiness.d.ts +11 -5
  142. package/dist/http/readiness.js +10 -3
  143. package/dist/http/request-guards.d.ts +16 -23
  144. package/dist/http/request-guards.js +30 -15
  145. package/dist/http/resume-ctx-read.d.ts +2 -5
  146. package/dist/http/resume-ctx-read.js +7 -4
  147. package/dist/http/resume-legs.d.ts +3 -4
  148. package/dist/http/resume-legs.js +126 -69
  149. package/dist/http/retired-service-deps.d.ts +43 -0
  150. package/dist/http/retired-service-deps.js +18 -0
  151. package/dist/http/route-ctx.d.ts +44 -28
  152. package/dist/http/route-ctx.js +4 -0
  153. package/dist/http/route-table.js +2 -0
  154. package/dist/http/routes/a2a-serve.js +3 -4
  155. package/dist/http/routes/admin-config-refresh.js +1 -1
  156. package/dist/http/routes/admin-drain.js +1 -1
  157. package/dist/http/routes/admin-memory-optout.js +5 -1
  158. package/dist/http/routes/adoption.js +2 -9
  159. package/dist/http/routes/approvals-assistant.js +49 -48
  160. package/dist/http/routes/background.js +3 -2
  161. package/dist/http/routes/capabilities.js +20 -4
  162. package/dist/http/routes/config-catalog.d.ts +3 -3
  163. package/dist/http/routes/config-catalog.js +1 -1
  164. package/dist/http/routes/devices.js +3 -17
  165. package/dist/http/routes/diagnostics.js +5 -1
  166. package/dist/http/routes/images.js +6 -7
  167. package/dist/http/routes/leader.js +1 -8
  168. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  169. package/dist/http/routes/mcp-reconnect.js +3 -2
  170. package/dist/http/routes/memory-bundle.js +1 -1
  171. package/dist/http/routes/memory-compliance.js +1 -1
  172. package/dist/http/routes/memory-consolidation.js +1 -1
  173. package/dist/http/routes/memory-origin.js +1 -1
  174. package/dist/http/routes/memory-policy.d.ts +1 -1
  175. package/dist/http/routes/memory-policy.js +3 -2
  176. package/dist/http/routes/notify-wake.js +8 -21
  177. package/dist/http/routes/observability.js +2 -2
  178. package/dist/http/routes/principal-inbox.d.ts +39 -0
  179. package/dist/http/routes/principal-inbox.js +76 -0
  180. package/dist/http/routes/retention-ops.js +2 -9
  181. package/dist/http/routes/rules.js +5 -18
  182. package/dist/http/routes/runs.d.ts +5 -0
  183. package/dist/http/routes/runs.js +33 -106
  184. package/dist/http/routes/session-sync.js +15 -28
  185. package/dist/http/routes/sessions.js +30 -40
  186. package/dist/http/routes/side-query.js +6 -4
  187. package/dist/http/routes/tasks.js +50 -14
  188. package/dist/http/routes/workflows.d.ts +351 -0
  189. package/dist/http/routes/workflows.js +153 -119
  190. package/dist/http/send.d.ts +24 -3
  191. package/dist/http/send.js +14 -2
  192. package/dist/http/server.d.ts +17 -18
  193. package/dist/http/server.js +15 -13
  194. package/dist/http/stored-body-replay.js +17 -4
  195. package/dist/http/submit-ctx.js +4 -3
  196. package/dist/http/submit-replay.d.ts +4 -3
  197. package/dist/http/submit-replay.js +5 -4
  198. package/dist/http/wire-types.d.ts +10 -7
  199. package/dist/index.d.ts +1 -1
  200. package/dist/index.js +0 -1
  201. package/dist/lane-home-probe.d.ts +78 -9
  202. package/dist/lane-home-probe.js +78 -12
  203. package/dist/leader/endpoint.d.ts +4 -1
  204. package/dist/leader/endpoint.js +11 -10
  205. package/dist/limit-refusal.d.ts +17 -5
  206. package/dist/limit-refusal.js +4 -1
  207. package/dist/mcp-assertion-header.d.ts +31 -10
  208. package/dist/mcp-assertion-header.js +10 -3
  209. package/dist/mcp-tool-faces.js +1 -3
  210. package/dist/memory-project-layer.d.ts +37 -0
  211. package/dist/memory-project-layer.js +46 -0
  212. package/dist/memory-scope.d.ts +23 -16
  213. package/dist/memory-scope.js +24 -8
  214. package/dist/memory-sync-client.d.ts +27 -13
  215. package/dist/memory-sync-client.js +107 -18
  216. package/dist/model-entry-refusal.d.ts +9 -1
  217. package/dist/model-entry-refusal.js +6 -1
  218. package/dist/model-plane-face.d.ts +51 -0
  219. package/dist/model-plane-face.js +24 -0
  220. package/dist/model-provider.d.ts +5 -0
  221. package/dist/model-provider.js +4 -2
  222. package/dist/model-route-endpoint.d.ts +8 -11
  223. package/dist/model-route-endpoint.js +4 -7
  224. package/dist/model-route-env.d.ts +22 -0
  225. package/dist/model-route-env.js +2 -0
  226. package/dist/model-route-gap.d.ts +60 -30
  227. package/dist/model-route-gap.js +21 -15
  228. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  229. package/dist/observability/corrupt-read-seat.js +9 -0
  230. package/dist/observability/err-text.d.ts +6 -0
  231. package/dist/observability/err-text.js +18 -4
  232. package/dist/observability/fail-open.d.ts +35 -9
  233. package/dist/observability/fail-open.js +35 -9
  234. package/dist/observability/metrics.js +1 -0
  235. package/dist/observability/prompt-manifest.d.ts +3 -17
  236. package/dist/observability/prompt-manifest.js +45 -42
  237. package/dist/observability/tool-trace.js +9 -9
  238. package/dist/operator-ask.d.ts +10 -0
  239. package/dist/operator-ask.js +3 -0
  240. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  241. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  242. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  243. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  244. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  245. package/dist/orchestration/workflow-notify-journal.js +27 -34
  246. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  247. package/dist/orchestration/workflow-park-decision.js +118 -0
  248. package/dist/org-delivery-gate.d.ts +81 -0
  249. package/dist/org-delivery-gate.js +59 -0
  250. package/dist/panel-tool-names.d.ts +23 -0
  251. package/dist/panel-tool-names.js +8 -0
  252. package/dist/parked-decide.d.ts +39 -6
  253. package/dist/parked-decide.js +98 -51
  254. package/dist/parked-revive-surface.d.ts +9 -2
  255. package/dist/parked-revive-surface.js +11 -8
  256. package/dist/permission-rule-list.d.ts +1 -1
  257. package/dist/permission-rule-list.js +2 -2
  258. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  259. package/dist/plugins/approval-ask-store-file.js +21 -0
  260. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  261. package/dist/plugins/approval-ask-store-memory.js +34 -2
  262. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  263. package/dist/plugins/approval-ask-store-sql.js +37 -1
  264. package/dist/plugins/blob-backend.d.ts +38 -25
  265. package/dist/plugins/blob-backend.js +29 -19
  266. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  267. package/dist/plugins/breaker-state-sql.js +4 -4
  268. package/dist/plugins/caching-session-store.d.ts +3 -0
  269. package/dist/plugins/caching-session-store.js +3 -0
  270. package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
  271. package/dist/plugins/checkpoint-store-sql.js +20 -2
  272. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  273. package/dist/plugins/file-history-store-sql.js +3 -1
  274. package/dist/plugins/file-run-store.d.ts +5 -13
  275. package/dist/plugins/file-run-store.js +9 -0
  276. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  277. package/dist/plugins/fork-routing-session-store.js +12 -1
  278. package/dist/plugins/host-platform.d.ts +2 -0
  279. package/dist/plugins/host-platform.js +2 -1
  280. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  281. package/dist/plugins/local-checkpoint-store.js +6 -1
  282. package/dist/plugins/local-session-store.d.ts +1 -1
  283. package/dist/plugins/local-session-window.d.ts +39 -0
  284. package/dist/plugins/local-session-window.js +54 -0
  285. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  286. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  287. package/dist/plugins/mailbox-store-sql.js +77 -52
  288. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  289. package/dist/plugins/memory-run-store.d.ts +5 -13
  290. package/dist/plugins/memory-run-store.js +8 -0
  291. package/dist/plugins/one-time-migrations.d.ts +110 -5
  292. package/dist/plugins/one-time-migrations.js +320 -8
  293. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  294. package/dist/plugins/org-delivery-quota-store.js +228 -0
  295. package/dist/plugins/pg-pool.js +39 -7
  296. package/dist/plugins/pg-session-storage.d.ts +17 -4
  297. package/dist/plugins/pg-session-storage.js +29 -6
  298. package/dist/plugins/remote-env-adb.d.ts +6 -12
  299. package/dist/plugins/remote-env-adb.js +12 -2
  300. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  301. package/dist/plugins/remote-env-k8s.js +23 -5
  302. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  303. package/dist/plugins/remote-env-local-docker.js +12 -9
  304. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  305. package/dist/plugins/remote-env-ssh.js +17 -11
  306. package/dist/plugins/run-store-sql.d.ts +16 -14
  307. package/dist/plugins/run-store-sql.js +22 -2
  308. package/dist/plugins/schema-indexes.js +2 -0
  309. package/dist/plugins/send-user-file.js +2 -2
  310. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  311. package/dist/plugins/session-epoch-anchor.js +2 -3
  312. package/dist/plugins/session-store.d.ts +18 -8
  313. package/dist/plugins/session-store.js +15 -4
  314. package/dist/plugins/sql-driver.d.ts +74 -11
  315. package/dist/plugins/sql-driver.js +210 -12
  316. package/dist/plugins/sql-errors.d.ts +23 -0
  317. package/dist/plugins/sql-errors.js +21 -0
  318. package/dist/plugins/store-backend.d.ts +36 -1
  319. package/dist/plugins/store-backend.js +40 -14
  320. package/dist/plugins/store-contracts.d.ts +42 -0
  321. package/dist/plugins/store-contracts.js +1 -0
  322. package/dist/plugins/tidb-pool.d.ts +6 -1
  323. package/dist/plugins/tidb-pool.js +44 -10
  324. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  325. package/dist/plugins/tidb-session-storage.js +2 -2
  326. package/dist/plugins/tidb-session-store.d.ts +24 -4
  327. package/dist/plugins/tidb-session-store.js +28 -4
  328. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  329. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  330. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  331. package/dist/plugins/workflow-run-store-sql.js +50 -9
  332. package/dist/posture-source.d.ts +18 -10
  333. package/dist/posture-source.js +4 -1
  334. package/dist/project-identity.d.ts +45 -6
  335. package/dist/project-identity.js +162 -8
  336. package/dist/project-layer-key.d.ts +28 -0
  337. package/dist/project-layer-key.js +29 -0
  338. package/dist/question.js +3 -2
  339. package/dist/read-deny-entry.d.ts +25 -0
  340. package/dist/read-deny-entry.js +12 -0
  341. package/dist/read-face-posture.d.ts +37 -11
  342. package/dist/read-face-posture.js +32 -3
  343. package/dist/request-key-closure.d.ts +7 -0
  344. package/dist/request-key-closure.js +9 -1
  345. package/dist/request-value-closure.d.ts +5 -0
  346. package/dist/request-value-closure.js +11 -3
  347. package/dist/rule-entry-list.d.ts +26 -2
  348. package/dist/rule-entry-list.js +72 -12
  349. package/dist/rules-consent.js +3 -4
  350. package/dist/run-acceptance.d.ts +19 -3
  351. package/dist/run-acceptance.js +13 -1
  352. package/dist/run-local.js +36 -6
  353. package/dist/runs.d.ts +10 -9
  354. package/dist/runs.js +21 -3
  355. package/dist/runtime-caps-resolver.d.ts +16 -6
  356. package/dist/runtime-caps-resolver.js +18 -5
  357. package/dist/sandbox-pkg-source.d.ts +19 -1
  358. package/dist/sandbox-pkg-source.js +29 -7
  359. package/dist/security.d.ts +87 -9
  360. package/dist/security.js +52 -9
  361. package/dist/session-error-wire.d.ts +19 -2
  362. package/dist/session-error-wire.js +5 -1
  363. package/dist/session-titled-frame.d.ts +33 -0
  364. package/dist/session-titled-frame.js +4 -0
  365. package/dist/session-titler.d.ts +9 -1
  366. package/dist/session-titler.js +15 -4
  367. package/dist/spec-fields.js +21 -2
  368. package/dist/sql-engine-posture.d.ts +3 -1
  369. package/dist/task-cwd.d.ts +1 -1
  370. package/dist/task-mcp.d.ts +3 -3
  371. package/dist/task-mcp.js +7 -66
  372. package/dist/task-settings.d.ts +89 -88
  373. package/dist/task-settings.js +71 -63
  374. package/dist/text-bidi.d.ts +0 -4
  375. package/dist/text-bidi.js +1 -3
  376. package/dist/tighten-only-seats.d.ts +150 -0
  377. package/dist/tighten-only-seats.js +196 -0
  378. package/dist/tool-approval.d.ts +303 -87
  379. package/dist/tool-approval.js +623 -239
  380. package/dist/trace/core-keyset-guard.d.ts +104 -22
  381. package/dist/trace/exit-seat.d.ts +28 -0
  382. package/dist/trace/exit-seat.js +76 -0
  383. package/dist/trace/ledger-events.d.ts +3 -2
  384. package/dist/trace/project.d.ts +80 -12
  385. package/dist/trace/project.js +41 -28
  386. package/dist/trace/projection-table.d.ts +100 -0
  387. package/dist/trace/projection-table.js +130 -0
  388. package/dist/trace/redact.d.ts +54 -0
  389. package/dist/trace/redact.js +778 -152
  390. package/dist/trace/self-minted-wire.d.ts +345 -1
  391. package/dist/trace/self-minted-wire.js +117 -1
  392. package/dist/trace/wire-projection-faces.d.ts +298 -2
  393. package/dist/trace/wire-projection-faces.js +154 -13
  394. package/dist/url-refusal.js +2 -0
  395. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  396. package/dist/web-admin-client/apply-effective.js +56 -5
  397. package/dist/web-admin-client/facade.d.ts +1 -1
  398. package/dist/web-admin-client/facade.js +1 -1
  399. package/dist/web-admin-client/read-face.js +5 -9
  400. package/dist/web-admin-client/skills-mcp.js +4 -5
  401. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  402. package/package.json +7 -3
@@ -10,6 +10,7 @@ import { LocalCheckpointStore } from "./local-checkpoint-store.js";
10
10
  import { FileResumeAnchorStore } from "./file-resume-anchor-store.js";
11
11
  import { type ApprovalExemptionStore } from "./approval-exemption-store.js";
12
12
  import { type ApprovalNonceStore } from "./approval-nonce-store.js";
13
+ import { type OrgDeliveryQuotaStore } from "./org-delivery-quota-store.js";
13
14
  import { type ApprovalAskStore as ApprovalAskStoreType } from "./approval-ask-store-sql.js";
14
15
  import { type MemoryOptOutGrantStore } from "./memory-optout-grant-store-sql.js";
15
16
  import { type SendFileLedger } from "./send-file-ledger.js";
@@ -59,6 +60,19 @@ export type ServiceSessionPolicyStore = SessionPolicyStore;
59
60
  * whole-tree `ServiceFileSnapshotStore` ([ref]: the boundary covers the TRACKED set only — files this
60
61
  * session edited; there is no whole-tree manifest anymore). Also the 2c history-transfer store
61
62
  * (exportHistory/importHistory + the blob negotiation faces below). */
63
+ /**
64
+ * The 2c `putBlob` answer: core's `FileHistoryResult` plus ONE arm — the SQL blob judge refused the blob on the connection that
65
+ * would have written it ({@link import("./blob-backend.js").BlobTooLargeError}, code `blob_too_large_for_sql`). `PUT /sync/blobs`
66
+ * answers that arm 413 (the store's sentence, plus the machine-readable `wallSource` = where the cap came from) and every other failure 502 (retryable).
67
+ */
68
+ export type SyncBlobPutResult = import("@sema-agent/core").FileHistoryResult | {
69
+ readonly ok: false;
70
+ readonly error: {
71
+ readonly code: import("./blob-backend.js").BlobTooLargeError["code"];
72
+ readonly message: string;
73
+ readonly wallSource: import("./blob-backend.js").SqlBlobCapReading["source"];
74
+ };
75
+ };
62
76
  export type ServiceFileHistoryStore = FileHistoryStore & {
63
77
  /** 2c sync blob-face marker — see SqlFileHistoryStore.syncBlobFaces (codex R2-high: name-probing
64
78
  * `putBlob` on an arbitrary store collides with the local core store's PRIVATE void helper). */
@@ -70,7 +84,7 @@ export type ServiceFileHistoryStore = FileHistoryStore & {
70
84
  * protected — never a synchronous external-store delete). Reaper-driven; SQL twins only. */
71
85
  sweepOrphanBlobs?(): Promise<number>;
72
86
  /** 2c blob negotiation: upload one content-addressed blob ahead of importHistory. SQL twins only. */
73
- putBlob?(hash: string, bytes: Uint8Array): Promise<import("@sema-agent/core").FileHistoryResult>;
87
+ putBlob?(hash: string, bytes: Uint8Array): Promise<SyncBlobPutResult>;
74
88
  /** 2c blob read face (scope-checked by the route against the session's history graph). SQL twins only. */
75
89
  getBlob?(hash: string): Promise<Uint8Array | undefined>;
76
90
  /** The subset of `hashes` already present — a cheap SQL INDEX probe (the import presence pre-check,
@@ -163,6 +177,11 @@ export interface StoreBackend {
163
177
  * `approvalExemption` 同姿势:tidb/pg = SQL 双方言(单类双语句),local = File 追加日志 + 压实。
164
178
  * **不能**退化成进程内易失形:一次重启若把记录抹掉,JWT TTL 窗内的重放就复活了,而那正是本店要关的洞。 */
165
179
  approvalNonce(): ApprovalNonceStore;
180
+ /** [ref] §10.2 —— 跨主体投递门的配额店(`org-delivery-quota-store.ts`:一次 take 在同一把锁下判并记对偶界与收件人
181
+ * 聚合界)。REQUIRED on all backends —— tidb/pg = SQL 双方言(单类双语句,窗按库钟),local = File 整份快照(本进程墙钟;
182
+ * 数据根锁保证一个进程)。门装配时才取(`PRINCIPAL_INBOX_ASSISTANT` 在场);**不能**退化成进程内易失形:多副本各数各的
183
+ * = 额度 × 副本数,一次重启清零 = 窗内额度复活。 */
184
+ orgDeliveryQuota(): OrgDeliveryQuotaStore;
166
185
  /** [ref]([ref] §3.0-§3.2)流内审批协议持久层:每个流内工具调用一行的 ask 状态机 + 批行。
167
186
  * REQUIRED **且持久** on all backends — tidb/pg = SQL 双方言 twin;local = {@link FileApprovalAskStore}。
168
187
  *
@@ -287,6 +306,11 @@ export interface StoreBackend {
287
306
  * 缺席**是一个真答案**:那里的索引家在 run 店同一间屋子里(`LocalWorkflowAgentSessionIndex`,文件账本
288
307
  * 或纯内存),不需要经过 backend。契约与单写者纪律的属主 = orchestration/workflow-agent-session-index.ts。 */
289
308
  workflowAgentSessionIndex?(): import("../orchestration/workflow-agent-session-index.js").WorkflowAgentSessionIndex;
309
+ /** workflow 子代停驻卡的耐久决定行(一张卡一行,键 = 子代 checkpoint 的 token),**绑在本后端的 {@link run} 那只 run 店上**(每一笔写都在它的会话认领栅栏里落)。
310
+ * 与 `run()` 同形:无参、恒交同一只(三孪生同),所以这只决定店绑的就是部署的 run 店。SQL 后端 = 跨副本表,读写走 run 店的池;`local` 后端 = 进程内,
311
+ * 账本位置由后端按自己的数据根与 `WORKFLOW_RUN_STORE` 定(`<数据根>/workflows/workflow-park-decisions/decisions.jsonl`;`memory` ⇒ 纯内存)。
312
+ * 契约与律的属主 = orchestration/workflow-park-decision.ts。 */
313
+ workflowParkDecisions?(): import("../orchestration/workflow-park-decision.js").WorkflowParkDecisionStore;
290
314
  /** Cloud-only stores below are OPTIONAL: the `local` (in-memory/file) backend omits them (it has no core
291
315
  * in-memory twin carrying the service extras, and these are fleet/multi-replica concepts), so a local HTTP
292
316
  * service degrades EXACTLY like today's no-DB env (the consumers gate on `backend?.X?.()`). TiDB/PG provide all. */
@@ -301,6 +325,17 @@ export interface StoreBackend {
301
325
  checkpoint?(logger?: {
302
326
  info?(msg: string, meta?: unknown): void;
303
327
  }): CheckpointStoreFull;
328
+ /**
329
+ * 待决 checkpoint 的**只读**读口(**必选**成员)—— 审批账本留存律(`approval-ask-retention.ts` 的挂靠集)读「还有哪些会话停驻着」就走这一口,不走 {@link checkpoint}。
330
+ * 区别只有一条:这一口**不牵动任何别的店**。local 车道的 `checkpoint()` 是 durable 停驻面的装配点 —— 它给 run 店接上 [ref] 的收割探针(停驻行的收割从 no-op 变生效),
331
+ * 那是开了 `DURABLE_APPROVAL` 的部署才该发生的事;留存腿在没开它的部署上同样要读(前世 / 别的副本留下的停驻不因这一世的开关消失,看不见就会把还能被决的停驻的问删掉),
332
+ * 所以读和接线必须分口。SQL 孪生本来无状态(接线靠 JOIN),两口同一只。
333
+ *
334
+ * 🔴 为什么必选而不是跟着 {@link checkpoint} 一起可选:留存腿读不到这一口的后果在**删除方向**(挂靠集里少了待决停驻 ⇒ 还能被决的停驻的问按龄被删),
335
+ * 「有 checkpoint 店却没交读口」若只是运行期的 `undefined`,就是一次静默少保护;必选 ⇒ 漏实现是**编译红**。没有 checkpoint 店的后端(`checkpoint` 缺席)交一只恒空的读口
336
+ * (`{ listPendingSessionIds: async () => [] }` —— 没有店 ⇒ 没有停驻,这是事实不是缺省)。
337
+ */
338
+ checkpointReadView(): Pick<CheckpointStoreFull, "listPendingSessionIds">;
304
339
  toolResult?(): ToolResultStoreFull;
305
340
  imageIndex?(): ImageIndex;
306
341
  imageBake?(): ImageBake;
@@ -7,8 +7,9 @@ import { FileWorkflowJournalStore } from "@sema-agent/core";
7
7
  import { fileSessionCaptureRecordStore } from "@sema-agent/core";
8
8
  import { TiDBOutcomeLedger, PgOutcomeLedger } from "./outcome-ledger-sql.js";
9
9
  import { FileOutcomeSink } from "./file-outcome-sink.js";
10
- import { TiDBWorkflowRunStore, TiDBWorkflowCompletionInbox, TiDBWorkflowNotifyJournalStore, TiDBWorkflowAgentSessionIndex, PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore, PgWorkflowAgentSessionIndex } from "./workflow-run-store-sql.js";
10
+ import { TiDBWorkflowRunStore, TiDBWorkflowCompletionInbox, TiDBWorkflowNotifyJournalStore, TiDBWorkflowAgentSessionIndex, SqlWorkflowParkDecisionStore, PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore, PgWorkflowAgentSessionIndex } from "./workflow-run-store-sql.js";
11
11
  import { FileRunStore } from "./file-run-store.js";
12
+ import { LocalWorkflowParkDecisionStore } from "../orchestration/workflow-park-decision.js";
12
13
  import { StoreBootRefusalError } from "./store-contracts.js";
13
14
  import { buildStoreOpenRefusalTail } from "./store-open-refusal.js";
14
15
  import { acquireLocalBackendWithWait } from "./store-lock-wait.js";
@@ -19,6 +20,7 @@ import { LocalCheckpointStore } from "./local-checkpoint-store.js";
19
20
  import { FileResumeAnchorStore } from "./file-resume-anchor-store.js";
20
21
  import { TiDBApprovalExemptionStore, PgApprovalExemptionStore, FileApprovalExemptionStore } from "./approval-exemption-store.js";
21
22
  import { TiDBApprovalNonceStore, PgApprovalNonceStore, FileApprovalNonceStore } from "./approval-nonce-store.js";
23
+ import { TiDBOrgDeliveryQuotaStore, PgOrgDeliveryQuotaStore, FileOrgDeliveryQuotaStore } from "./org-delivery-quota-store.js";
22
24
  import { TiDBApprovalAskStore, PgApprovalAskStore } from "./approval-ask-store-sql.js";
23
25
  import { FileApprovalAskStore } from "./approval-ask-store-file.js";
24
26
  import { TiDBMemoryOptOutGrantStore, PgMemoryOptOutGrantStore } from "./memory-optout-grant-store-sql.js";
@@ -61,7 +63,7 @@ import { openWithinWait } from "./store-open-wait.js";
61
63
  function historyBlobBackend(config, dialect, pool) {
62
64
  const s = config.snapshotBlobStore;
63
65
  if (!s)
64
- return new SqlBlobBackend(dialect, pool, config.snapshotBlobSqlMaxBytes, FILE_HISTORY_BLOB_TABLE);
66
+ return new SqlBlobBackend(dialect, pool, config.snapshotBlobSqlMaxBytes, FILE_HISTORY_BLOB_TABLE, createLogger(config.logLevel));
65
67
  return new MinioBlobBackend({
66
68
  endpoint: s.endpoint,
67
69
  bucket: s.bucket,
@@ -75,7 +77,7 @@ function historyBlobBackend(config, dialect, pool) {
75
77
  function legacyBlobBackend(config, dialect, pool) {
76
78
  const s = config.snapshotBlobStore;
77
79
  if (!s)
78
- return new SqlBlobBackend(dialect, pool, config.snapshotBlobSqlMaxBytes);
80
+ return new SqlBlobBackend(dialect, pool, config.snapshotBlobSqlMaxBytes, undefined, createLogger(config.logLevel));
79
81
  return new MinioBlobBackend({
80
82
  endpoint: s.endpoint,
81
83
  bucket: s.bucket,
@@ -121,10 +123,12 @@ class TiDBBackend {
121
123
  }
122
124
  ensureSchema() { return ensureTidbSchema(this.pool); }
123
125
  close() { return this.pool.end(); }
124
- run() { return new TiDBRunStore(this.pool); }
126
+ run() { return (this.runStoreInst ??= new TiDBRunStore(this.pool)); }
127
+ runStoreInst;
125
128
  resumeAnchor() { return new TiDBResumeAnchorStore(this.pool); }
126
129
  approvalExemption() { return new TiDBApprovalExemptionStore(this.pool); }
127
130
  approvalNonce() { return new TiDBApprovalNonceStore(this.pool); }
131
+ orgDeliveryQuota() { return new TiDBOrgDeliveryQuotaStore(this.pool); }
128
132
  approvalAsk() { return new TiDBApprovalAskStore(this.pool); }
129
133
  permissionRule() { return createSqlPermissionRuleStores(mysqlDriver(this.pool)); }
130
134
  sendFileLedger() { return new TiDBSendFileLedger(this.pool); }
@@ -142,8 +146,11 @@ class TiDBBackend {
142
146
  completionInbox(onWarn) { return new TiDBWorkflowCompletionInbox(this.pool, onWarn); }
143
147
  notifyJournal() { return new TiDBWorkflowNotifyJournalStore(this.pool); }
144
148
  workflowAgentSessionIndex() { return new TiDBWorkflowAgentSessionIndex(this.pool); }
149
+ workflowParkDecisions() { return (this.parkDecisionsInst ??= new SqlWorkflowParkDecisionStore(this.run())); }
150
+ parkDecisionsInst;
145
151
  sharedMemoryStore(authorizer) { return new TiDBSharedMemoryStore(this.pool, authorizer); }
146
152
  checkpoint(logger) { return new TiDBCheckpointStore(this.pool, logger); }
153
+ checkpointReadView() { return this.checkpoint(); }
147
154
  toolResult() { return new TiDBToolResultStore(this.pool); }
148
155
  imageIndex() { return new TiDBImageIndex(this.pool); }
149
156
  imageBake() { return new TiDBImageBake(this.pool); }
@@ -154,7 +161,7 @@ class TiDBBackend {
154
161
  breaker(onWriteFail) { return new TiDBBreakerState(this.pool, onWriteFail); }
155
162
  costQuota(limitMicroUsd, windowMs, onDegraded) { return new TiDBCostQuota(this.pool, limitMicroUsd, windowMs, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
156
163
  rateLimiter(limit, onDegraded) { return new TiDBRateLimiter(this.pool, limit, undefined, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
157
- session() { return new TiDBSessionStore(this.pool); }
164
+ session() { return new TiDBSessionStore(this.pool, { log: createLogger(this.config.logLevel) }); }
158
165
  adoptionLog() { return new TiDBAdoptionLogStore(this.pool); }
159
166
  mysqlPool() { return this.pool; }
160
167
  pgPool() { return undefined; }
@@ -170,10 +177,12 @@ class PgBackend {
170
177
  }
171
178
  ensureSchema() { return ensurePgSchema(this.pool); }
172
179
  close() { return this.pool.end(); }
173
- run() { return new PgRunStore(this.pool); }
180
+ run() { return (this.runStoreInst ??= new PgRunStore(this.pool)); }
181
+ runStoreInst;
174
182
  resumeAnchor() { return new PgResumeAnchorStore(this.pool); }
175
183
  approvalExemption() { return new PgApprovalExemptionStore(this.pool); }
176
184
  approvalNonce() { return new PgApprovalNonceStore(this.pool); }
185
+ orgDeliveryQuota() { return new PgOrgDeliveryQuotaStore(this.pool); }
177
186
  approvalAsk() { return new PgApprovalAskStore(this.pool); }
178
187
  permissionRule() { return createSqlPermissionRuleStores(pgDriver(this.pool)); }
179
188
  sendFileLedger() { return new PgSendFileLedger(this.pool); }
@@ -191,8 +200,11 @@ class PgBackend {
191
200
  completionInbox(onWarn) { return new PgWorkflowCompletionInbox(this.pool, onWarn); }
192
201
  notifyJournal() { return new PgWorkflowNotifyJournalStore(this.pool); }
193
202
  workflowAgentSessionIndex() { return new PgWorkflowAgentSessionIndex(this.pool); }
203
+ workflowParkDecisions() { return (this.parkDecisionsInst ??= new SqlWorkflowParkDecisionStore(this.run())); }
204
+ parkDecisionsInst;
194
205
  sharedMemoryStore(authorizer) { return new PgSharedMemoryStore(this.pool, authorizer); }
195
206
  checkpoint(logger) { return new PgCheckpointStore(this.pool, logger); }
207
+ checkpointReadView() { return this.checkpoint(); }
196
208
  toolResult() { return new PgToolResultStore(this.pool); }
197
209
  imageIndex() { return new PgImageIndex(this.pool); }
198
210
  imageBake() { return new PgImageBake(this.pool); }
@@ -203,7 +215,7 @@ class PgBackend {
203
215
  breaker(onWriteFail) { return new PgBreakerState(this.pool, onWriteFail); }
204
216
  costQuota(limitMicroUsd, windowMs, onDegraded) { return new PgCostQuota(this.pool, limitMicroUsd, windowMs, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
205
217
  rateLimiter(limit, onDegraded) { return new PgRateLimiter(this.pool, limit, undefined, undefined, onDegraded, this.config.dbQueryTimeoutMs); }
206
- session() { return new PgSessionStore(this.pool); }
218
+ session() { return new PgSessionStore(this.pool, { log: createLogger(this.config.logLevel) }); }
207
219
  adoptionLog() { return new PgAdoptionLogStore(this.pool); }
208
220
  mysqlPool() { return undefined; }
209
221
  pgPool() { return this.pool; }
@@ -217,6 +229,7 @@ class LocalBackend {
217
229
  resumeAnchorStore;
218
230
  approvalExemptionStore;
219
231
  approvalNonceStore;
232
+ orgDeliveryQuotaStore;
220
233
  approvalAskStore;
221
234
  sendFileLedgerStore;
222
235
  userInputLedgerStore;
@@ -225,6 +238,7 @@ class LocalBackend {
225
238
  onWarn;
226
239
  onError;
227
240
  discloseWarn;
241
+ parkDecisionLedgerRoot;
228
242
  constructor(root, config, onWarn, onError) {
229
243
  this.onWarn = onWarn;
230
244
  this.discloseWarn = onWarn ?? ((msg, meta) => console.warn(msg, meta));
@@ -249,9 +263,11 @@ class LocalBackend {
249
263
  strictHydrate: config.runStoreStrictHydrate,
250
264
  });
251
265
  this.sessionStore = new LocalSessionStore(createLocalSessionRepo(this.fileBackend.root), this.runStore, this.fileBackend.root, { log: createLogger(config.logLevel) });
266
+ this.parkDecisionLedgerRoot = config.workflowRunStoreBackend === "memory" ? undefined : join(this.fileBackend.root, "workflows");
252
267
  this.resumeAnchorStore = new FileResumeAnchorStore(this.fileBackend.root);
253
268
  this.approvalExemptionStore = new FileApprovalExemptionStore(this.fileBackend.root, { warn: corruptReadWarn });
254
269
  this.approvalNonceStore = new FileApprovalNonceStore(this.fileBackend.root, { warn: corruptReadWarn });
270
+ this.orgDeliveryQuotaStore = new FileOrgDeliveryQuotaStore(this.fileBackend.root, { warn: corruptReadWarn });
255
271
  this.approvalAskStore = new FileApprovalAskStore(this.fileBackend.root);
256
272
  this.sendFileLedgerStore = new FileSendFileLedger(this.fileBackend.root);
257
273
  this.userInputLedgerStore = new FileUserInputLedgerStore(this.fileBackend.root);
@@ -284,9 +300,14 @@ class LocalBackend {
284
300
  await this.fileBackend.dispose();
285
301
  }
286
302
  run() { return this.runStore; }
303
+ workflowParkDecisions() {
304
+ return (this.parkDecisionsInst ??= new LocalWorkflowParkDecisionStore(this.runStore, this.parkDecisionLedgerRoot));
305
+ }
306
+ parkDecisionsInst;
287
307
  resumeAnchor() { return this.resumeAnchorStore; }
288
308
  approvalExemption() { return this.approvalExemptionStore; }
289
309
  approvalNonce() { return this.approvalNonceStore; }
310
+ orgDeliveryQuota() { return this.orgDeliveryQuotaStore; }
290
311
  approvalAsk() { return this.approvalAskStore; }
291
312
  permissionRule() {
292
313
  if (!this.permissionRuleStoresInst) {
@@ -300,20 +321,25 @@ class LocalBackend {
300
321
  permissionRuleStoresInst;
301
322
  sendFileLedger() { return this.sendFileLedgerStore; }
302
323
  userInputLedger() { return this.userInputLedgerStore; }
324
+ checkpointStoreOf() {
325
+ return (this.checkpointStoreInst ??= new LocalCheckpointStore(this.fileBackend.root, {
326
+ getActiveTaskId: (sessionId) => this.runStore.getActiveTaskId(sessionId),
327
+ ownerOf: (sessionId) => this.sessionStore.ownerOf(sessionId),
328
+ }));
329
+ }
303
330
  checkpoint() {
304
- if (!this.checkpointStoreInst) {
305
- const cs = new LocalCheckpointStore(this.fileBackend.root, {
306
- getActiveTaskId: (sessionId) => this.runStore.getActiveTaskId(sessionId),
307
- ownerOf: (sessionId) => this.sessionStore.ownerOf(sessionId),
308
- });
309
- this.checkpointStoreInst = cs;
331
+ const cs = this.checkpointStoreOf();
332
+ if (!this.checkpointProbeWired) {
333
+ this.checkpointProbeWired = true;
310
334
  this.runStore.setCheckpointProbe({
311
335
  hasPending: async (sessionId) => (await cs.findPendingTokenBySession(sessionId)) !== null,
312
336
  hasExpired: (sessionId) => cs.hasExpiredBySession(sessionId),
313
337
  });
314
338
  }
315
- return this.checkpointStoreInst;
339
+ return cs;
316
340
  }
341
+ checkpointReadView() { return this.checkpointStoreOf(); }
342
+ checkpointProbeWired = false;
317
343
  checkpointStoreInst;
318
344
  sessionPolicy() { return this.fileBackend.sessionPolicyStore; }
319
345
  fileUsageWindowStore() { return this.fileBackend.usageWindowStore; }
@@ -183,6 +183,22 @@ export declare function readLegacyHolderDeathCode(row: {
183
183
  * 正常失败(别的码 / 无码)/ park 过期收割(`approval.expired`:腿 park 过)都**不是**死亡判决。
184
184
  */
185
185
  export declare function isHolderDeathVerdict(run: Pick<RunRecord, "status" | "errorCode">): boolean;
186
+ /**
187
+ * `listRuns` 的查询(三只 run 店同一份形)。过滤都是精确匹配(`""` 是合法的精确值,不是「不滤」—— B10)。
188
+ * `owner`:串 = 恰这一个主体的 run;`null` = 属主为 null 的 run(不带主体提交的任务:匿名 / 单用户 —— 审批读面的公共 scope `_` 由调用方译成它,店里不认 `_`);
189
+ * 缺席 = 不按属主过滤。SQL 两方言 `null` ⇒ `owner IS NULL`(`owner = NULL` 恒不为真)。
190
+ */
191
+ export interface RunListQuery {
192
+ status?: string;
193
+ jobId?: string;
194
+ source?: string;
195
+ owner?: string | null;
196
+ cursor?: {
197
+ createdAt: string;
198
+ taskId: string;
199
+ };
200
+ limit: number;
201
+ }
186
202
  export interface RunRecord {
187
203
  taskId: string;
188
204
  sessionId: string;
@@ -272,6 +288,32 @@ export type CreateRunOutcome = {
272
288
  existing?: undefined;
273
289
  activeTaskId: string;
274
290
  };
291
+ /** SQL 认领栅栏的结局:`held: false` = 认领此刻不是这条 run 的(或它已不在跑),`write` 一次都没调。 */
292
+ export type ClaimFenced<T> = {
293
+ readonly held: true;
294
+ readonly value: T;
295
+ } | {
296
+ readonly held: false;
297
+ };
298
+ /**
299
+ * 进程内栅栏 `write` 交回的**落定记号**。`write` 的型是 `() => FenceLanded`:只有**同步**交回这只记号的回调编得过 —— async 回调交回的是
300
+ * `Promise<FenceLanded>`(把真正的写挪到栅栏判完、放开之后的别的微任务里,「判认领与落行同一拍」就不成立了),不是它;栅栏方法没有类型参数,
301
+ * 显式写宽(`<unknown>` / `<void>` / `<object>`)无处可写,回调把返回标宽也编不过。要带出值,用闭包。
302
+ */
303
+ export declare const FENCE_LANDED: unique symbol;
304
+ export type FenceLanded = typeof FENCE_LANDED;
305
+ /**
306
+ * **宿主会话的认领当写栅栏用 —— 进程内那一形**(属主 = run 店;Memory / File 两孪生同律)。认领 = 会话 → 持有它的 taskId,
307
+ * 由 {@link CreateRunOutcome} 的建行(或续跑腿的 markResuming)取得、终局 / 收割放掉 —— 「这次受理还持有会话吗」只问它,不另记身份。
308
+ *
309
+ * `whileHoldingClaim(sessionId, taskId, write)`:**只有** `taskId` 此刻持有 `sessionId` 的认领、且这条 run 是活的(`running`)时才调 `write`、答 `true`,
310
+ * 同一拍把这条 run 的活性戳刷新(一次栅栏写也是一次心跳);否则一次都不调、答 `false`。整只是**同步**的 —— `write` 也是:判、刷新、`write` 落定是同一个同步段,
311
+ * 中间没有让出,所以认领在 `write` 落定之前挪不动(这一条由类型担保 —— `write` 必须同步交回 {@link FENCE_LANDED},不靠「这里恰好没有 await」)。
312
+ * SQL 孪生的栅栏是一个事务(`run-store-sql.ts` `SqlRunStore.whileHoldingClaim`,`write` 收那只事务连接,结局 {@link ClaimFenced}),不是本型。
313
+ */
314
+ export interface InProcessClaimFence {
315
+ whileHoldingClaim(sessionId: string, taskId: string, write: () => FenceLanded): boolean;
316
+ }
275
317
  /**
276
318
  * `RunRecord["status"]`(= `"running" | TaskStatus`)的**唯一分类表** —— 词表的属主 = 判据的属主,
277
319
  * 与类型定义同住一个文件。四个类:
@@ -20,6 +20,7 @@ export function readLegacyHolderDeathCode(row) {
20
20
  export function isHolderDeathVerdict(run) {
21
21
  return run.status === "failed" && run.errorCode !== null && RUN_HOLDER_DEATH_CODE_WORDS.has(run.errorCode);
22
22
  }
23
+ export const FENCE_LANDED = Symbol("in-process-claim-fence.landed");
23
24
  export const RUN_STATUS_CLASS = {
24
25
  running: "live",
25
26
  completed: "succeeded",
@@ -23,7 +23,12 @@ export declare function tidbPoolOptions(tidb: NonNullable<ServiceConfig["tidb"]>
23
23
  * · `lib/base/pool.js` / `lib/promise/pool.js` —— 池层与 promise 包装层都**不**把连接 error 再
24
24
  * emit 到池对象上(池层只 emit acquire/connection/enqueue/release)。
25
25
  * ⇒ 空闲连接被 KILL / 故障切换杀掉 = 库内吞并淘汰,进程不死、池自愈。真 TiDB KILL 钉在
26
- * `test/pool-idle-error-db-integration.test.ts` 第③格。升 mysql2 大版时按上面三坐标复核。 */
26
+ * `test/pool-idle-error-db-integration.test.ts` 第③格。升 mysql2 大版时按上面三坐标复核。
27
+ *
28
+ * **另一种病不在上面三坐标里 —— 库回完一个错误包随后才关连接**(1153 语句超过 `max_allowed_packet`:库读完包头就拒、回错、关连接):
29
+ * mysql2 的 `pool.query` 只看见「这条语句完了」,连接照常归还,库的 FIN / RST 晚一拍才到,紧接着的下一笔借到这条半死的连接、答 `write ECONNRESET`
30
+ * (`lib/base/pool.js` 的 `query` 只对只读节点三个错误号销毁连接)。所以交出去的池是 {@link createCloseAwarePool} 包过的:池上的裸语句改为每条租一条连接,
31
+ * 收到 `isConnectionUnusableError` 一类的错先销毁再抛(借出给店的连接走同一只守卫,`sql-driver.ts` 的 `leaseOf`)。 */
27
32
  export declare function createTidbPool(config: ServiceConfig): Pool;
28
33
  /**
29
34
  * Idempotent schema. `session_event` is the append-only L1 event log (positional slicing by
@@ -9,6 +9,7 @@ import { TIDB_RETENTION_STATEMENTS } from "./retention-store-sql.js";
9
9
  import { SESSION_META_INCARNATION_COLUMN } from "../session-incarnation.js";
10
10
  import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
11
11
  import { SESSION_TITLE_MAX_CHARS } from "../session-row.js";
12
+ import { PRINCIPAL_MAX_UTF8_BYTES } from "../security.js";
12
13
  import { ensureIndexes } from "./ensure-index.js";
13
14
  import { CENTRAL_SCHEMA_INDEXES } from "./schema-indexes.js";
14
15
  import { SESSION_INDEXES } from "./pg-session-storage.js";
@@ -24,6 +25,7 @@ import { PERMISSION_RULE_INDEXES } from "./permission-rule-store-sql.js";
24
25
  import { RETENTION_INDEXES } from "./retention-store-sql.js";
25
26
  import { LEADER_RUN_INDEXES } from "./leader-run-store-sql.js";
26
27
  import { pollUntilLocked } from "./ensure-schema-lock-policy.js";
28
+ import { createCloseAwarePool } from "./sql-driver.js";
27
29
  export function tidbPoolOptions(tidb) {
28
30
  const { host, port, user, password, database, connectionLimit } = tidb;
29
31
  const limit = connectionLimit ?? 10;
@@ -48,7 +50,7 @@ export function createTidbPool(config) {
48
50
  throw new Error("TiDB config missing. Set MYSQL_HOST / MYSQL_USER / MYSQL_DATABASE (and MYSQL_PASSWORD/PORT) " +
49
51
  "when SESSION_BACKEND=mysql.");
50
52
  }
51
- return mysql.createPool(tidbPoolOptions(config.tidb));
53
+ return createCloseAwarePool(mysql.createPool(tidbPoolOptions(config.tidb)));
52
54
  }
53
55
  export const SCHEMA_STATEMENTS = [
54
56
  `CREATE TABLE IF NOT EXISTS session_meta (
@@ -193,7 +195,7 @@ export const SCHEMA_STATEMENTS = [
193
195
  -- ever served an operator's ad-hoc WHERE error_code LIKE 'budget.%', while every task_run write paid its
194
196
  -- maintenance cost. If you need that ad-hoc query, build the index temporarily and drop it after.
195
197
  ) COLLATE utf8mb4_bin`,
196
- `CREATE TABLE IF NOT EXISTS circuit_breaker (
198
+ `CREATE TABLE IF NOT EXISTS breaker_state (
197
199
  breaker_key VARCHAR(190) NOT NULL,
198
200
  phase VARCHAR(16) NOT NULL,
199
201
  failures INT NOT NULL DEFAULT 0,
@@ -373,6 +375,25 @@ export const SCHEMA_STATEMENTS = [
373
375
  expires_at_ms BIGINT NOT NULL,
374
376
  PRIMARY KEY (session_id, nonce),
375
377
  KEY idx_approval_nonce_expires (expires_at_ms)
378
+ ) COLLATE utf8mb4_bin`,
379
+ `CREATE TABLE IF NOT EXISTS org_delivery_sender_quota (
380
+ from_scope VARBINARY(${PRINCIPAL_MAX_UTF8_BYTES}) NOT NULL,
381
+ window_start_ms BIGINT NOT NULL,
382
+ attempts INT NOT NULL,
383
+ PRIMARY KEY (from_scope)
384
+ ) COLLATE utf8mb4_bin`,
385
+ `CREATE TABLE IF NOT EXISTS org_delivery_recipient_quota (
386
+ to_scope VARBINARY(${PRINCIPAL_MAX_UTF8_BYTES}) NOT NULL,
387
+ window_start_ms BIGINT NOT NULL,
388
+ delivered INT NOT NULL,
389
+ PRIMARY KEY (to_scope)
390
+ ) COLLATE utf8mb4_bin`,
391
+ `CREATE TABLE IF NOT EXISTS org_delivery_pair_quota (
392
+ to_scope VARBINARY(${PRINCIPAL_MAX_UTF8_BYTES}) NOT NULL,
393
+ from_scope VARBINARY(${PRINCIPAL_MAX_UTF8_BYTES}) NOT NULL,
394
+ window_start_ms BIGINT NOT NULL,
395
+ delivered INT NOT NULL,
396
+ PRIMARY KEY (to_scope, from_scope)
376
397
  ) COLLATE utf8mb4_bin`,
377
398
  `CREATE TABLE IF NOT EXISTS user_input_acceptance (
378
399
  accept_id VARCHAR(64) NOT NULL,
@@ -517,18 +538,19 @@ export const SCHEMA_STATEMENTS = [
517
538
  ) COLLATE utf8mb4_bin`,
518
539
  `CREATE TABLE IF NOT EXISTS workflow_journal (
519
540
  run_id VARCHAR(191) NOT NULL,
541
+ incarnation VARCHAR(64) NOT NULL,
520
542
  ordinal INT NOT NULL,
521
- -- scope (SVC-2 / CORE-9 audit BLOCKER): the table predates scope — it was added when the
522
- -- WorkflowJournalStore seam grew a scope param for cross-tenant resume isolation. Every new append writes the
523
- -- run's REAL scope. EXISTING (pre-migration) rows carry '' = CROSS-SCOPE ORPHANS, harmless by construction: a
524
- -- real resume filters WHERE scope = <caller>, so the blank-scope residue never matches a tenant. The
525
- -- NOT NULL DEFAULT '' is what let the original ALTER succeed on a table that already had rows — keep the
526
- -- default so the "'' = orphan, never a tenant" reading stays true.
527
- scope VARCHAR(190) NOT NULL DEFAULT '',
528
543
  call_key VARCHAR(255) NOT NULL,
529
544
  result MEDIUMTEXT NOT NULL,
530
545
  created_at_ms BIGINT NOT NULL,
531
- PRIMARY KEY (run_id, ordinal)
546
+ PRIMARY KEY (run_id, incarnation, ordinal)
547
+ ) COLLATE utf8mb4_bin`,
548
+ `CREATE TABLE IF NOT EXISTS workflow_journal_owner (
549
+ run_id VARCHAR(191) NOT NULL,
550
+ scope VARCHAR(190) NOT NULL,
551
+ incarnation VARCHAR(64) NOT NULL,
552
+ appended_at_ms BIGINT NOT NULL,
553
+ PRIMARY KEY (run_id)
532
554
  ) COLLATE utf8mb4_bin`,
533
555
  `CREATE TABLE IF NOT EXISTS workflow_resume_claim (
534
556
  source_run_id VARCHAR(191) NOT NULL,
@@ -556,6 +578,18 @@ export const SCHEMA_STATEMENTS = [
556
578
  scope VARCHAR(190) NOT NULL,
557
579
  PRIMARY KEY (session_id, run_id),
558
580
  KEY idx_wfagentsess_run (run_id)
581
+ ) COLLATE utf8mb4_bin`,
582
+ `CREATE TABLE IF NOT EXISTS workflow_park_decision (
583
+ token VARCHAR(120) NOT NULL,
584
+ run_id VARCHAR(191) NOT NULL,
585
+ host_session_id VARCHAR(190) NOT NULL,
586
+ outcome MEDIUMTEXT NOT NULL,
587
+ fingerprint VARCHAR(64) NOT NULL,
588
+ delivered_task_id VARCHAR(191) NOT NULL,
589
+ accepted_at_ms BIGINT NOT NULL,
590
+ PRIMARY KEY (token),
591
+ KEY idx_wfparkdec_host (host_session_id),
592
+ KEY idx_wfparkdec_run (run_id)
559
593
  ) COLLATE utf8mb4_bin`,
560
594
  `CREATE TABLE IF NOT EXISTS workflow_completion_inbox (
561
595
  seq BIGINT NOT NULL AUTO_INCREMENT,
@@ -27,8 +27,9 @@ export declare class TiDBSessionStorage extends BaseSessionStorage {
27
27
  * [ref] S3 [ref] pull seam — `SessionStorage.getEpochAnchor?()`: the nearest prompt-epoch carrier BELOW the
28
28
  * bounded-wake floor, AS STORED (engine 7.52.0: `Promise<unknown>`; the engine reads the record, a retired shape
29
29
  * included). The engine's `Session.getPromptEpoch()` asks for it only when the in-window branch walk finds no carrier
30
- * (a rewind/resumeAt cut inside the kept tail; compactions without a restatement). The one reading of both SQL twins
31
- * is {@link scanEpochAnchor}; this backend supplies its page query (keyset-paged to exhaustion).
30
+ * (a rewind/resumeAt cut inside the kept tail; compactions without a restatement). The one reading of every windowed
31
+ * storage (both SQL twins, the local leg's view window) is {@link scanEpochAnchor}; this backend supplies its page query
32
+ * (keyset-paged to exhaustion) and decodes its own rows.
32
33
  */
33
34
  getEpochAnchor(): Promise<unknown>;
34
35
  /**
@@ -24,10 +24,10 @@ export class TiDBSessionStorage extends BaseSessionStorage {
24
24
  this.floorSeq = floorSeq;
25
25
  }
26
26
  async getEpochAnchor() {
27
- return scanEpochAnchor(this.sessionId, this.floorSeq, async (beforeSeq) => {
27
+ return scanEpochAnchor(this.floorSeq, async (beforeSeq) => {
28
28
  const [rows] = await this.pool.query(SESSION_EVENT_LATEST_BY_TYPE_SQL.epochAnchor, [this.sessionId, beforeSeq]);
29
29
  return rows.map((r) => ({ seq: r.seq, payload: r.payload }));
30
- });
30
+ }, (row) => decodeSessionEventPayload(row.payload, this.sessionId, row.seq));
31
31
  }
32
32
  static async wake(pool, sessionId) {
33
33
  const [metaRows] = await pool.query(`SELECT created_at, leaf_id, leaf_seq, incarnation, ${PLACEMENT_SELECT_COLUMNS} FROM session_meta WHERE session_id = ?`, [sessionId]);
@@ -10,12 +10,13 @@
10
10
  * Persistence only. **Tenant authorization (who may wake which session) lives in the service layer**
11
11
  * (`src/security.ts`), which uses `ownerOf` / `register` below. The store does not infer identity.
12
12
  */
13
- import { type AcquiredSession, type PlacedSessionRow, type SessionPlacement, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry } from "@sema-agent/core";
13
+ import { type AcquiredSession, type PlacedSessionRow, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry } from "@sema-agent/core";
14
14
  import type { Pool } from "mysql2/promise";
15
15
  import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
16
16
  import { type SessionFace } from "../session-incarnation.js";
17
17
  import type { SessionSummary } from "./store-contracts.js";
18
18
  import type { SessionRowPatch } from "../session-row.js";
19
+ import { type OrphanOwnerLog } from "../delegated-session-owner.js";
19
20
  import { type PlacementAcquireOpts } from "./session-placement.js";
20
21
  import { type StagingHandle } from "../session-sync-kernel.js";
21
22
  export declare class TiDBSessionStore implements SessionStore {
@@ -33,14 +34,33 @@ export declare class TiDBSessionStore implements SessionStore {
33
34
  };
34
35
  /** In-flight acquisitions keyed by id, so concurrent acquire(sameId) in one process share one. */
35
36
  private readonly pending;
36
- constructor(pool: Pool);
37
+ /** 委派子代孤行那一行 warn 的去处(`delegated-session-owner.ts`;装配给部署的 logger,缺席 ⇒ 缺省 logger,不静默)。 */
38
+ private readonly log;
39
+ constructor(pool: Pool, opts?: {
40
+ readonly log?: OrphanOwnerLog;
41
+ });
37
42
  acquire(sessionId?: string, opts?: PlacementAcquireOpts): Promise<AcquiredSession>;
38
43
  private load;
39
- /** Idempotently create a session_meta row with an owner. Existing owner is never overwritten.
44
+ /** Idempotently create a session_meta row with an owner (core `SessionStore.register`). Existing owner is never overwritten. */
45
+ register(sessionId: string, owner: string | null): Promise<void>;
46
+ /**
47
+ * acquire 的建行(唯一一处):普通会话 ⇒ 无主(按 id 首建的既有读法);placed 会话 ⇒ 属主按委派继承律在**这一笔**里写入
48
+ * (S-1770:根会话的属主,根行不在取父,都不在 ⇒ 孤行哨兵 + warn;属主 = 判断时见证到的,读来源 → 判 → INSERT —— 读法与顺序只住在
49
+ * `delegated-session-owner.ts` 的 `createPlacedSessionRow`,本店只交既有读写口,PG 孪生同调)。
50
+ */
51
+ private createOnAcquire;
52
+ /**
53
+ * S-1770 委派继承律的**认领口**:这只会话的那一位住客(判断时读到的化身)仍是无主的 placed 行 ⇒ 写 `owner`,返回是否写成
54
+ * (句 = `CLAIM_OWNERLESS_PLACED_SQL`,只 CAS 子行自己,与停驻挂点 / M23 同一只;规则在 `delegated-session-owner.ts`)。普通会话行不在射程(placed 判别位)。
55
+ */
56
+ claimOwnerless(sessionId: string, incarnation: string, owner: string): Promise<boolean>;
57
+ /** 若干来源行的会话面(属主 + 化身)一次读回(委派继承律的来源读;本店没有的 id 不在表里;化身经与 {@link sessionFaceOf} 同一只解码,空 ⇒ 响亮拒)。 */
58
+ private sourceFaces;
59
+ /** The one session_meta INSERT. Existing owner is never overwritten.
40
60
  * [ref]:`placement` 在场时与行同一条 INSERT 落六列;ON DUPLICATE 臂是 no-op ⇒ 已存在的行的元组
41
61
  * **永不被重写**(first-write 不可变,义务 5 的写侧半场)。
42
62
  * S-790:化身与属主同一条 first-write 律 —— 新行铸一只(`mintSessionIncarnation`),已存在的行 no-op 臂一个字节不动。 */
43
- register(sessionId: string, owner: string | null, placement?: SessionPlacement): Promise<void>;
63
+ private insertMeta;
44
64
  /**
45
65
  * [ref] 义务 6 的廉价探针 —— 一行 PK SELECT:`undefined` = 普通会话或无此行。
46
66
  * (release 的冷缓存腿、包装店的暖命中准入判、诊断面共用这一只。)
@@ -7,6 +7,8 @@ import { BASELINE_IO_DEADLINE_MS, decodeInstructionSource, encodeInstructionSour
7
7
  import { MANAGED_RETENTION } from "./retention-store-sql.js";
8
8
  import { carriedIncarnation, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
9
9
  import { contentForkRelation, fastForwardSharedContentDiverged } from "../session-sync-content.js";
10
+ import { CLAIM_OWNERLESS_PLACED_SQL, claimOwnerlessParams, createPlacedSessionRow } from "../delegated-session-owner.js";
11
+ import { createLogger } from "../observability/logger.js";
10
12
  import { assertPlacementAdmission, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues, SQL_SESSION_PLACEMENTS, } from "./session-placement.js";
11
13
  import { classifySyncRelationshipByIds, SyncConflictError, stagingIdFor, STAGING_ID_MARKER, STAGING_GC_GRACE_MS, } from "../session-sync-kernel.js";
12
14
  export class TiDBSessionStore {
@@ -14,13 +16,15 @@ export class TiDBSessionStore {
14
16
  retention = MANAGED_RETENTION;
15
17
  placements = SQL_SESSION_PLACEMENTS;
16
18
  pending = new Map();
17
- constructor(pool) {
19
+ log;
20
+ constructor(pool, opts = {}) {
18
21
  this.pool = pool;
22
+ this.log = opts.log ?? createLogger();
19
23
  }
20
24
  async acquire(sessionId, opts) {
21
25
  if (!sessionId) {
22
26
  const id = uuidv7();
23
- await this.register(id, null, opts?.placement);
27
+ await this.createOnAcquire(id, opts?.placement);
24
28
  return this.load(id, false, opts);
25
29
  }
26
30
  if (opts?.requireExisting)
@@ -43,7 +47,7 @@ export class TiDBSessionStore {
43
47
  }
44
48
  if (requireExisting)
45
49
  throw new SessionError("not_found", `session ${sessionId} not found`);
46
- await this.register(sessionId, null, opts?.placement);
50
+ await this.createOnAcquire(sessionId, opts?.placement);
47
51
  storage = await TiDBSessionStorage.wake(this.pool, sessionId);
48
52
  if (!storage) {
49
53
  throw new SessionError("storage", `session ${sessionId} vanished between register and wake (a concurrent purge won the race) — retry`);
@@ -51,7 +55,27 @@ export class TiDBSessionStore {
51
55
  assertPlacementAdmission(sessionId, (await storage.getMetadata()).placement, opts);
52
56
  return { session: new StoredSession(storage), sessionId };
53
57
  }
54
- async register(sessionId, owner, placement) {
58
+ async register(sessionId, owner) {
59
+ await this.insertMeta(sessionId, owner, undefined);
60
+ }
61
+ async createOnAcquire(sessionId, placement) {
62
+ if (placement === undefined)
63
+ return this.insertMeta(sessionId, null, undefined);
64
+ await createPlacedSessionRow(sessionId, placement, {
65
+ readFaces: (ids) => this.sourceFaces(ids),
66
+ insert: (owner) => this.insertMeta(sessionId, owner, placement),
67
+ readOwner: () => this.ownerOf(sessionId),
68
+ }, this.log);
69
+ }
70
+ async claimOwnerless(sessionId, incarnation, owner) {
71
+ const [res] = await this.pool.query(CLAIM_OWNERLESS_PLACED_SQL.tidb, [...claimOwnerlessParams(sessionId, incarnation, owner)]);
72
+ return res.affectedRows > 0;
73
+ }
74
+ async sourceFaces(ids) {
75
+ const [rows] = await this.pool.query(`SELECT session_id, owner, incarnation FROM session_meta WHERE session_id IN (${ids.map(() => "?").join(", ")})`, [...ids]);
76
+ return new Map(rows.map((r) => [String(r.session_id), sessionFaceFromRow(String(r.session_id), r.owner ?? null, r.incarnation)]));
77
+ }
78
+ async insertMeta(sessionId, owner, placement) {
55
79
  const now = new Date();
56
80
  await this.pool.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, " +
57
81
  "placement_kind, placement_scope, placement_parent_session_id, placement_root_session_id, placement_handle, placed_at) " +