@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
@@ -52,6 +52,11 @@ export function createSessionWorkspaceRecorder(store, witness) {
52
52
  },
53
53
  };
54
54
  }
55
+ export async function readSessionProjectId(store, sessionId) {
56
+ if (store === undefined)
57
+ return undefined;
58
+ return (await store.readSessionWorkspace(sessionId))?.project?.id;
59
+ }
55
60
  export async function legProjectIdOf(submitted, store, sessionId) {
56
61
  if (submitted !== undefined)
57
62
  return submitted;
@@ -4,7 +4,7 @@
4
4
  * SIGHUP(壳窗口关闭打到整个进程组)≠「没人在用这只引擎」:共享引擎形态(同 config 多壳会话,引擎按
5
5
  * T11 防孤儿拍骑在首壳进程组里)下 peer 会话还活着——无条件 drain 会把 peer mid-turn 斩掉(499)且窗内
6
6
  * 新提交 503。这里改为:SIGHUP 不翻 draining(peer 零感知),armed 一只空闲窗——工作谓词连续 idleGraceMs
7
- * 为假才 shutdown,任何工作重置窗口(谓词的在飞格读阻断集 `drainState.blockingInflight` = `http + leader`;会话驻留的后台 shell / monitor
7
+ * 为假才 shutdown,任何工作重置窗口(谓词的在飞格读阻断集 `drainState.blockingInflight` = `http + leader + backgroundAgents`;会话驻留的后台 shell / monitor
8
8
  * 在 `/health.inflight` 总数里、不阻断)。真孤儿(最后一窗关掉)
9
9
  * 有界自灭=T11 保留;第二个 SIGHUP 升级 escalate(既有 drain 路径,操作员硬梯子)。
10
10
  *
@@ -19,7 +19,8 @@ import type { SqlEngineFacts } from "./plugins/sql-driver.js";
19
19
  import { type SqlEngineCapability } from "./sql-engine-posture.js";
20
20
  /**
21
21
  * 降级词闭集(**按后端族**,不按失败发生在哪一步):
22
- * · `local_unwritable` —— **缺省推导**的 local 文件店构造期失败(mkdir / 数据根锁 / 权限 / 只读挂载 / 磁盘满)。
22
+ * · `local_unwritable` —— **缺省推导**的 local 文件店在**空 / 不存在**的数据根上构造期失败(mkdir / 权限 / 只读挂载 / 磁盘满)。
23
+ * 数据根上已有东西时开不了(含另一实例持锁)是拒启,不是降级(判据见 `openStoreBackendWithFallback`)。
23
24
  *
24
25
  * 🔴 SQL 族**没有**降级词:配了 DSN 的库当下打不开 ⇒ 窗内重试、到窗拒启(`plugins/store-open-wait.ts` / `openStoreBackendWithFallback`),
25
26
  * 从来不退成内存 —— 修前这里有第二个词 `db_unreachable`(`SESSION_BACKEND=auto` 下 SQL 族打不开 ⇒ 内存 + 本位置位),那是 [ref] P 类的静默 fail-open,随降级臂一并退役。
@@ -9,10 +9,11 @@ export type StoredHooksRereadM20 = (raw: unknown) => StoredHooksRereadM20Result
9
9
  /** 读者(= `parseHooksConfig`);作形参只为让「读者交回什么拒因」可被替身喂(默认值就是生产读者)。 */
10
10
  export type HooksReader = (raw: unknown) => ParseHooksConfigResult;
11
11
  /**
12
- * 重读一份存体 hooks:读者拒因全部属于两形 ⇒ 剥掉被点名的块里按类型确属未知的键、再问读者,**剥到读者受理为止**,过了就交回产物 + 被剥坐标;否则 `undefined`(原臂:整份不采纳)。
12
+ * 重读一份存体 hooks:读者拒因全部属于两形 ⇒ 剥掉被点名的块里该剥的键(全部未知键 + 被点名的不透明列)、再问读者,**剥到读者受理为止**,过了就交回产物 + 被剥坐标;否则 `undefined`(原臂:整份不采纳)。
13
13
  * 调用方只在读者**已经拒过**这份原值之后才来问;读者一开始就受理的值不进这里(进来也返回 `undefined`:没有可迁移的东西)。
14
14
  *
15
- * 终止:循环体以一次读开头(最后一次剥键之后必有一次读);继续下一轮的条件是本轮真从文档里剥掉了至少一个对象键,文档只减不增 ⇒ 必停;同一块只会被点名一次 ⇒ 轮数 ≤ 被点名的块数 + `__proto__` 键数。
15
+ * 终止:循环体以一次读开头(最后一次剥键之后必有一次读);继续下一轮的条件是本轮真从文档里剥掉了至少一个对象键,文档只减不增 ⇒ 必停;
16
+ * 同一块至多被点名 1 + 它的不透明列数次 ⇒ 轮数 ≤ Σ 被点名的块(1 + 不透明列数)+ `__proto__` 键数。
16
17
  */
17
18
  export declare function rereadStoredHooksM20(raw: unknown, read?: HooksReader): StoredHooksRereadM20Result | undefined;
18
19
  /**
@@ -1,13 +1,6 @@
1
- import { HOOK_ENTRY_TYPES } from "@sema-agent/settings-schema/hooks";
1
+ import { HOOK_ENTRY_FIELDS, HOOK_ENTRY_TYPES } from "@sema-agent/settings-schema/hooks";
2
2
  import { hooksCoordinate, parseHooksConfig } from "./hooks/hook-runner.js";
3
3
  import { ONE_TIME_MIGRATIONS, migrationWindowOpen } from "./plugins/one-time-migrations.js";
4
- const ENTRY_FIELD_NAMES = {
5
- command: { type: true, if: true, timeout: true, statusMessage: true, once: true, command: true, shell: true, async: true, asyncRewake: true },
6
- prompt: { type: true, if: true, timeout: true, statusMessage: true, once: true, prompt: true, model: true },
7
- agent: { type: true, if: true, timeout: true, statusMessage: true, once: true, prompt: true, model: true },
8
- http: { type: true, if: true, timeout: true, statusMessage: true, once: true, url: true, headers: true, allowedEnvVars: true },
9
- mcp_tool: { type: true, if: true, timeout: true, statusMessage: true, once: true, server: true, tool: true, input: true },
10
- };
11
4
  const MATCHER_FIELD_NAMES = { matcher: true, hooks: true };
12
5
  function isRecord(v) {
13
6
  return v !== null && typeof v === "object" && !Array.isArray(v);
@@ -27,13 +20,24 @@ function nodeAt(node, path) {
27
20
  }
28
21
  return cur;
29
22
  }
30
- function contractFieldsOf(code, block) {
23
+ const OPAQUE_KIND = "any";
24
+ function standingOf(code, block) {
31
25
  if (!isRecord(block))
32
26
  return undefined;
33
27
  if (code === "guard-matcher-invalid")
34
- return MATCHER_FIELD_NAMES;
28
+ return (key) => (Object.hasOwn(MATCHER_FIELD_NAMES, key) ? "read" : "unknown");
35
29
  const type = Object.hasOwn(block, "type") ? block.type : undefined;
36
- return isEntryType(type) ? ENTRY_FIELD_NAMES[type] : undefined;
30
+ if (!isEntryType(type))
31
+ return undefined;
32
+ const row = HOOK_ENTRY_FIELDS[type];
33
+ return (key) => {
34
+ if (key === "type")
35
+ return "read";
36
+ const kind = Object.hasOwn(row, key) ? row[key] : undefined;
37
+ if (kind === undefined)
38
+ return "unknown";
39
+ return (kind.endsWith("?") ? kind.slice(0, -1) : kind) === OPAQUE_KIND ? "opaque" : "read";
40
+ };
37
41
  }
38
42
  function stripTargetsOf(piece, doc) {
39
43
  const [root, ...rel] = piece.path;
@@ -43,11 +47,12 @@ function stripTargetsOf(piece, doc) {
43
47
  return [rel];
44
48
  if ((piece.code === "guard-entry-invalid" || piece.code === "guard-matcher-invalid") && typeof piece.field === "string") {
45
49
  const block = nodeAt(doc, rel);
46
- const known = contractFieldsOf(piece.code, block);
47
- if (known === undefined || !isRecord(block) || Object.hasOwn(known, piece.field) || !Object.hasOwn(block, piece.field))
50
+ const standing = standingOf(piece.code, block);
51
+ const named = piece.field;
52
+ if (standing === undefined || !isRecord(block) || !Object.hasOwn(block, named) || standing(named) === "read")
48
53
  return undefined;
49
54
  return Object.keys(block)
50
- .filter((key) => !Object.hasOwn(known, key))
55
+ .filter((key) => key === named || standing(key) === "unknown")
51
56
  .map((key) => [...rel, key]);
52
57
  }
53
58
  return undefined;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The SQL blob INDEX of a content-addressed blob domain — one row per blob `(blob_hash, byte_len, bytes, created_at)` in the
3
+ * domain's own table ([ref] D1: the file-history domain's `file_history_blob`; the retired snapshot epoch's `snapshot_blob`). The
4
+ * rows are the INDEX OWNER's (the store), never the byte port's: whether a blob is there, which blobs are orphans, the created_at
5
+ * grace window, the per-blob cap on SQL-kept bytes and the content-address check of a port read all live here. The byte port
6
+ * ({@link BlobBackend}, `plugins/blob-backend.ts`) only moves bytes: `put` / `get` / `delete` under a key.
7
+ *
8
+ * Where the bytes go — one option, the shape of the engine package's `fileHistory.blobs`:
9
+ * - no byte port (the DEFAULT): the bytes ride the index row itself (the `bytes` column), so a deployment without object storage
10
+ * keeps every blob in SQL, capped per blob ({@link sqlBlobCapOf}, judged on the connection that writes);
11
+ * - a byte port (object storage): the port stores the bytes under the blob's hash and the index row keeps `bytes` NULL. The port
12
+ * write lands BEFORE the index row, so an index row never claims bytes the port does not hold (an object with no row is
13
+ * unreachable and harmless); a port read is checked against its hash here ({@link readAtAddress}) — a mismatch reads as absent.
14
+ *
15
+ * Deletion stays ASYNCHRONOUS (clay 2026-06-26): a purge deletes only the referencing rows, so a blob becomes an orphan; the periodic
16
+ * {@link SqlBlobIndex.sweep} removes the grace-passed index rows FIRST and then asks the port to delete exactly those keys. A port
17
+ * delete that fails surfaces (the sweep rejects — the reaper's throttled guard is the loud channel) and leaves an object with no row.
18
+ *
19
+ * The SQL statements below are the ones the retired `SqlBlobBackend` / indexed `MinioBlobBackend` sent, verbatim — this module only
20
+ * gathers them under their owner.
21
+ */
22
+ import type { Pool as MysqlPool } from "mysql2/promise";
23
+ import type { Pool as PgPool } from "pg";
24
+ import { type BlobBackend } from "../plugins/blob-backend.js";
25
+ import { type SqlEngineFacts, type SqlEngineReading, type SqlWallSource, type SqlWallsReading, type SqlDialect } from "../plugins/sql-driver.js";
26
+ import { type Logger } from "../observability/logger.js";
27
+ /**
28
+ * 文本协议的 blob 膨胀律 —— mysql2 `query()` 把 Buffer 参数写成 `X'<hex>'`,一字节两个字符,所以承载一个 blob 的语句至少是它的 2 倍。
29
+ * 包墙折成「能装下多大的 blob」只用这一只常量,推导里不手写 `/ 2`。
30
+ */
31
+ export declare const SQL_TEXT_PROTOCOL_BLOB_INFLATION = 2;
32
+ /**
33
+ * 包墙下能装多大的 blob:语句里的载荷量({@link packetWallStatementBytes})再按 {@link SQL_TEXT_PROTOCOL_BLOB_INFLATION} 折半。
34
+ * blob 以十六进制字面进语句、有 2× —— 膨胀律是 blob 腿自己的,余量不是。
35
+ */
36
+ export declare function packetWallBlobCap(maxPacketBytes: number): number;
37
+ /**
38
+ * SQL 快照 blob 的**缺省**帽(运维没设 `SNAPSHOT_BLOB_SQL_MAX_BYTES` 时)的唯一推导 —— 入参是判官 `sqlWallsOf` 给的墙(不读事实、不判缺席、不看方言),**两堵墙取最小**:
39
+ * 行墙腿(`SqlEngineFacts.maxRowBytes`,TiDB:{@link rowWallPayloadBytes} 的 `blob` = 行墙 − blob 行的余量 1 KiB —— 按这一行的真实形算,不借 JSON 提交体行的 64 KiB)
40
+ * 与包墙腿(`SqlEngineFacts.maxPacketBytes`,InnoDB 与 TiDB 都有:{@link packetWallBlobCap} = ⌊(包墙 − 1 KiB 语句余量) ÷ 2⌋)。余量只在 `sql-driver.ts` 定义一次
41
+ * (墙 × 行的形各一只),提交体受理口(`http/request-guards.ts` `refuseSubmitBody`)读同一张表的 `json` 那一只,不各抄。
42
+ * 墙的 `null` 只表示「这堵墙不存在」;两堵都不存在(PG —— 扩展协议无这两堵墙 —— 或没有 SQL 后端)⇒ `undefined` 不设帽。
43
+ * 「事实本身缺席」不是这里的入参:店的写前判读的是借出连接自己的事实(恒已建立,见 {@link SqlConnectionReading}),缺席的读法只在提交受理口读池级读口时出现(判官 `sqlWallsOf` 给墙)。
44
+ * 显式旋钮是运维的策略帽,在本推导之上(见 {@link sqlBlobCapBytes})。
45
+ *
46
+ * 两堵墙的真库读数(clay 拍 a+c,2026-07-27;k3s8 tidb-test v7.5.1 默认配置探针):7 MiB / 31 MiB = `entry too large`(行墙,默认 6291456)、
47
+ * 32 MiB = `max_allowed_packet`(包墙,64 MiB ÷ ~2× 文本协议膨胀)。帽=诚实拒绝:超限 blob 在 query 之前 typed 拒(消费面 HTTP 413 / capture warn
48
+ * 拿到可行动信息);帽与墙之间只差这一行自己的几百字节(blob 行余量),帽之下的 blob 在缺省配置下落得进。D-1 附件战役同墙教训:`task-attachment-store.ts` 头注。
49
+ */
50
+ export declare function sqlBlobDefaultCapBytes(walls: SqlWallsReading): number | undefined;
51
+ /**
52
+ * 一个 SQL 快照 blob 的帽 + 它**从哪来**。`operator` = 运维显式设的 `SNAPSHOT_BLOB_SQL_MAX_BYTES`(策略帽);`reported` / `assumed` = 缺省推导里**定下这个帽的那条腿**的墙数字出处
53
+ * ({@link SqlWallSource}:库自己报的 / 读失败或事实缺席而退的文档缺省)。机读位同 413 拒体的 `wallSource` 词,旋钮形多一个 `operator`。
54
+ */
55
+ export interface SqlBlobCapReading {
56
+ readonly capBytes: number;
57
+ readonly source: "operator" | SqlWallSource;
58
+ }
59
+ /**
60
+ * 缺省帽的推导(唯一一处,{@link sqlBlobDefaultCapBytes} 是它的字节投影):两条腿各带自己那堵墙的出处,取最小的那条;两条一样小取行墙腿。两堵墙都不存在 ⇒ `undefined`。
61
+ */
62
+ export declare function sqlBlobDefaultCapOf(walls: SqlWallsReading): SqlBlobCapReading | undefined;
63
+ /**
64
+ * 一条**借出连接**的引擎读口:方言(装配事实)+ 它自己那次初始化回读的事实。与 {@link SqlEngineReading} 的差别只有一处 —— `facts` 恒在:连接是借出时才有的,
65
+ * 借出即已初始化({@link connectJudged} 交给判决的就是借出连接的 `sqlConnectionFacts`),所以「事实缺席」在这条读法上**不可表示**(编译期拒,不是运行期一个没人走的分支)。
66
+ * 事实缺席(池上还没建立过、或最近一次初始化被拒)只出现在读**池级**读口的地方 —— 提交受理口 —— 那一格的墙由判官 `sqlWallsOf` 给,不经过帽的推导。
67
+ */
68
+ export interface SqlConnectionReading {
69
+ readonly dialect: SqlEngineReading["dialect"];
70
+ readonly facts: SqlEngineFacts;
71
+ }
72
+ /**
73
+ * 一个 SQL 快照 blob 此刻的帽 —— **显式旋钮 ?? 判官给的墙走缺省推导**的唯一一只函数。唯一读者 = 店的写前判({@link SqlBlobIndex.put} 的 SQL 存字节臂),传的读口({@link SqlConnectionReading})是
74
+ * **将要执行写入的那条连接**的(方言 + 它自己那次初始化回读的事实,墙经与提交受理口同一只判官 `sqlWallsOf`):包墙是连接的会话值,所以判决只在写入的那条连接上做,
75
+ * HTTP 面不替店另算一份帽。
76
+ */
77
+ export declare function sqlBlobCapOf(explicitCapBytes: number | undefined, connection: SqlConnectionReading): SqlBlobCapReading | undefined;
78
+ /** {@link sqlBlobCapOf} 的字节投影(同一个推导,不另读)。 */
79
+ export declare function sqlBlobCapBytes(explicitCapBytes: number | undefined, connection: SqlConnectionReading): number | undefined;
80
+ /**
81
+ * 这一拒是不是**那条连接的包墙**定的:帽是缺省推导出的(不是运维旋钮)、那条连接有包墙、且包墙腿的折算恰是这个帽(包墙腿是最矮的一腿,或与行墙腿并列)。
82
+ * 只有这种拒才值得问「这条连接过时了吗」({@link connectJudged}) —— 旋钮的拒、行墙的拒与连接新旧无关。`walls` = 判出这个帽的那一份墙({@link sqlWallsOf})。
83
+ */
84
+ export declare function capBoundByPacketWall(cap: SqlBlobCapReading, walls: SqlWallsReading): boolean;
85
+ /**
86
+ * 一次 blob 超帽的拒句 —— **唯一的组句器**(店的 typed {@link BlobTooLargeError} 调它;`PUT /sync/blobs` 的 413 原样转出它的句子):句子按帽的出处({@link SqlBlobCapReading.source})
87
+ * 分三形,不把假定说成库的上限、也不把运维的旋钮说成库的上限。
88
+ * · `operator` —— 帽是运维设的 `SNAPSHOT_BLOB_SQL_MAX_BYTES`;
89
+ * · `reported` —— 帽由库报的两堵墙推出(单行上限与包墙÷文本协议膨胀的较小者);
90
+ * · `assumed` —— 库的上限没读到(事实还没建立,或这一堵读失败),帽按受支持引擎里最保守的缺省墙推出,稍后重试或由运维设旋钮。
91
+ */
92
+ export declare function sqlBlobCapRefusalText(byteLen: number, cap: SqlBlobCapReading): string;
93
+ /** typed 判别错:blob 超过 SQL 店的承载帽。判别码供店侧结果映射/HTTP 面/日志使用——绝不能与
94
+ * transient 写失败混在一类(那类是可重试的 502;这类重试永远不会成功)。句子是 {@link sqlBlobCapRefusalText}(带帽的出处)。 */
95
+ export declare class BlobTooLargeError extends Error {
96
+ readonly cap: SqlBlobCapReading;
97
+ readonly code: "blob_too_large_for_sql";
98
+ constructor(byteLen: number, cap: SqlBlobCapReading);
99
+ }
100
+ /** The blob domain an index serves, and where its bytes go (see the file header). */
101
+ export interface SqlBlobIndexOptions {
102
+ /** The domain's index table (a code literal, never user input). */
103
+ readonly table: string;
104
+ /** The byte port; absent ⇒ the bytes ride the index rows (SQL). */
105
+ readonly bytes?: BlobBackend;
106
+ /** The operator's explicit per-blob cap for SQL-kept bytes (`SNAPSHOT_BLOB_SQL_MAX_BYTES`); absent ⇒ the derivation in
107
+ * {@link sqlBlobCapOf} over the walls of the connection each write borrows. Not read with a byte port. */
108
+ readonly maxBytes?: number;
109
+ /** Where a stale connection's replacement is logged ({@link connectJudged}). */
110
+ readonly log?: Pick<Logger, "warn">;
111
+ }
112
+ /**
113
+ * One blob domain's index, owned by its store: every read and write of the domain's blob rows, and the only caller of the byte port.
114
+ */
115
+ export declare class SqlBlobIndex {
116
+ private readonly dialect;
117
+ private readonly pool;
118
+ private readonly opts;
119
+ /** The write path's connection source: an SQL-kept `put` borrows ONE connection from it (through {@link connectJudged}), judges on that connection's walls, writes on it. */
120
+ private readonly db;
121
+ private readonly log;
122
+ constructor(dialect: SqlDialect, pool: MysqlPool | PgPool, opts: SqlBlobIndexOptions);
123
+ /** Store `bytes` under `hash` (idempotent; a repeat refreshes created_at even on a dedup hit, so a just-written or re-used blob is
124
+ * "touched = now" and grace-protected — the delete-in-use lease).
125
+ * · SQL-kept: an over-cap blob is REJECTED (typed {@link BlobTooLargeError}) BEFORE the driver sees the bytes. 🔴 The cap is judged
126
+ * ON THE CONNECTION THAT WRITES ([ref]): `max_allowed_packet` is a session value, so the write borrows one connection through
127
+ * {@link connectJudged}, which reads ITS walls, judges, and — when the refusal is that connection's packet wall and the server's
128
+ * global wall is higher — replaces the stale connection and judges once more; the INSERT runs on the connection that passed.
129
+ * · Port-kept: the port write first, then the bytes-NULL index row (an index row never claims bytes the port does not hold). A
130
+ * failed port write throws (a silent drop would read as `read_failed` on restore). */
131
+ put(hash: string, bytes: Uint8Array): Promise<void>;
132
+ /** The bytes for `hash`, or `undefined` when absent. SQL-kept: the row's bytes (a pool / query error PROPAGATES — a transient fault
133
+ * is loud, not a silent "missing blob"). Port-kept: the port's bytes, checked against `hash` ({@link readAtAddress}: a mismatch —
134
+ * corruption or a poisoned object — reads as absent, never as wrong bytes; a transient port fault throws). */
135
+ get(hash: string): Promise<Uint8Array | undefined>;
136
+ /** The subset of `hashes` with an index row — one `blob_hash IN (...)` SELECT, the same reading for both byte homes (a bytes-NULL
137
+ * row counts as present). No bytes are read. */
138
+ has(hashes: readonly string[]): Promise<Set<string>>;
139
+ /** Collect orphans: the caller (the store) computes the orphan SET from its own domain's references and hands it here. Removes the
140
+ * index rows past the grace window (`created_at < cutoff` — a just-written blob an in-flight write still needs is never deleted:
141
+ * delete-in-use is data loss, under-delete is harmless), then — with a byte port — deletes exactly those keys' bytes. Returns the
142
+ * number of blobs removed (the grace-passed subset). A port delete failure surfaces as a rejection after the rows are gone. */
143
+ sweep(orphans: readonly string[]): Promise<number>;
144
+ /** DELETE the index rows for `hashes` that have passed the grace window; returns the hashes ACTUALLY deleted. Best-effort: a DB
145
+ * error is swallowed (under-delete is harmless; the next sweep retries). */
146
+ private deleteRowsPastGrace;
147
+ }
148
+ //# sourceMappingURL=blob-index-sql.d.ts.map
@@ -0,0 +1,154 @@
1
+ import { readAtAddress } from "../plugins/blob-backend.js";
2
+ import { connectJudged, mysqlDriver, packetWallStatementBytes, pgDriver, rowWallPayloadBytes, sqlWallsOf } from "../plugins/sql-driver.js";
3
+ import { createLogger } from "../observability/logger.js";
4
+ const BLOB_GC_GRACE_MS = 3_600_000;
5
+ export const SQL_TEXT_PROTOCOL_BLOB_INFLATION = 2;
6
+ export function packetWallBlobCap(maxPacketBytes) {
7
+ return Math.floor(packetWallStatementBytes(maxPacketBytes) / SQL_TEXT_PROTOCOL_BLOB_INFLATION);
8
+ }
9
+ export function sqlBlobDefaultCapBytes(walls) {
10
+ return sqlBlobDefaultCapOf(walls)?.capBytes;
11
+ }
12
+ export function sqlBlobDefaultCapOf(walls) {
13
+ const legs = [];
14
+ if (walls.maxRowBytes !== null)
15
+ legs.push({ capBytes: rowWallPayloadBytes(walls.maxRowBytes, "blob"), source: walls.sources.maxRowBytes });
16
+ if (walls.maxPacketBytes !== null)
17
+ legs.push({ capBytes: packetWallBlobCap(walls.maxPacketBytes), source: walls.sources.maxPacketBytes });
18
+ return legs.reduce((best, leg) => (best === undefined || leg.capBytes < best.capBytes ? leg : best), undefined);
19
+ }
20
+ export function sqlBlobCapOf(explicitCapBytes, connection) {
21
+ return explicitCapBytes !== undefined ? { capBytes: explicitCapBytes, source: "operator" } : sqlBlobDefaultCapOf(sqlWallsOf(connection));
22
+ }
23
+ export function sqlBlobCapBytes(explicitCapBytes, connection) {
24
+ return sqlBlobCapOf(explicitCapBytes, connection)?.capBytes;
25
+ }
26
+ export function capBoundByPacketWall(cap, walls) {
27
+ return cap.source !== "operator" && walls.maxPacketBytes !== null && packetWallBlobCap(walls.maxPacketBytes) === cap.capBytes;
28
+ }
29
+ export function sqlBlobCapRefusalText(byteLen, cap) {
30
+ const objectStorage = "configure MinIO object storage (MINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY) for large snapshot blobs";
31
+ const head = `blob of ${byteLen} bytes exceeds this deployment's SQL snapshot-blob cap (${cap.capBytes} bytes — `;
32
+ switch (cap.source) {
33
+ case "operator":
34
+ return `${head}set by the operator's SNAPSHOT_BLOB_SQL_MAX_BYTES) — ${objectStorage}, or raise SNAPSHOT_BLOB_SQL_MAX_BYTES if the database allows larger writes`;
35
+ case "reported":
36
+ return `${head}the smaller of the database's single-row limit (TiDB txn-entry-size-limit, 6MiB by default) and about half its max_allowed_packet (the text protocol doubles a blob inside the statement)) — ${objectStorage}, or raise SNAPSHOT_BLOB_SQL_MAX_BYTES if your deployment lifted those limits`;
37
+ case "assumed":
38
+ return `${head}the database's limits were not read — engine facts not read yet, or a limit could not be read — so the smallest documented default wall applies) — retry shortly, ${objectStorage}, or set SNAPSHOT_BLOB_SQL_MAX_BYTES to the limit your deployment actually has`;
39
+ default: {
40
+ const unhandled = cap.source;
41
+ throw new Error(`blob cap refusal without a sentence: ${String(unhandled)}`);
42
+ }
43
+ }
44
+ }
45
+ export class BlobTooLargeError extends Error {
46
+ cap;
47
+ code = "blob_too_large_for_sql";
48
+ constructor(byteLen, cap) {
49
+ super(sqlBlobCapRefusalText(byteLen, cap));
50
+ this.cap = cap;
51
+ this.name = "BlobTooLargeError";
52
+ }
53
+ }
54
+ export class SqlBlobIndex {
55
+ dialect;
56
+ pool;
57
+ opts;
58
+ db;
59
+ log;
60
+ constructor(dialect, pool, opts) {
61
+ this.dialect = dialect;
62
+ this.pool = pool;
63
+ this.opts = opts;
64
+ this.db = dialect === "mysql" ? mysqlDriver(pool) : pgDriver(pool);
65
+ this.log = opts.log ?? createLogger();
66
+ }
67
+ async put(hash, bytes) {
68
+ const port = this.opts.bytes;
69
+ if (port !== undefined) {
70
+ await port.put(hash, bytes);
71
+ if (this.dialect === "mysql") {
72
+ await this.pool.query(`INSERT INTO ${this.opts.table} (blob_hash, byte_len, bytes, created_at) VALUES (?,?,NULL,?) ON DUPLICATE KEY UPDATE created_at = VALUES(created_at)`, [hash, bytes.byteLength, new Date()]);
73
+ }
74
+ else {
75
+ await this.pool.query(`INSERT INTO ${this.opts.table} (blob_hash, byte_len, bytes, created_at) VALUES ($1,$2,NULL,$3) ON CONFLICT (blob_hash) DO UPDATE SET created_at = EXCLUDED.created_at`, [hash, bytes.byteLength, new Date()]);
76
+ }
77
+ return;
78
+ }
79
+ const judged = await connectJudged(this.db, (facts) => {
80
+ const connection = { dialect: this.dialect, facts };
81
+ const cap = sqlBlobCapOf(this.opts.maxBytes, connection);
82
+ if (cap === undefined || bytes.byteLength <= cap.capBytes)
83
+ return undefined;
84
+ return { cap, packetBound: capBoundByPacketWall(cap, sqlWallsOf(connection)) };
85
+ }, (refusal) => refusal.packetBound, this.log);
86
+ if (judged.refusal !== undefined)
87
+ throw new BlobTooLargeError(bytes.byteLength, judged.refusal.cap);
88
+ try {
89
+ await judged.conn.query(this.dialect === "mysql"
90
+ ? `INSERT INTO ${this.opts.table} (blob_hash, byte_len, bytes, created_at) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE created_at = VALUES(created_at)`
91
+ : `INSERT INTO ${this.opts.table} (blob_hash, byte_len, bytes, created_at) VALUES ($1,$2,$3,$4) ON CONFLICT (blob_hash) DO UPDATE SET created_at = EXCLUDED.created_at`, [hash, bytes.byteLength, Buffer.from(bytes), new Date()]);
92
+ }
93
+ finally {
94
+ judged.conn.release();
95
+ }
96
+ }
97
+ async get(hash) {
98
+ const port = this.opts.bytes;
99
+ if (port !== undefined)
100
+ return readAtAddress(port, hash);
101
+ if (this.dialect === "mysql") {
102
+ const [rows] = await this.pool.query(`SELECT bytes FROM ${this.opts.table} WHERE blob_hash = ?`, [hash]);
103
+ return rows[0]?.bytes != null ? new Uint8Array(rows[0].bytes) : undefined;
104
+ }
105
+ const b = await this.pool.query(`SELECT bytes FROM ${this.opts.table} WHERE blob_hash = $1`, [hash]);
106
+ return b.rows[0]?.bytes != null ? new Uint8Array(b.rows[0].bytes) : undefined;
107
+ }
108
+ async has(hashes) {
109
+ if (hashes.length === 0)
110
+ return new Set();
111
+ const distinct = [...new Set(hashes)];
112
+ if (this.dialect === "mysql") {
113
+ const ph = distinct.map(() => "?").join(",");
114
+ const [rows] = await this.pool.query(`SELECT blob_hash FROM ${this.opts.table} WHERE blob_hash IN (${ph})`, distinct);
115
+ return new Set(rows.map((r) => String(r.blob_hash)));
116
+ }
117
+ const ph = distinct.map((_, i) => `$${i + 1}`).join(",");
118
+ const r = await this.pool.query(`SELECT blob_hash FROM ${this.opts.table} WHERE blob_hash IN (${ph})`, distinct);
119
+ return new Set(r.rows.map((row) => row.blob_hash));
120
+ }
121
+ async sweep(orphans) {
122
+ const removed = await this.deleteRowsPastGrace(orphans);
123
+ const port = this.opts.bytes;
124
+ if (port !== undefined && removed.length > 0)
125
+ await port.delete(removed);
126
+ return removed.length;
127
+ }
128
+ async deleteRowsPastGrace(hashes) {
129
+ if (hashes.length === 0)
130
+ return [];
131
+ const distinct = [...new Set(hashes)];
132
+ const cutoff = new Date(Date.now() - BLOB_GC_GRACE_MS);
133
+ if (this.dialect === "mysql") {
134
+ const ph = distinct.map(() => "?").join(",");
135
+ const grace = await this.pool
136
+ .query(`SELECT blob_hash FROM ${this.opts.table} WHERE created_at < ? AND blob_hash IN (${ph})`, [cutoff, ...distinct])
137
+ .then(([rows]) => rows.map((r) => String(r.blob_hash)))
138
+ .catch(() => []);
139
+ if (grace.length === 0)
140
+ return [];
141
+ const gph = grace.map(() => "?").join(",");
142
+ await this.pool
143
+ .query(`DELETE FROM ${this.opts.table} WHERE created_at < ? AND blob_hash IN (${gph})`, [cutoff, ...grace])
144
+ .catch(() => undefined);
145
+ return grace;
146
+ }
147
+ const ph = distinct.map((_, i) => `$${i + 2}`).join(",");
148
+ const r = await this.pool
149
+ .query(`DELETE FROM ${this.opts.table} WHERE created_at < $1 AND blob_hash IN (${ph}) RETURNING blob_hash`, [cutoff, ...distinct])
150
+ .catch(() => undefined);
151
+ return (r?.rows ?? []).map((row) => row.blob_hash);
152
+ }
153
+ }
154
+ //# sourceMappingURL=blob-index-sql.js.map
@@ -85,7 +85,7 @@ export declare class SqlCheckpointStore implements CheckpointStore {
85
85
  info?(msg: string, meta?: unknown): void;
86
86
  } | undefined;
87
87
  /** 托管留存声明 = 装配交给它的词(后端按扫车道开不开给;不给 ⇒ `"none"`)。读法与「为什么 SQL 店答 managed 而三方法的实现体在
88
- * `retention-store-sql.ts`」逐字见 {@link MANAGED_RETENTION}(扫车道开着时本店的 `checkpoint`/`checkpoint_ctx` 两表由那只聚合店按期清)。 */
88
+ * `retention-store-sql.ts`」逐字见 `plugins/retention-declaration.ts` 的 {@link MANAGED_RETENTION}(扫车道开着时本店的 `checkpoint`/`checkpoint_ctx` 两表由那只聚合店按期清)。 */
89
89
  readonly retention: RetentionDeclaration;
90
90
  /**
91
91
  * `CheckpointStore.durability` 声明([ref] 欠账,[ref] 件5)—— 行落在 MySQL-protocol / PostgreSQL 的
@@ -9,7 +9,7 @@ import { durableRowIdentity, withoutCheckpointToken } from "../checkpoint-identi
9
9
  import { mysqlDriver, pgDriver, dialectProtocolJsonEncoder } from "../plugins/sql-driver.js";
10
10
  import { isDupKeyError, isMissingColumnError, rowTooLargeOrSelf, StoreRowTooLargeError } from "../plugins/sql-errors.js";
11
11
  import { describeProbedTableDrift } from "../plugins/schema-drift-sentence.js";
12
- import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "../plugins/retention-store-sql.js";
12
+ import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "../plugins/retention-declaration.js";
13
13
  import { approvalPayloadFingerprint } from "../plugins/approval-payload-fingerprint.js";
14
14
  import { approvalDecisionOfWinner, boundedRuleOffers, boundedToolInput, candidateIdentityOf, DECIDED_REPLAY_SCAN_CAP, queueRowGateKind, TERMINAL_BACKSTOP_MS, TERMINAL_GRACE_MS, UnreadableCheckpointRowError, } from "../plugins/checkpoint-store-face.js";
15
15
  const CTX_REWRITE_PAGE = 500;
@@ -187,39 +187,23 @@ function candidateIdentityOfColumn(cell, where) {
187
187
  }
188
188
  return candidateIdentityOf(cp);
189
189
  }
190
- function readActorAssertion(v) {
191
- if (typeof v !== "object" || v === null)
192
- return undefined;
193
- const id = "id" in v ? v.id : undefined;
194
- const hostAsserted = "hostAsserted" in v ? v.hostAsserted : undefined;
195
- if (typeof id !== "string" || typeof hostAsserted !== "boolean")
196
- return undefined;
197
- const issuer = "issuer" in v ? v.issuer : undefined;
198
- return { id, hostAsserted, ...(typeof issuer === "string" ? { issuer } : {}) };
199
- }
200
190
  function readQueueEntry(v) {
201
191
  if (typeof v !== "object" || v === null)
202
192
  return undefined;
203
- const text = "text" in v ? v.text : undefined;
204
- const trusted = "trusted" in v ? v.trusted : undefined;
205
193
  const seq = "seq" in v ? v.seq : undefined;
206
- const inputId = "inputId" in v ? v.inputId : undefined;
207
- if (typeof text !== "string" || typeof trusted !== "boolean")
208
- return undefined;
209
194
  if (typeof seq !== "number" || !Number.isFinite(seq))
210
195
  return undefined;
211
- if (typeof inputId !== "string" || inputId === "")
196
+ if (!("inputId" in v) || v.inputId === undefined)
212
197
  return undefined;
213
- const priority = "priority" in v ? v.priority : undefined;
214
- const actor = readActorAssertion("actor" in v ? v.actor : undefined);
215
- return {
216
- text,
217
- trusted,
218
- seq,
219
- inputId,
220
- ...(actor !== undefined ? { actor } : {}),
221
- ...(priority === "now" || priority === "next" || priority === "later" ? { priority } : {}),
222
- };
198
+ const carried = Object.fromEntries(Object.entries(v).filter(([key]) => key !== "seq"));
199
+ try {
200
+ return { ...validatePendingSteer(carried), seq };
201
+ }
202
+ catch (e) {
203
+ if (e instanceof CheckpointError && e.code === "steering.invalid_content")
204
+ return undefined;
205
+ throw e;
206
+ }
223
207
  }
224
208
  export function readPendingSteerQueueColumn(queueRaw) {
225
209
  let lossy = false;
@@ -1,10 +1,11 @@
1
1
  import type { Pool as MySqlPool } from "mysql2/promise";
2
2
  import type { Pool as PgPool } from "pg";
3
3
  import { type FileHistoryRetentionPolicy, type ExecutionEnv, type FileHistoryStore, type FileHistoryResult, type FileHistoryTrackResult, type FileHistoryRestoreResult, type FileHistoryExport, type FileHistoryExportResult } from "@sema-agent/core";
4
- import { type BlobBackend } from "./blob-backend.js";
5
- import type { ServiceBlobExchange } from "./store-backend.js";
6
- import { type SqlDriver, type SqlDialect } from "./sql-driver.js";
7
- /** The file-history blob domain's SQL table (BlobBackend `table`/MinIO index binding + the A7 assert). */
4
+ import type { BlobBackend } from "../plugins/blob-backend.js";
5
+ import { SqlBlobIndex } from "./blob-index-sql.js";
6
+ import type { ServiceBlobExchange } from "../plugins/store-backend.js";
7
+ import { type SqlDriver, type SqlDialect } from "../plugins/sql-driver.js";
8
+ /** The file-history blob domain's SQL table (this store's blob index + the A7 assert). */
8
9
  export declare const FILE_HISTORY_BLOB_TABLE = "file_history_blob";
9
10
  /** MinIO object-key prefix for this domain (snapshot epoch used "blobs/"; a separate prefix keeps the
10
11
  * two domains' objects disjoint so neither sweep can see the other's keys). */
@@ -17,18 +18,29 @@ export declare const FILE_HISTORY_BLOB_KEY_PREFIX = "file-history/";
17
18
  */
18
19
  export interface SqlFileHistoryStoreOptions {
19
20
  retention?: FileHistoryRetentionPolicy;
21
+ /** Where the blob bytes go — the shape of the engine package's `fileHistory.blobs`: absent ⇒ in this store's own
22
+ * `file_history_blob` rows (SQL, capped per blob); a byte port ⇒ the port holds them and the rows keep bytes NULL. */
23
+ blobs?: BlobBackend;
24
+ /** The operator's explicit per-blob cap for SQL-kept bytes (`SNAPSHOT_BLOB_SQL_MAX_BYTES`); absent ⇒ derived from the walls of
25
+ * the connection that writes. Not read with a byte port. */
26
+ blobSqlMaxBytes?: number;
27
+ /** Where a stale connection's replacement on an SQL-kept blob write is logged. */
28
+ log?: {
29
+ warn(msg: string, meta?: Record<string, unknown>): void;
30
+ };
20
31
  }
21
32
  /** Dual-dialect durable FileHistoryStore. See the file header for posture + dialect-delta ledger. */
22
33
  export declare class SqlFileHistoryStore implements FileHistoryStore {
23
34
  protected readonly db: SqlDriver;
24
- /** RAW native pool — handed to blob-backend.ts (outside the SqlDriver seam, dialect-switches on
35
+ /** RAW native pool — handed to the blob index (`blob-index-sql.ts`, outside the SqlDriver seam, dialect-switches on
25
36
  * its own string). Not used for this class's own statements (those go through `db`). */
26
37
  protected readonly pool: MySqlPool | PgPool;
27
38
  /** The blob exchange (core's `FileHistoryStore.blobExchange` group, see {@link ServiceBlobExchange}): how another machine's bytes
28
39
  * come in ahead of an `importHistory`, go out to a puller, and are asked about. Its presence IS the capability — read through
29
40
  * `blobExchangeOf` (`session-sync.ts`), which defers to core's judge; there is no second word for it on this class. */
30
41
  readonly blobExchange: ServiceBlobExchange;
31
- protected readonly blobs: BlobBackend;
42
+ /** This store's blob index (the `file_history_blob` rows; the byte port, when given, behind it). */
43
+ protected readonly blobs: SqlBlobIndex;
32
44
  /** §10 S-6 in-process lease state (design v1 D2: NOT persisted). Keys = `${scope}\x00${entryId}`. */
33
45
  private readonly spentAttempts;
34
46
  private readonly activeAttempts;
@@ -36,9 +48,9 @@ export declare class SqlFileHistoryStore implements FileHistoryStore {
36
48
  * 由 core 的 `resolveFileHistoryRetention` 在构造期裁定 —— 与两只内置后端同一道门、同一句拒绝。 */
37
49
  private readonly boundaryKeep;
38
50
  constructor(db: SqlDriver,
39
- /** RAW native pool — handed to blob-backend.ts (outside the SqlDriver seam, dialect-switches on
51
+ /** RAW native pool — handed to the blob index (`blob-index-sql.ts`, outside the SqlDriver seam, dialect-switches on
40
52
  * its own string). Not used for this class's own statements (those go through `db`). */
41
- pool: MySqlPool | PgPool, blobBackend?: BlobBackend, opts?: SqlFileHistoryStoreOptions);
53
+ pool: MySqlPool | PgPool, opts?: SqlFileHistoryStoreOptions);
42
54
  /** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
43
55
  private q;
44
56
  private bool;
@@ -174,18 +186,18 @@ export declare class SqlFileHistoryStore implements FileHistoryStore {
174
186
  /**
175
187
  * Fetch + content-address verify EVERY blob the envelope references from the source, one at a time (memory bounded by one blob) —— 首推与同图重推共用的**唯一**取值校验;
176
188
  * 任何一枚取不出 / 核不过 ⇒ 整信封典型拒,什么都不发布。`onVerified` = 校验过的这一枚拿来做什么:首推传「续租式 upsert」(delete-in-use 租约 —— 发布前的孤儿清扫不许收走
177
- * 这次导入正要引用的字节);同图重推不传 —— 已发布的图的版本行本身就是引用,租约无事可护,而回写会把每只对象重传一遍(MinIO 的 `putBlob` 是整体 PUT)。
189
+ * 这次导入正要引用的字节);同图重推不传 —— 已发布的图的版本行本身就是引用,租约无事可护,而回写会把每只对象重传一遍(对象存储字节口的 `put` 是整体 PUT)。
178
190
  */
179
191
  private verifySourceBlobs;
180
192
  importHistory(scope: string, data: FileHistoryExport, srcGetBlob: (hash: string) => Promise<Uint8Array | undefined>): Promise<FileHistoryResult>;
181
193
  }
182
194
  /** MySQL-protocol (TiDB) binding. */
183
195
  export declare class TiDBFileHistoryStore extends SqlFileHistoryStore {
184
- constructor(pool: MySqlPool, blobBackend?: BlobBackend, opts?: SqlFileHistoryStoreOptions);
196
+ constructor(pool: MySqlPool, opts?: SqlFileHistoryStoreOptions);
185
197
  }
186
198
  /** PostgreSQL binding. */
187
199
  export declare class PgFileHistoryStore extends SqlFileHistoryStore {
188
- constructor(pool: PgPool, blobBackend?: BlobBackend, opts?: SqlFileHistoryStoreOptions);
200
+ constructor(pool: PgPool, opts?: SqlFileHistoryStoreOptions);
189
201
  }
190
202
  /**
191
203
  * [ref] D1② — A7-recipe upgrade precondition assert (**refuse to start**, never a warn; the form and