@sema-agent/server 7.147.0 → 7.148.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 (725) hide show
  1. package/MIGRATION.md +1039 -24
  2. package/README.md +20 -7
  3. package/README.zh-CN.md +14 -8
  4. package/USAGE.md +380 -163
  5. package/deploy/sema-up/README.md +16 -5
  6. package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +20 -4
  8. package/deploy/sema-up/chart/values.yaml +3 -2
  9. package/deploy/sema-up/cluster-up.sh +74 -176
  10. package/deploy/sema-up/kube-up.sh +29 -49
  11. package/deploy/sema-up/lib/chart-run.sh +23 -0
  12. package/deploy/sema-up/lib/dataroot.sh +3 -3
  13. package/deploy/sema-up/lib/health.sh +62 -13
  14. package/deploy/sema-up/lib/helm-values-cluster.py +18 -0
  15. package/deploy/sema-up/lib/helm-values-kube.py +35 -0
  16. package/deploy/sema-up/lib/regcred.py +8 -0
  17. package/deploy/sema-up/lib/remote/helm-install.sh +3 -0
  18. package/deploy/sema-up/lib/remote/image-import.sh +6 -0
  19. package/deploy/sema-up/lib/remote/machine-precheck.sh +11 -0
  20. package/deploy/sema-up/lib/remote/region-probe.sh +3 -0
  21. package/deploy/sema-up/lib/remote/stack-ready.sh +26 -0
  22. package/deploy/sema-up/lib/remote/vxlan-guard.sh +8 -0
  23. package/deploy/sema-up/lib/render-stack.py +17 -0
  24. package/deploy/sema-up/lib/shell-text.sh +87 -0
  25. package/deploy/sema-up/lib/usage-flags.txt +10 -0
  26. package/deploy/sema-up/lib/usage-head.txt +1 -0
  27. package/deploy/sema-up/lib/usage-tail.txt +13 -0
  28. package/deploy/sema-up/preflight.sh +10 -8
  29. package/deploy/sema-up/sema-up.sh +14 -39
  30. package/deploy/sema-up/smoke.sh +7 -6
  31. package/deploy/sema-up/stack/compose.dataroot.yaml +3 -0
  32. package/deploy/sema-up/stack/compose.yaml +13 -1
  33. package/deploy/sema-up/stack/sema-stack-cluster.yaml +21 -0
  34. package/dist/adoption/plan.d.ts +24 -0
  35. package/dist/adoption/plan.js +53 -1
  36. package/dist/adoption/runner.d.ts +10 -1
  37. package/dist/adoption/runner.js +36 -16
  38. package/dist/adoption/wire.d.ts +3 -3
  39. package/dist/approval-card.d.ts +28 -30
  40. package/dist/approval-gate-currency.js +3 -2
  41. package/dist/approval-reconciler.d.ts +4 -13
  42. package/dist/approval-reconciler.js +2 -2
  43. package/dist/approval.d.ts +13 -11
  44. package/dist/approval.js +3 -3
  45. package/dist/audit.d.ts +10 -3
  46. package/dist/audit.js +15 -7
  47. package/dist/auth-bridge.d.ts +0 -14
  48. package/dist/auth-bridge.js +0 -7
  49. package/dist/auto-mode-face.d.ts +10 -7
  50. package/dist/auto-mode-face.js +7 -4
  51. package/dist/background-agent-name.d.ts +19 -1
  52. package/dist/background-agent-name.js +12 -2
  53. package/dist/background-session-reap.d.ts +1 -1
  54. package/dist/bake-runner/main.js +9 -6
  55. package/dist/bench/s1/arms.js +6 -5
  56. package/dist/bench/s1/live-deps.js +5 -2
  57. package/dist/bench/s1/run-firm.js +6 -5
  58. package/dist/bind-host.d.ts +25 -0
  59. package/dist/bind-host.js +25 -0
  60. package/dist/boot/adoption.d.ts +3 -0
  61. package/dist/boot/adoption.js +1 -0
  62. package/dist/boot/deployment-mods.d.ts +1 -1
  63. package/dist/boot/execution-env.d.ts +17 -7
  64. package/dist/boot/execution-env.js +37 -31
  65. package/dist/boot/exit-boundary.d.ts +2 -2
  66. package/dist/boot/exit-boundary.js +6 -5
  67. package/dist/boot/fatal-exit.d.ts +3 -5
  68. package/dist/boot/fatal-exit.js +2 -2
  69. package/dist/boot/leader.d.ts +15 -0
  70. package/dist/boot/leader.js +17 -15
  71. package/dist/boot/memory-consolidation.d.ts +37 -29
  72. package/dist/boot/memory-consolidation.js +11 -5
  73. package/dist/boot/org-memory.js +1 -1
  74. package/dist/boot/parked-revive-gate.js +2 -2
  75. package/dist/boot/reapers.d.ts +4 -3
  76. package/dist/boot/reapers.js +19 -16
  77. package/dist/boot/resolve-spec.d.ts +5 -3
  78. package/dist/boot/resolve-spec.js +55 -67
  79. package/dist/boot/retention-lane.d.ts +4 -4
  80. package/dist/boot/retention-lane.js +2 -2
  81. package/dist/boot/runner-deps.d.ts +28 -7
  82. package/dist/boot/runner-deps.js +11 -4
  83. package/dist/boot/runtime-caps.d.ts +2 -2
  84. package/dist/boot/runtime-caps.js +16 -2
  85. package/dist/boot/session-faces.d.ts +16 -7
  86. package/dist/boot/session-faces.js +114 -94
  87. package/dist/boot/shutdown.d.ts +5 -4
  88. package/dist/boot/shutdown.js +6 -4
  89. package/dist/boot/stage-01-config.js +9 -1
  90. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
  91. package/dist/boot/stage-02-web-admin-pull.js +6 -1
  92. package/dist/boot/stage-03-store-backend.d.ts +3 -0
  93. package/dist/boot/stage-03-store-backend.js +4 -3
  94. package/dist/boot/stage-04-stores.d.ts +2 -0
  95. package/dist/boot/stage-04-stores.js +2 -2
  96. package/dist/boot/stage-05-execution-env.d.ts +7 -3
  97. package/dist/boot/stage-05-execution-env.js +2 -2
  98. package/dist/boot/stage-06-runners.d.ts +10 -12
  99. package/dist/boot/stage-06-runners.js +23 -15
  100. package/dist/boot/stage-07-capability-layer.d.ts +11 -8
  101. package/dist/boot/stage-07-capability-layer.js +5 -3
  102. package/dist/boot/stage-08-reapers.d.ts +11 -8
  103. package/dist/boot/stage-08-reapers.js +3 -3
  104. package/dist/boot/stage-09-leader.d.ts +12 -15
  105. package/dist/boot/stage-09-leader.js +12 -4
  106. package/dist/boot/stage-10-http-server.d.ts +12 -15
  107. package/dist/boot/stage-10-http-server.js +7 -4
  108. package/dist/boot/store-evidence.d.ts +20 -0
  109. package/dist/boot/store-evidence.js +13 -0
  110. package/dist/boot/stores.d.ts +3 -0
  111. package/dist/boot/stores.js +21 -10
  112. package/dist/boot/task-list-lane.d.ts +4 -4
  113. package/dist/boot/web-admin.d.ts +4 -2
  114. package/dist/boot/web-admin.js +55 -35
  115. package/dist/boot/webfetch-summarize-lane.d.ts +1 -1
  116. package/dist/boot-reclaim.d.ts +3 -1
  117. package/dist/boot-reclaim.js +1 -1
  118. package/dist/brain.d.ts +7 -18
  119. package/dist/brain.js +5 -17
  120. package/dist/budget.js +6 -6
  121. package/dist/capabilities/center-plugins.d.ts +7 -1
  122. package/dist/capabilities/center-plugins.js +32 -10
  123. package/dist/capabilities/center-wiring.js +1 -1
  124. package/dist/capabilities/composite-members.d.ts +2 -2
  125. package/dist/capabilities/composite-members.js +2 -2
  126. package/dist/capabilities/repo-tools.d.ts +2 -0
  127. package/dist/capabilities/repo-tools.js +14 -12
  128. package/dist/capabilities/scenarios.d.ts +6 -15
  129. package/dist/capabilities/scenarios.js +11 -16
  130. package/dist/capabilities/skills.d.ts +1 -1
  131. package/dist/capabilities/tool-defer.d.ts +1 -1
  132. package/dist/capability-facts.d.ts +38 -11
  133. package/dist/capability-facts.js +47 -8
  134. package/dist/card-void.d.ts +4 -4
  135. package/dist/card-void.js +1 -1
  136. package/dist/center-credential-renewer.d.ts +6 -2
  137. package/dist/center-credential-renewer.js +7 -3
  138. package/dist/config-catalog.d.ts +16 -1
  139. package/dist/config-catalog.js +62 -56
  140. package/dist/config-dir-trust.d.ts +37 -4
  141. package/dist/config-dir-trust.js +88 -44
  142. package/dist/config-invariants.d.ts +42 -3
  143. package/dist/config-invariants.js +69 -5
  144. package/dist/config-lkg.d.ts +23 -1
  145. package/dist/config-lkg.js +17 -3
  146. package/dist/config-provider.d.ts +9 -9
  147. package/dist/config-provider.js +25 -110
  148. package/dist/config-pull-failure.d.ts +50 -0
  149. package/dist/config-pull-failure.js +48 -0
  150. package/dist/config-types.d.ts +26 -17
  151. package/dist/config.d.ts +8 -16
  152. package/dist/config.js +113 -47
  153. package/dist/delegated-session-owner.d.ts +1 -1
  154. package/dist/deleted-session-ids.d.ts +3 -2
  155. package/dist/deployment-governance.d.ts +3 -3
  156. package/dist/deployment-shape.d.ts +30 -4
  157. package/dist/deployment-shape.js +7 -0
  158. package/dist/egress-redirect.d.ts +25 -7
  159. package/dist/egress-redirect.js +20 -2
  160. package/dist/elicitation.d.ts +6 -5
  161. package/dist/elicitation.js +23 -22
  162. package/dist/engine-identity.d.ts +28 -0
  163. package/dist/engine-identity.js +10 -0
  164. package/dist/entry-problems.d.ts +5 -7
  165. package/dist/entry-problems.js +1 -1
  166. package/dist/env-facts.js +2 -1
  167. package/dist/env-witness.d.ts +7 -0
  168. package/dist/env-witness.js +16 -0
  169. package/dist/execution-lane-caps.d.ts +5 -18
  170. package/dist/execution-lane-caps.js +0 -22
  171. package/dist/execution-placement.d.ts +58 -18
  172. package/dist/execution-placement.js +41 -2
  173. package/dist/field-conflict.d.ts +7 -11
  174. package/dist/field-conflict.js +3 -3
  175. package/dist/file-history-capture.d.ts +3 -3
  176. package/dist/file-history-disclosure.js +1 -0
  177. package/dist/fleet/fleet-bus.d.ts +21 -3
  178. package/dist/fleet/fleet-bus.js +35 -25
  179. package/dist/fleet/fleet-reconciler.js +2 -2
  180. package/dist/fleet/serving-lease.js +3 -3
  181. package/dist/fleet-client.js +3 -3
  182. package/dist/fleet-lease.d.ts +0 -1
  183. package/dist/fleet-lease.js +4 -5
  184. package/dist/history-anchor.d.ts +23 -3
  185. package/dist/history-anchor.js +24 -4
  186. package/dist/hitl-delivery.d.ts +90 -0
  187. package/dist/hitl-delivery.js +98 -0
  188. package/dist/hooks/classic-stations.d.ts +8 -11
  189. package/dist/hooks/classic-stations.js +0 -7
  190. package/dist/hooks/hook-llm.d.ts +5 -1
  191. package/dist/hooks/hook-llm.js +24 -15
  192. package/dist/hooks/hook-runner.d.ts +67 -57
  193. package/dist/hooks/hook-runner.js +260 -186
  194. package/dist/host-lsp-manager.d.ts +22 -8
  195. package/dist/host-lsp-manager.js +4 -1
  196. package/dist/http/active-run-conflict.d.ts +2 -43
  197. package/dist/http/active-run-conflict.js +3 -7
  198. package/dist/http/admission.d.ts +4 -18
  199. package/dist/http/admission.js +75 -78
  200. package/dist/http/approval-sweeps.d.ts +3 -3
  201. package/dist/http/approval-sweeps.js +54 -30
  202. package/dist/http/caller-trust.d.ts +8 -10
  203. package/dist/http/caller-trust.js +1 -2
  204. package/dist/http/claim-heartbeat.d.ts +49 -0
  205. package/dist/http/claim-heartbeat.js +46 -0
  206. package/dist/http/claimed-run.d.ts +4 -3
  207. package/dist/http/dispatch.d.ts +8 -1
  208. package/dist/http/dispatch.js +76 -30
  209. package/dist/http/durable-run-leg.d.ts +3 -3
  210. package/dist/http/durable-run-leg.js +17 -12
  211. package/dist/http/execution-context.d.ts +17 -43
  212. package/dist/http/execution-context.js +7 -5
  213. package/dist/http/health-reader.d.ts +36 -0
  214. package/dist/http/health-reader.js +21 -0
  215. package/dist/http/health-self-report.d.ts +9 -9
  216. package/dist/http/health-self-report.js +4 -4
  217. package/dist/http/idempotency.d.ts +9 -5
  218. package/dist/http/idempotency.js +4 -4
  219. package/dist/http/memory-compliance-failure-reply.d.ts +15 -16
  220. package/dist/http/memory-compliance-failure-reply.js +4 -2
  221. package/dist/http/memory-face-fault-reply.d.ts +67 -0
  222. package/dist/http/memory-face-fault-reply.js +71 -0
  223. package/dist/http/memory-store-refusal-reply.d.ts +1 -1
  224. package/dist/http/memory-store-refusal-reply.js +3 -0
  225. package/dist/http/owner-access.d.ts +391 -67
  226. package/dist/http/owner-access.js +371 -35
  227. package/dist/http/principal-gate.d.ts +24 -81
  228. package/dist/http/principal-gate.js +24 -68
  229. package/dist/http/refusal-body.d.ts +35 -2
  230. package/dist/http/refusal-body.js +34 -0
  231. package/dist/http/request-guards.d.ts +9 -13
  232. package/dist/http/request-guards.js +34 -68
  233. package/dist/http/resume-composition.d.ts +37 -0
  234. package/dist/http/resume-composition.js +18 -0
  235. package/dist/http/resume-ctx-read.d.ts +35 -12
  236. package/dist/http/resume-ctx-read.js +25 -6
  237. package/dist/http/resume-legs.d.ts +21 -18
  238. package/dist/http/resume-legs.js +189 -129
  239. package/dist/http/retired-skill-manifest.d.ts +1 -1
  240. package/dist/http/route-ctx.d.ts +25 -32
  241. package/dist/http/routes/a2a-serve.d.ts +43 -5
  242. package/dist/http/routes/a2a-serve.js +58 -37
  243. package/dist/http/routes/admin-config-refresh.js +2 -2
  244. package/dist/http/routes/admin-drain.js +2 -2
  245. package/dist/http/routes/admin-memory-optout.js +4 -3
  246. package/dist/http/routes/adoption.d.ts +3 -0
  247. package/dist/http/routes/adoption.js +17 -10
  248. package/dist/http/routes/agents-roster.js +13 -7
  249. package/dist/http/routes/approvals-assistant.js +70 -65
  250. package/dist/http/routes/attachments.js +2 -2
  251. package/dist/http/routes/background.d.ts +3 -3
  252. package/dist/http/routes/background.js +9 -17
  253. package/dist/http/routes/capabilities.js +15 -18
  254. package/dist/http/routes/config-catalog.js +2 -2
  255. package/dist/http/routes/devices.d.ts +3 -3
  256. package/dist/http/routes/devices.js +4 -4
  257. package/dist/http/routes/diagnostics.d.ts +27 -3
  258. package/dist/http/routes/diagnostics.js +27 -21
  259. package/dist/http/routes/engine.js +2 -2
  260. package/dist/http/routes/fleet.js +5 -3
  261. package/dist/http/routes/images.js +10 -6
  262. package/dist/http/routes/leader.d.ts +7 -2
  263. package/dist/http/routes/leader.js +12 -3
  264. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  265. package/dist/http/routes/mcp-reconnect.js +7 -15
  266. package/dist/http/routes/memory-bundle.js +4 -7
  267. package/dist/http/routes/memory-compliance.js +4 -4
  268. package/dist/http/routes/memory-consolidation.js +6 -9
  269. package/dist/http/routes/memory-origin.d.ts +2 -0
  270. package/dist/http/routes/memory-origin.js +7 -8
  271. package/dist/http/routes/memory-policy.js +17 -12
  272. package/dist/http/routes/notify-wake.js +10 -19
  273. package/dist/http/routes/observability.js +3 -3
  274. package/dist/http/routes/principal-inbox.d.ts +1 -1
  275. package/dist/http/routes/principal-inbox.js +2 -2
  276. package/dist/http/routes/projects.d.ts +1 -1
  277. package/dist/http/routes/projects.js +3 -2
  278. package/dist/http/routes/retention-ops.js +6 -9
  279. package/dist/http/routes/rules.js +20 -5
  280. package/dist/http/routes/run-memory-capture.d.ts +2 -2
  281. package/dist/http/routes/run-memory-capture.js +6 -12
  282. package/dist/http/routes/run-permission-mode.d.ts +2 -2
  283. package/dist/http/routes/run-permission-mode.js +10 -17
  284. package/dist/http/routes/runs.js +146 -231
  285. package/dist/http/routes/session-memory-sync.d.ts +2 -2
  286. package/dist/http/routes/session-memory-sync.js +7 -13
  287. package/dist/http/routes/session-sync.d.ts +4 -2
  288. package/dist/http/routes/session-sync.js +21 -20
  289. package/dist/http/routes/sessions-list.d.ts +3 -3
  290. package/dist/http/routes/sessions-list.js +9 -9
  291. package/dist/http/routes/sessions.js +87 -124
  292. package/dist/http/routes/shared-memory.js +6 -6
  293. package/dist/http/routes/side-query.js +2 -2
  294. package/dist/http/routes/tasks.js +136 -120
  295. package/dist/http/routes/trace-usage.d.ts +0 -12
  296. package/dist/http/routes/trace-usage.js +40 -46
  297. package/dist/http/routes/workflows.d.ts +39 -4
  298. package/dist/http/routes/workflows.js +42 -14
  299. package/dist/http/run-concurrency-cap.d.ts +20 -12
  300. package/dist/http/run-concurrency-cap.js +39 -26
  301. package/dist/http/run-read-face.d.ts +3 -5
  302. package/dist/http/run-read-face.js +8 -13
  303. package/dist/http/send.d.ts +12 -3
  304. package/dist/http/send.js +42 -6
  305. package/dist/http/server.d.ts +39 -40
  306. package/dist/http/server.js +36 -11
  307. package/dist/http/sse-log.d.ts +17 -10
  308. package/dist/http/sse-log.js +7 -7
  309. package/dist/http/stored-body-replay.d.ts +12 -0
  310. package/dist/http/stored-body-replay.js +2 -2
  311. package/dist/http/submit-ctx.d.ts +16 -8
  312. package/dist/http/submit-ctx.js +6 -2
  313. package/dist/http/submit-replay.d.ts +19 -6
  314. package/dist/http/submit-replay.js +18 -6
  315. package/dist/http/sync-submit-body.d.ts +3 -4
  316. package/dist/http/sync-submit-body.js +4 -5
  317. package/dist/http/wire-types.d.ts +4 -3
  318. package/dist/identity-source.d.ts +36 -5
  319. package/dist/identity-source.js +27 -0
  320. package/dist/index.d.ts +1 -0
  321. package/dist/index.js +1 -0
  322. package/dist/key-resolver.d.ts +32 -0
  323. package/dist/key-resolver.js +23 -9
  324. package/dist/leader/diffup.js +2 -1
  325. package/dist/leader/endpoint.d.ts +26 -5
  326. package/dist/leader/endpoint.js +154 -14
  327. package/dist/leader/fanout.d.ts +3 -0
  328. package/dist/leader/fanout.js +78 -63
  329. package/dist/leader/leader.d.ts +16 -0
  330. package/dist/leader/leader.js +43 -3
  331. package/dist/leader/merge.d.ts +9 -1
  332. package/dist/leader/merge.js +16 -1
  333. package/dist/leader/repair-wire.js +1 -1
  334. package/dist/leader/wire.d.ts +36 -3
  335. package/dist/leader/wire.js +59 -18
  336. package/dist/lsp-evict.d.ts +6 -4
  337. package/dist/lsp-evict.js +2 -3
  338. package/dist/memory-operator-faces.d.ts +5 -4
  339. package/dist/memory-operator-faces.js +1 -1
  340. package/dist/memory-scope.d.ts +29 -2
  341. package/dist/memory-scope.js +64 -15
  342. package/dist/memory-store-refusal.d.ts +5 -2
  343. package/dist/memory-sync-client.d.ts +3 -2
  344. package/dist/memory-sync-client.js +6 -3
  345. package/dist/model-compat.d.ts +17 -8
  346. package/dist/model-compat.js +6 -2
  347. package/dist/model-context-window.d.ts +18 -0
  348. package/dist/model-context-window.js +2 -0
  349. package/dist/model-entry-headers.d.ts +46 -4
  350. package/dist/model-entry-headers.js +2 -2
  351. package/dist/model-entry-refusal.d.ts +35 -16
  352. package/dist/model-entry-refusal.js +40 -27
  353. package/dist/model-plane-face.d.ts +19 -11
  354. package/dist/model-plane-face.js +9 -1
  355. package/dist/model-plane-probe.d.ts +2 -0
  356. package/dist/model-plane-probe.js +17 -0
  357. package/dist/model-provider.d.ts +3 -3
  358. package/dist/model-route-endpoint.d.ts +9 -5
  359. package/dist/model-route-endpoint.js +29 -7
  360. package/dist/model-select.d.ts +16 -0
  361. package/dist/model-select.js +4 -0
  362. package/dist/mountinfo.d.ts +37 -0
  363. package/dist/mountinfo.js +47 -0
  364. package/dist/namespaced-rule-name.d.ts +23 -14
  365. package/dist/namespaced-rule-name.js +8 -11
  366. package/dist/net-address.d.ts +1 -1
  367. package/dist/observability/corrupt-read-seat.d.ts +4 -4
  368. package/dist/observability/corrupt-read-seat.js +5 -3
  369. package/dist/observability/fail-open.d.ts +58 -38
  370. package/dist/observability/fail-open.js +60 -38
  371. package/dist/observability/logger.d.ts +22 -1
  372. package/dist/observability/logger.js +89 -12
  373. package/dist/observability/metrics.js +3 -4
  374. package/dist/observability/otel-exporter.js +2 -1
  375. package/dist/observability/principal-context.d.ts +14 -7
  376. package/dist/observability/principal-context.js +8 -3
  377. package/dist/observability/run-terminal.d.ts +7 -1
  378. package/dist/observability/run-terminal.js +5 -2
  379. package/dist/orchestration/hardened-vm-runner.d.ts +1 -0
  380. package/dist/orchestration/hardened-vm-runner.js +11 -5
  381. package/dist/orchestration/hardened-vm-worker-runner.d.ts +0 -14
  382. package/dist/orchestration/hardened-vm-worker-runner.js +5 -0
  383. package/dist/orchestration/hardened-vm-worker.js +2 -1
  384. package/dist/orchestration/workflow-completion-inbox.d.ts +3 -3
  385. package/dist/orchestration/workflow-completion-inbox.js +3 -2
  386. package/dist/org-delivery-gate.d.ts +5 -4
  387. package/dist/org-delivery-gate.js +7 -6
  388. package/dist/outbound-dispatcher.d.ts +1 -1
  389. package/dist/outbound-dispatcher.js +6 -12
  390. package/dist/owner-brands.d.ts +81 -0
  391. package/dist/owner-brands.js +42 -0
  392. package/dist/owner-faces.d.ts +531 -0
  393. package/dist/owner-faces.js +126 -0
  394. package/dist/parked-decide.d.ts +67 -5
  395. package/dist/parked-decide.js +127 -5
  396. package/dist/parked-revive-surface.d.ts +14 -4
  397. package/dist/parked-revive-surface.js +5 -4
  398. package/dist/peer-directory.d.ts +6 -8
  399. package/dist/peer-directory.js +3 -2
  400. package/dist/permission-rule-vocab.d.ts +53 -8
  401. package/dist/permission-rule-vocab.js +30 -2
  402. package/dist/plugins/adoption-log-sql.d.ts +0 -22
  403. package/dist/plugins/adoption-log-sql.js +5 -3
  404. package/dist/plugins/approval-ask-retired-delete-by-task-m50.d.ts +7 -0
  405. package/dist/plugins/approval-ask-retired-delete-by-task-m50.js +17 -0
  406. package/dist/plugins/approval-ask-store-file.d.ts +18 -7
  407. package/dist/plugins/approval-ask-store-file.js +37 -14
  408. package/dist/plugins/approval-ask-store-memory.d.ts +12 -4
  409. package/dist/plugins/approval-ask-store-memory.js +24 -10
  410. package/dist/plugins/approval-ask-store-sql.d.ts +39 -20
  411. package/dist/plugins/approval-ask-store-sql.js +41 -10
  412. package/dist/plugins/approval-exemption-skill-m46.d.ts +20 -0
  413. package/dist/plugins/approval-exemption-skill-m46.js +25 -0
  414. package/dist/plugins/approval-exemption-store.d.ts +6 -1
  415. package/dist/plugins/approval-exemption-store.js +14 -0
  416. package/dist/plugins/approval-nonce-store.d.ts +39 -12
  417. package/dist/plugins/approval-nonce-store.js +72 -23
  418. package/dist/plugins/blob-backend.d.ts +2 -0
  419. package/dist/plugins/blob-backend.js +9 -6
  420. package/dist/plugins/caching-session-store.d.ts +13 -1
  421. package/dist/plugins/caching-session-store.js +43 -4
  422. package/dist/plugins/checkpoint-index-columns.d.ts +32 -5
  423. package/dist/plugins/checkpoint-index-columns.js +36 -1
  424. package/dist/plugins/checkpoint-store-face.d.ts +83 -10
  425. package/dist/plugins/checkpoint-store-face.js +18 -1
  426. package/dist/plugins/device-store-sql.js +1 -0
  427. package/dist/plugins/ensure-index.d.ts +13 -1
  428. package/dist/plugins/ensure-index.js +154 -21
  429. package/dist/plugins/ensure-schema-lock-policy.d.ts +0 -15
  430. package/dist/plugins/ensure-schema-lock-policy.js +3 -2
  431. package/dist/plugins/file-run-store.d.ts +63 -23
  432. package/dist/plugins/file-run-store.js +138 -83
  433. package/dist/plugins/host-platform.d.ts +24 -3
  434. package/dist/plugins/host-platform.js +15 -1
  435. package/dist/plugins/image-bake-store-sql.js +2 -0
  436. package/dist/plugins/imported-layer-root-retirement.d.ts +2 -2
  437. package/dist/plugins/k8s-pod-reaper.d.ts +1 -3
  438. package/dist/plugins/k8s-pod-reaper.js +0 -1
  439. package/dist/plugins/leader-run-store-sql.d.ts +22 -0
  440. package/dist/plugins/leader-run-store-sql.js +34 -4
  441. package/dist/plugins/local-checkpoint-store.d.ts +58 -23
  442. package/dist/plugins/local-checkpoint-store.js +195 -76
  443. package/dist/plugins/local-data-dir-modes-m39.js +2 -1
  444. package/dist/plugins/local-docker-capacity.d.ts +93 -0
  445. package/dist/plugins/local-docker-capacity.js +194 -0
  446. package/dist/plugins/local-docker-reaper.d.ts +92 -0
  447. package/dist/plugins/local-docker-reaper.js +102 -0
  448. package/dist/plugins/local-engine-high-water.d.ts +4 -2
  449. package/dist/plugins/local-engine-high-water.js +4 -1
  450. package/dist/plugins/local-session-store.d.ts +358 -125
  451. package/dist/plugins/local-session-store.js +824 -251
  452. package/dist/plugins/local-session-window.d.ts +3 -2
  453. package/dist/plugins/local-session-window.js +3 -2
  454. package/dist/plugins/local-sidecar-quarantine.js +3 -2
  455. package/dist/plugins/local-task-attachment-store.d.ts +18 -1
  456. package/dist/plugins/local-task-attachment-store.js +22 -1
  457. package/dist/plugins/memory-embedder.js +9 -7
  458. package/dist/plugins/memory-engine-pg.d.ts +3 -2
  459. package/dist/plugins/memory-engine-pg.js +14 -5
  460. package/dist/plugins/memory-engine-sql-apply.d.ts +8 -4
  461. package/dist/plugins/memory-engine-sql-apply.js +6 -8
  462. package/dist/plugins/memory-engine-tidb.d.ts +4 -2
  463. package/dist/plugins/memory-engine-tidb.js +11 -2
  464. package/dist/plugins/memory-optout-grant-store-sql.d.ts +1 -1
  465. package/dist/plugins/memory-optout-grant-store-sql.js +3 -3
  466. package/dist/plugins/memory-run-store.d.ts +39 -27
  467. package/dist/plugins/memory-run-store.js +72 -70
  468. package/dist/plugins/one-time-migration-marker.d.ts +10 -0
  469. package/dist/plugins/one-time-migration-marker.js +7 -0
  470. package/dist/plugins/one-time-migrations.d.ts +186 -45
  471. package/dist/plugins/one-time-migrations.js +442 -119
  472. package/dist/plugins/org-delivery-quota-store.js +2 -1
  473. package/dist/plugins/permission-rule-store-file.d.ts +3 -3
  474. package/dist/plugins/permission-rule-store-sql.d.ts +4 -63
  475. package/dist/plugins/permission-rule-store-sql.js +6 -86
  476. package/dist/plugins/pg-pool.d.ts +1 -31
  477. package/dist/plugins/pg-pool.js +16 -7
  478. package/dist/plugins/remote-env-e2b.d.ts +7 -25
  479. package/dist/plugins/remote-env-e2b.js +34 -25
  480. package/dist/plugins/remote-env-host.d.ts +2 -9
  481. package/dist/plugins/remote-env-host.js +34 -22
  482. package/dist/plugins/remote-env-k8s.d.ts +40 -45
  483. package/dist/plugins/remote-env-k8s.js +107 -58
  484. package/dist/plugins/remote-env-local-docker.d.ts +148 -14
  485. package/dist/plugins/remote-env-local-docker.js +367 -72
  486. package/dist/plugins/remote-scratchpad.js +4 -0
  487. package/dist/plugins/retention-deployment.d.ts +49 -17
  488. package/dist/plugins/retention-deployment.js +39 -8
  489. package/dist/plugins/run-preview-m45.d.ts +11 -0
  490. package/dist/plugins/run-preview-m45.js +19 -0
  491. package/dist/plugins/run-store-sql.d.ts +56 -68
  492. package/dist/plugins/run-store-sql.js +127 -116
  493. package/dist/plugins/s3-answer.d.ts +2 -1
  494. package/dist/plugins/sandbox-reaper.d.ts +26 -0
  495. package/dist/plugins/sandbox-reaper.js +2 -0
  496. package/dist/plugins/scenario-prefix-switch-m42.d.ts +54 -0
  497. package/dist/plugins/scenario-prefix-switch-m42.js +55 -0
  498. package/dist/plugins/scheduler-support.d.ts +16 -1
  499. package/dist/plugins/scheduler-support.js +22 -2
  500. package/dist/plugins/schema-consistency.d.ts +42 -9
  501. package/dist/plugins/schema-consistency.js +212 -11
  502. package/dist/plugins/schema-drift-sentence.d.ts +4 -1
  503. package/dist/plugins/schema-drift-sentence.js +4 -4
  504. package/dist/plugins/schema-ensure-legs.d.ts +9 -0
  505. package/dist/plugins/schema-ensure-legs.js +1 -1
  506. package/dist/plugins/schema-indexes.js +3 -0
  507. package/dist/plugins/schema-live-columns.d.ts +14 -5
  508. package/dist/plugins/schema-live-columns.js +10 -10
  509. package/dist/plugins/send-user-file.js +2 -1
  510. package/dist/plugins/session-birth.d.ts +37 -0
  511. package/dist/plugins/session-birth.js +38 -0
  512. package/dist/plugins/session-epoch-anchor.d.ts +40 -12
  513. package/dist/plugins/session-epoch-anchor.js +33 -11
  514. package/dist/plugins/session-ext-table.d.ts +27 -3
  515. package/dist/plugins/session-ext-table.js +19 -6
  516. package/dist/plugins/session-fork.d.ts +15 -1
  517. package/dist/plugins/session-fork.js +3 -0
  518. package/dist/plugins/session-ownership.d.ts +1 -1
  519. package/dist/plugins/session-placement.d.ts +22 -16
  520. package/dist/plugins/session-placement.js +15 -12
  521. package/dist/plugins/session-row-sql.d.ts +12 -0
  522. package/dist/plugins/session-row-sql.js +3 -3
  523. package/dist/plugins/session-run-rollup.d.ts +29 -0
  524. package/dist/plugins/session-run-rollup.js +40 -0
  525. package/dist/plugins/session-store-sql.d.ts +38 -12
  526. package/dist/plugins/session-store-sql.js +130 -30
  527. package/dist/plugins/session-withdraw-sql.d.ts +36 -0
  528. package/dist/plugins/session-withdraw-sql.js +42 -0
  529. package/dist/plugins/shared-memory-store-sql.d.ts +0 -69
  530. package/dist/plugins/shared-memory-store-sql.js +2 -1
  531. package/dist/plugins/shell-sentinel-owner-m48.d.ts +20 -0
  532. package/dist/plugins/shell-sentinel-owner-m48.js +3 -0
  533. package/dist/plugins/snapshot-bucket-presence.d.ts +2 -1
  534. package/dist/plugins/sql-driver.d.ts +1 -1
  535. package/dist/plugins/sql-driver.js +2 -1
  536. package/dist/plugins/sql-errors.d.ts +32 -5
  537. package/dist/plugins/sql-errors.js +55 -7
  538. package/dist/plugins/sql-json-column.d.ts +8 -7
  539. package/dist/plugins/sql-json-column.js +10 -6
  540. package/dist/plugins/store-backend.d.ts +84 -15
  541. package/dist/plugins/store-backend.js +186 -55
  542. package/dist/plugins/store-contracts.d.ts +90 -30
  543. package/dist/plugins/store-contracts.js +22 -1
  544. package/dist/plugins/store-fault.d.ts +28 -2
  545. package/dist/plugins/store-fault.js +20 -2
  546. package/dist/plugins/task-attachment-store.d.ts +15 -3
  547. package/dist/plugins/task-attachment-store.js +22 -9
  548. package/dist/plugins/tidb-pool.js +23 -8
  549. package/dist/plugins/web-search.js +5 -3
  550. package/dist/plugins/workflow-run-store-sql.d.ts +6 -1
  551. package/dist/plugins/workflow-run-store-sql.js +11 -5
  552. package/dist/principal-jwt.d.ts +4 -4
  553. package/dist/principal-jwt.js +20 -5
  554. package/dist/principal-shape.d.ts +41 -0
  555. package/dist/principal-shape.js +19 -0
  556. package/dist/question.d.ts +13 -23
  557. package/dist/question.js +21 -39
  558. package/dist/request-declaration-refusal.d.ts +35 -12
  559. package/dist/request-declaration-refusal.js +21 -9
  560. package/dist/request-form.d.ts +58 -0
  561. package/dist/request-form.js +72 -0
  562. package/dist/request-image-urls.d.ts +8 -2
  563. package/dist/request-image-urls.js +2 -1
  564. package/dist/request-images.d.ts +20 -0
  565. package/dist/request-images.js +59 -0
  566. package/dist/request-key-closure.d.ts +6 -7
  567. package/dist/request-key-closure.js +15 -2
  568. package/dist/resource-suspend.d.ts +7 -16
  569. package/dist/resource-suspend.js +1 -1
  570. package/dist/retired-name-host-notice.d.ts +21 -0
  571. package/dist/retired-name-host-notice.js +12 -0
  572. package/dist/rule-entry-list.d.ts +2 -2
  573. package/dist/rule-entry-list.js +3 -4
  574. package/dist/rule-issue-reading.d.ts +58 -0
  575. package/dist/rule-issue-reading.js +14 -0
  576. package/dist/rules-consent.d.ts +5 -3
  577. package/dist/rules-consent.js +1 -0
  578. package/dist/run-acceptance.d.ts +3 -1
  579. package/dist/run-acceptance.js +3 -0
  580. package/dist/run-local.d.ts +14 -6
  581. package/dist/run-local.js +92 -80
  582. package/dist/run-stale-default.d.ts +7 -0
  583. package/dist/run-stale-default.js +2 -0
  584. package/dist/runs.d.ts +26 -15
  585. package/dist/runs.js +39 -27
  586. package/dist/runtime-caps-resolver.d.ts +21 -6
  587. package/dist/runtime-caps-resolver.js +17 -4
  588. package/dist/runtime-governance.d.ts +2 -2
  589. package/dist/runtime-governance.js +5 -3
  590. package/dist/sealed-key-layout.d.ts +12 -5
  591. package/dist/sealed-key-layout.js +5 -0
  592. package/dist/sealed-key.d.ts +12 -2
  593. package/dist/sealed-key.js +115 -27
  594. package/dist/security.d.ts +128 -158
  595. package/dist/security.js +163 -59
  596. package/dist/sema-config-dir.d.ts +20 -0
  597. package/dist/sema-config-dir.js +25 -0
  598. package/dist/server-secret-env.d.ts +21 -5
  599. package/dist/server-secret-env.js +14 -4
  600. package/dist/session-children-retire.d.ts +7 -5
  601. package/dist/session-children-retire.js +7 -2
  602. package/dist/session-deletion.d.ts +88 -0
  603. package/dist/session-deletion.js +8 -0
  604. package/dist/session-erase.d.ts +145 -0
  605. package/dist/session-erase.js +115 -0
  606. package/dist/session-error-wire.d.ts +5 -5
  607. package/dist/session-error-wire.js +1 -1
  608. package/dist/session-incarnation.d.ts +52 -5
  609. package/dist/session-incarnation.js +19 -2
  610. package/dist/session-policy-wire.d.ts +6 -3
  611. package/dist/session-policy-wire.js +11 -1
  612. package/dist/session-resident-background.d.ts +0 -71
  613. package/dist/session-resident-background.js +4 -3
  614. package/dist/session-row.d.ts +2 -1
  615. package/dist/session-rules-seat.d.ts +12 -0
  616. package/dist/session-rules-seat.js +19 -0
  617. package/dist/session-titler.d.ts +7 -15
  618. package/dist/session-titler.js +1 -1
  619. package/dist/spec-fields.d.ts +57 -3
  620. package/dist/spec-fields.js +72 -51
  621. package/dist/store-posture.d.ts +136 -20
  622. package/dist/store-posture.js +188 -3
  623. package/dist/stored-request-hooks-m20.js +2 -2
  624. package/dist/stores-sql/background-agent-store-sql.d.ts +11 -2
  625. package/dist/stores-sql/background-agent-store-sql.js +73 -20
  626. package/dist/stores-sql/checkpoint-store-sql.d.ts +33 -28
  627. package/dist/stores-sql/checkpoint-store-sql.js +75 -44
  628. package/dist/stores-sql/mailbox-store-sql.d.ts +7 -4
  629. package/dist/stores-sql/mailbox-store-sql.js +31 -32
  630. package/dist/stores-sql/pg-session-storage.d.ts +7 -5
  631. package/dist/stores-sql/pg-session-storage.js +54 -46
  632. package/dist/stores-sql/retention-store-sql.d.ts +87 -19
  633. package/dist/stores-sql/retention-store-sql.js +92 -27
  634. package/dist/stores-sql/session-policy-store-sql.d.ts +32 -10
  635. package/dist/stores-sql/session-policy-store-sql.js +44 -36
  636. package/dist/stores-sql/session-write-hooks.d.ts +12 -6
  637. package/dist/stores-sql/tidb-session-storage.d.ts +4 -4
  638. package/dist/stores-sql/tidb-session-storage.js +13 -8
  639. package/dist/stores-sql/tidb-session-store.d.ts +36 -17
  640. package/dist/stores-sql/tidb-session-store.js +69 -39
  641. package/dist/stores-sql/windowed-session-storage.d.ts +5 -0
  642. package/dist/stores-sql/windowed-session-storage.js +9 -0
  643. package/dist/submission-exit.d.ts +50 -0
  644. package/dist/submission-exit.js +108 -0
  645. package/dist/task-a2a.d.ts +1 -1
  646. package/dist/task-a2a.js +3 -3
  647. package/dist/task-cwd.d.ts +20 -0
  648. package/dist/task-cwd.js +8 -0
  649. package/dist/task-mcp.d.ts +1 -1
  650. package/dist/task-mcp.js +3 -3
  651. package/dist/task-settings.d.ts +14 -10
  652. package/dist/task-settings.js +18 -7
  653. package/dist/terminal.d.ts +25 -43
  654. package/dist/terminal.js +31 -11
  655. package/dist/tool-approval.d.ts +131 -129
  656. package/dist/tool-approval.js +189 -193
  657. package/dist/trace/core-keyset-guard.d.ts +13 -6
  658. package/dist/trace/core-vocab-wire.d.ts +95 -0
  659. package/dist/trace/core-vocab-wire.js +15 -0
  660. package/dist/trace/exit-seat.d.ts +30 -4
  661. package/dist/trace/exit-seat.js +40 -36
  662. package/dist/trace/extension-call-face.d.ts +3 -2
  663. package/dist/trace/extension-call-face.js +3 -1
  664. package/dist/trace/ledger-events.d.ts +4 -7
  665. package/dist/trace/ledger-sink.d.ts +1 -30
  666. package/dist/trace/ledger-sink.js +0 -11
  667. package/dist/trace/model-segment.d.ts +5 -5
  668. package/dist/trace/model-segment.js +5 -5
  669. package/dist/trace/project.d.ts +55 -42
  670. package/dist/trace/project.js +52 -19
  671. package/dist/trace/redact.d.ts +123 -27
  672. package/dist/trace/redact.js +880 -260
  673. package/dist/trace/self-minted-wire.d.ts +487 -19
  674. package/dist/trace/self-minted-wire.js +172 -23
  675. package/dist/trace/wire-projection-faces.d.ts +5 -6
  676. package/dist/trace/wire-projection-faces.js +2 -2
  677. package/dist/upstream-body.d.ts +23 -0
  678. package/dist/upstream-body.js +16 -0
  679. package/dist/url-refusal.d.ts +3 -3
  680. package/dist/url-refusal.js +11 -4
  681. package/dist/user-authored-text.d.ts +1 -1
  682. package/dist/user-input-ledger.d.ts +7 -8
  683. package/dist/user-input-ledger.js +1 -1
  684. package/dist/web-admin-client/apply-effective.d.ts +6 -3
  685. package/dist/web-admin-client/apply-effective.js +13 -16
  686. package/dist/web-admin-client/apply-ledger.d.ts +16 -7
  687. package/dist/web-admin-client/apply-ledger.js +5 -2
  688. package/dist/web-admin-client/center-request.d.ts +2 -2
  689. package/dist/web-admin-client/center-request.js +15 -15
  690. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  691. package/dist/web-admin-client/effective-keys.js +1 -1
  692. package/dist/web-admin-client/entry-metadata.d.ts +8 -0
  693. package/dist/web-admin-client/entry-metadata.js +13 -0
  694. package/dist/web-admin-client/http-client.d.ts +1 -1
  695. package/dist/web-admin-client/http-client.js +23 -4
  696. package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
  697. package/dist/web-admin-client/mcp-revocation.js +2 -1
  698. package/dist/web-admin-client/read-warnings.d.ts +1 -0
  699. package/dist/web-admin-client/read-warnings.js +1 -0
  700. package/dist/web-admin-client/restart-signal.js +8 -4
  701. package/dist/web-admin-client/skills-mcp.d.ts +2 -2
  702. package/dist/web-admin-client/types.d.ts +1 -2
  703. package/dist/workspace-space.d.ts +3 -2
  704. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +4 -4
  705. package/package.json +6 -3
  706. package/scripts/drain-check-local.mjs +118 -147
  707. package/scripts/drain-check.mysql.sql +22 -2
  708. package/scripts/drain-check.pg.sql +22 -2
  709. package/wire-changes/server@7.148.0.json +1517 -0
  710. package/dist/http/memory-control-plane-corrupt-reply.d.ts +0 -25
  711. package/dist/http/memory-control-plane-corrupt-reply.js +0 -19
  712. package/dist/http/memory-layer-reply.d.ts +0 -30
  713. package/dist/http/memory-layer-reply.js +0 -24
  714. package/dist/lsp/e2b-bridge.d.ts +0 -57
  715. package/dist/lsp/e2b-bridge.js +0 -139
  716. package/dist/lsp/e2b-manager.d.ts +0 -93
  717. package/dist/lsp/e2b-manager.js +0 -178
  718. package/dist/lsp/lsp-frames.d.ts +0 -14
  719. package/dist/lsp/lsp-frames.js +0 -25
  720. package/dist/lsp/manager.d.ts +0 -129
  721. package/dist/lsp/manager.js +0 -127
  722. package/dist/lsp/types.d.ts +0 -12
  723. package/dist/lsp/types.js +0 -2
  724. package/dist/lsp/ws-transport.d.ts +0 -40
  725. package/dist/lsp/ws-transport.js +0 -210
@@ -1,8 +1,9 @@
1
- import { join } from "node:path";
1
+ import { dirname, join } from "node:path";
2
2
  import { randomBytes, createHash } from "node:crypto";
3
- import { SchedulerError, isValidCronExpr } from "@sema-agent/core";
3
+ import { SchedulerError, ensureDir, isValidCronExpr } from "@sema-agent/core";
4
4
  import { loadSchedulerStore, mutateSchedulerStore } from "@sema-agent/settings-schema/node";
5
5
  import { configRootOf } from "../sema-config-dir.js";
6
+ import { trustedFileRefusal } from "../config-dir-trust.js";
6
7
  const ok = (value) => ({ ok: true, value });
7
8
  const err = (error) => ({ ok: false, error });
8
9
  export const DEFAULT_SCHEDULER_CAPS = {
@@ -89,12 +90,21 @@ export class FileSchedulerBackend {
89
90
  storePath;
90
91
  now;
91
92
  log;
93
+ trust;
92
94
  constructor(opts) {
93
95
  this.schedulerCapabilities = { ...DEFAULT_SCHEDULER_CAPS, ...(opts.caps ?? {}) };
94
96
  this.storePath = opts.storePath;
95
97
  this.log = opts.log;
98
+ this.trust = opts.trust;
96
99
  this.now = opts.now ?? (() => Date.now());
97
100
  }
101
+ async untrustedStore() {
102
+ const refusal = await trustedFileRefusal({ reader: "scheduler-store", file: this.storePath, declaredOwnerUid: this.trust.declaredOwnerUid, ...(this.trust.host !== undefined ? { host: this.trust.host } : {}) });
103
+ if (refusal === undefined)
104
+ return undefined;
105
+ this.log.warn("scheduler_store_untrusted", { path: this.storePath, refusal, note: "the scheduled-task store can be changed by another user — this read / write was refused and nothing was written; the refusal names the path and the fix" });
106
+ return new SchedulerError("io", "the scheduled-task store is not trusted (another user could change it) — nothing was read or written; the operator log names the path and the fix");
107
+ }
98
108
  mutate(fn, what) {
99
109
  let result;
100
110
  let produced = false;
@@ -135,6 +145,10 @@ export class FileSchedulerBackend {
135
145
  if (intent.lifetime === "session" && this.schedulerCapabilities.supportsSessionLifetime === false) {
136
146
  return err(new SchedulerError("invalid_schedule", 'lifetime:"session" is not supported on this deployment (no resident daemon reaps session-lifetime records — the row would be an orphan)'));
137
147
  }
148
+ const untrusted = await this.untrustedStore();
149
+ if (untrusted)
150
+ return err(untrusted);
151
+ ensureDir(dirname(this.storePath));
138
152
  const key = dedupKey(ctx.scope, intent, ctx.sessionId);
139
153
  const decided = this.mutate((records) => {
140
154
  const existingIdx = records.findIndex((r) => {
@@ -166,6 +180,9 @@ export class FileSchedulerBackend {
166
180
  return decided.ok ? decided.value : decided;
167
181
  }
168
182
  async cancel(id, ctx) {
183
+ const untrusted = await this.untrustedStore();
184
+ if (untrusted)
185
+ return err(untrusted);
169
186
  const decided = this.mutate((records) => {
170
187
  const idx = records.findIndex((r) => r.id === id);
171
188
  if (idx < 0 || records[idx].scope !== ctx.scope) {
@@ -176,6 +193,9 @@ export class FileSchedulerBackend {
176
193
  return decided.ok ? decided.value : decided;
177
194
  }
178
195
  async list(ctx) {
196
+ const untrusted = await this.untrustedStore();
197
+ if (untrusted)
198
+ return err(untrusted);
179
199
  let read;
180
200
  try {
181
201
  read = loadSchedulerStore(this.storePath, { nowMs: this.now() });
@@ -26,6 +26,16 @@
26
26
  * 半径远大于本批;先解析文本,理由写在这里。)拒启文案里的那句 `ALTER TABLE … ADD COLUMN …` 也由
27
27
  * **同一份解析结果**生成,不是手写的。
28
28
  *
29
+ * ── 第二问:声明非空而库里允许 NULL(tightened)─────────────────────────────────────────────────────
30
+ * 缺列的拒句给的是 `ALTER TABLE … ADD COLUMN <原文>`;对「声明 `NOT NULL`、没有缺省、不是键」的列,那一句原文在已有行的表上会被引擎拒(PG)或写进隐式缺省(MySQL 非严格),
31
+ * 部署者于是把列加成**可空**——只列名对账从此转绿,而存量行在这一列上是 NULL,本构建按非空读它。所以对账多问一件事,**一条谓词**:本构建声明非空的列
32
+ * (顶层 `NOT NULL`,或主键成员)在库里是否也非空;库里允许 NULL ⇒ 拒,并给出收紧的下一步。谓词不分类;**配方**按同一张分类表({@link columnFill})给:
33
+ * · `self` —— 引擎自己给值(可空 / 有 DEFAULT / 自增 / 生成列):缺列 ⇒ 一句 `ADD COLUMN <原文>`;库里允许 NULL ⇒ 有 DEFAULT 的:一句**真语句**
34
+ * `UPDATE t SET c = <声明的 DEFAULT 原文> WHERE c IS NULL;`(缺省是本构建声明的,不算替存量行猜值)再收紧;自增 / 生成列:只收紧(值由引擎给);
35
+ * · `value` —— 声明非空、无缺省、不是键:缺列 ⇒ 可空加列 → 注释回填(值只有部署者知道) → 收紧;库里允许 NULL ⇒ 只打后两(三)句;
36
+ * · `key` —— 主键成员:给存量行加主键列等于改它们的身份,**不出语句**,只一句话(出路走「部署匹配的构建」)。
37
+ * 反方向(构建可空、库里非空)不判:现网库里可能有,判了会让数量不明的库起不来。
38
+ *
29
39
  * ── 失败方向:读不到就拒,不跳过 ─────────────────────────────────────────────────────────────
30
40
  * information_schema 查询抛错、或整库一行都读不出来 ⇒ **拒启**。探针的语义是「我证明了库等于代码」,
31
41
  * 证不出来时放行等于把一条保护性断言静默降级成祝福([ref]:保护型缺席必须 fail-closed)。
@@ -51,12 +61,16 @@
51
61
  import type { Pool as MysqlPool } from "mysql2/promise";
52
62
  import type { Pool as PgPool } from "pg";
53
63
  import type { SqlDialect } from "./sql-driver.js";
54
- import { type SchemaProbeRead } from "./schema-live-columns.js";
64
+ import { type LiveColumns, type SchemaProbeRead } from "./schema-live-columns.js";
55
65
  import { StoreBootRefusalError } from "./store-contracts.js";
56
- /** 一列:名字 + 它在 `CREATE TABLE` 里的**原样定义文本**(生成 ADD COLUMN 指路用,不另手写)。 */
66
+ /**
67
+ * 一列:名字 + 它在 `CREATE TABLE` 里的**原样定义文本**(生成 ADD COLUMN 指路用,不另手写)。
68
+ * `key` 只在为真时出现:这一列是主键成员(内联 `PRIMARY KEY`,或表级 / 命名约束 `PRIMARY KEY (…)` 的成员);缺席 = 不是键。
69
+ */
57
70
  export interface ParsedColumn {
58
71
  readonly name: string;
59
72
  readonly ddl: string;
73
+ readonly key?: true;
60
74
  }
61
75
  /** 一张表的列形。 */
62
76
  export interface ParsedTable {
@@ -66,11 +80,25 @@ export interface ParsedTable {
66
80
  /**
67
81
  * 解析一条 `CREATE TABLE`。不是建表语句(CREATE INDEX / INSERT / SELECT / CREATE EXTENSION)⇒ `undefined`。
68
82
  *
69
- * 认识面窄得刻意:只取**表名 + 顶层列名 + 该列的定义文本**。类型、默认值、可空性一律**不比对** ——
83
+ * 认识面窄得刻意:取**表名 + 顶层列名 + 该列的定义文本 + 是否主键成员**。类型、默认值**不比对** ——
70
84
  * 本探针守的是「列在不在」这一类(T-47 的真病),把类型也拉进来会让方言差异(`DATETIME(3)` ⇄
71
85
  * `TIMESTAMPTZ(3)`、`vector(d)` ⇄ `jsonb` 的运行期参数化)变成一堆假红,而那是另一条判据另一台车。
86
+ * 唯一多看的一件是声明非空的列在库里是否仍允许 NULL({@link declaresNotNull} / {@link diffSchema}),原因见文件头「第二问」。
72
87
  */
73
88
  export declare function parseCreateTable(stmt: string): ParsedTable | undefined;
89
+ /** 这一列声明的 `DEFAULT` 表达式原文;没有缺省(或值由引擎给)⇒ `undefined`;有缺省却读不出 ⇒ 抛。 */
90
+ export declare function declaredDefault(col: ParsedColumn): string | undefined;
91
+ /** 本构建声明这一列非空:顶层 `NOT NULL`,或主键成员。**tightened 的唯一谓词**(库里该列允许 NULL ⇒ 拒)。 */
92
+ export declare function declaresNotNull(col: ParsedColumn): boolean;
93
+ /**
94
+ * 一列的「给存量行补值」类:**配方的分类表**(见文件头「第二问」;判 tightened 用 {@link declaresNotNull} 一条谓词,不按类开例外)。
95
+ * · `key` —— 主键成员(优先于其它);
96
+ * · `value` —— 声明非空(顶层 `NOT NULL`)∧ 无 `DEFAULT` ∧ 不是自增 / 序列 / 生成列:值只有部署者知道;
97
+ * · `self` —— 其余:可空、或引擎自己给值(DEFAULT 的值就是声明的那个)。
98
+ * 关键字只在顶层算({@link maskNested}):列名、引号串、括号组里的字样不参与。
99
+ */
100
+ export type ColumnFill = "key" | "value" | "self";
101
+ export declare function columnFill(col: ParsedColumn): ColumnFill;
74
102
  /** 启动时真会建出来的**全部**表形(录制 → 解析)。同名表二次出现以**先到**为准(`IF NOT EXISTS` 的真语义)。 */
75
103
  export declare function expectedTableShapes(dialect: SqlDialect): Promise<Map<string, ParsedTable>>;
76
104
  /** 一张表的对账结论。 */
@@ -80,19 +108,24 @@ export interface TableMismatch {
80
108
  readonly missing: readonly ParsedColumn[];
81
109
  /** 库有、代码没有(库比代码**新** —— 滚动窗里的旧副本)。 */
82
110
  readonly ghost: readonly string[];
111
+ /** 列在库里、构建声明非空({@link declaresNotNull})而库里允许 NULL(库比代码**旧**:缺列时部署者把它加成了可空,还没补值收紧;或手工放宽过)。 */
112
+ readonly tightened: readonly ParsedColumn[];
83
113
  }
84
- /** 对账(纯函数:期望 × 实况 → 不符表清单)。 */
85
- export declare function diffSchema(expected: Map<string, ParsedTable>, live: Map<string, Set<string>>): TableMismatch[];
114
+ /** 对账(纯函数:期望 × 实况 → 不符表清单)。实况 = {@link readLiveColumns} 的读数(列在不在 + 可不可空,一次读)。 */
115
+ export declare function diffSchema(expected: Map<string, ParsedTable>, live: LiveColumns): TableMismatch[];
116
+ /** 缺一列时的配方(按 {@link columnFill} 三类);拒启句里这一列的那几行就是它的返回值,真库钉据此取期望而不手抄句子。 */
117
+ export declare function missingColumnLines(dialect: SqlDialect, table: string, c: ParsedColumn): string[];
86
118
  /**
87
119
  * 逐表段 + 闭集出路段(多行):整库对账的拒启句与单表探针的拒因共用这一份句形(`schema-drift-sentence.ts` 的 `describeProbedTableDrift` 读它)。
88
- * ADD COLUMN 句由解析结果**生成**,不手写。
120
+ * 语句由解析结果**生成**,不手写;逐列配方按 {@link columnFill} 三类(缺列:自填 = 一句 ADD COLUMN,要值 = 可空加列 → 回填注释 → 收紧,键 = 一句话没有语句;
121
+ * 列在而允许 NULL:见 {@link tightenedColumnLines})。
89
122
  *
90
123
  * 出路段 = {@link SCHEMA_MISMATCH_WAYS_OUT}(**闭集三条**,常量;句子的属主在 `schema-drift-sentence.ts`):
91
- * ① 部署与这个库匹配的构建;② 库比构建旧(缺列)⇒ 部署者自己执行上面逐字打印的 `ALTER TABLE … ADD COLUMN …`(列集对账与拒启句永不改库);
92
- * ③ 库比构建新(多列)⇒ 部署持有那些列的构建(先升库、再升副本)。
124
+ * ① 部署与这个库匹配的构建;② 库比构建旧(缺列,或声明非空而库里允许 NULL)⇒ 部署者自己执行上面逐字打印的语句(要值的列,值归部署者;打印的语句全部生效之前拒启不松)
125
+ * (列集对账与拒启句永不改库);③ 库比构建新(多列)⇒ 部署持有那些列的构建(先升库、再升副本)。
93
126
  * 🔴 **没有销毁性的一条**:对带数据的库,任何「删库 / 重建」的指路都是教人销毁数据 —— 这里不写,拒启句的钉也守着(`test/schema-consistency.test.ts` ⑤)。
94
127
  */
95
- export declare function describeMismatchedTables(mismatches: readonly TableMismatch[]): string[];
128
+ export declare function describeMismatchedTables(dialect: SqlDialect, mismatches: readonly TableMismatch[]): string[];
96
129
  /** 拒启文案(表头 + 逐表段与闭集三条出路 {@link describeMismatchedTables})。 */
97
130
  export declare function describeSchemaMismatch(dialect: SqlDialect, mismatches: readonly TableMismatch[]): string;
98
131
  /**
@@ -3,7 +3,7 @@ import { readLiveColumns } from "./schema-live-columns.js";
3
3
  import { SCHEMA_MISMATCH_WAYS_OUT } from "./schema-drift-sentence.js";
4
4
  import { SCHEMA_MISMATCH_ERROR_CODE, StoreBootRefusalError } from "./store-contracts.js";
5
5
  const QUOTES = new Set(["'", '"', "`"]);
6
- function stripLineComments(sql) {
6
+ function stripComments(sql) {
7
7
  let out = "";
8
8
  for (let i = 0; i < sql.length; i++) {
9
9
  const c = sql[i];
@@ -25,6 +25,12 @@ function stripLineComments(sql) {
25
25
  out += "\n";
26
26
  continue;
27
27
  }
28
+ if (c === "/" && sql[i + 1] === "*") {
29
+ const end = sql.indexOf("*/", i + 2);
30
+ out += " ";
31
+ i = end < 0 ? sql.length : end + 1;
32
+ continue;
33
+ }
28
34
  out += c;
29
35
  }
30
36
  return out;
@@ -56,8 +62,69 @@ function splitTopLevel(body) {
56
62
  }
57
63
  const CONSTRAINT_HEADS = new Set(["PRIMARY", "UNIQUE", "KEY", "INDEX", "CONSTRAINT", "FOREIGN", "CHECK", "FULLTEXT", "SPATIAL", "EXCLUDE"]);
58
64
  const unquote = (s) => s.replace(/^[`"](.*)[`"]$/s, "$1");
65
+ function maskNested(s) {
66
+ let out = "";
67
+ let depth = 0;
68
+ for (let i = 0; i < s.length; i++) {
69
+ const c = s[i];
70
+ if (QUOTES.has(c)) {
71
+ let j = i + 1;
72
+ while (j < s.length && s[j] !== c)
73
+ j++;
74
+ out += "\0".repeat(Math.min(j, s.length - 1) - i + 1);
75
+ i = j;
76
+ continue;
77
+ }
78
+ if (c === "(") {
79
+ out += depth === 0 ? "(" : "\0";
80
+ depth++;
81
+ }
82
+ else if (c === ")") {
83
+ depth = Math.max(0, depth - 1);
84
+ out += "\0";
85
+ }
86
+ else {
87
+ out += depth > 0 ? "\0" : c;
88
+ }
89
+ }
90
+ return out;
91
+ }
92
+ function groupEnd(s, open) {
93
+ let depth = 0;
94
+ for (let i = open; i < s.length; i++) {
95
+ const c = s[i];
96
+ if (QUOTES.has(c)) {
97
+ i++;
98
+ while (i < s.length && s[i] !== c)
99
+ i++;
100
+ continue;
101
+ }
102
+ if (c === "(")
103
+ depth++;
104
+ else if (c === ")") {
105
+ depth--;
106
+ if (depth === 0)
107
+ return i;
108
+ }
109
+ }
110
+ return -1;
111
+ }
112
+ function primaryKeyMembers(constraint) {
113
+ const at = /\bPRIMARY\s+KEY\b/i.exec(maskNested(constraint));
114
+ if (!at)
115
+ return [];
116
+ const open = constraint.indexOf("(", at.index);
117
+ if (open < 0)
118
+ return [];
119
+ const close = groupEnd(constraint, open);
120
+ if (close < 0)
121
+ return [];
122
+ return splitTopLevel(constraint.slice(open + 1, close))
123
+ .map((m) => unquote(m.trim().split(/[\s(]/, 1)[0]).toLowerCase())
124
+ .filter((m) => m !== "");
125
+ }
59
126
  export function parseCreateTable(stmt) {
60
- const sql = stripLineComments(stmt).trim();
127
+ const sql = stripComments(stmt).trim();
61
128
  const head = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([`"]?[\w$.]+[`"]?)\s*\(/i.exec(sql);
62
129
  if (!head)
63
130
  return undefined;
@@ -85,18 +152,93 @@ export function parseCreateTable(stmt) {
85
152
  }
86
153
  if (close < 0)
87
154
  return undefined;
88
- const columns = [];
155
+ const plain = [];
156
+ const tableKey = new Set();
89
157
  for (const raw of splitTopLevel(sql.slice(open + 1, close))) {
90
158
  const part = raw.trim().replace(/\s+/g, " ");
91
159
  if (part === "")
92
160
  continue;
93
161
  const first = part.split(/[\s(]/, 1)[0];
94
- if (CONSTRAINT_HEADS.has(first.toUpperCase()))
162
+ if (CONSTRAINT_HEADS.has(first.toUpperCase())) {
163
+ for (const member of primaryKeyMembers(part))
164
+ tableKey.add(member);
95
165
  continue;
96
- columns.push({ name: unquote(first).toLowerCase(), ddl: part });
166
+ }
167
+ plain.push({ name: unquote(first).toLowerCase(), ddl: part, inlineKey: /\bPRIMARY\s+KEY\b/i.test(maskNested(part.slice(first.length))) });
97
168
  }
169
+ const columns = plain.map((c) => (c.inlineKey || tableKey.has(c.name) ? { name: c.name, ddl: c.ddl, key: true } : { name: c.name, ddl: c.ddl }));
98
170
  return { table: unquote(head[1]).toLowerCase(), columns };
99
171
  }
172
+ function declarationOf(col) {
173
+ const rest = col.ddl.slice(col.ddl.split(/[\s(]/, 1)[0].length);
174
+ const top = maskNested(rest);
175
+ const notNull = /\bNOT\s+NULL\b/i.test(top);
176
+ const engineGives = /\b(?:AUTO_INCREMENT|GENERATED|IDENTITY|(?:BIG|SMALL)?SERIAL\d?)\b/i.test(top) || /\bAS\s*\(/i.test(top);
177
+ const at = /\bDEFAULT\b/i.exec(top);
178
+ const hasDefault = at !== null;
179
+ const defaultExpr = () => (!engineGives && at !== null ? defaultExpression(rest, at.index + at[0].length, col.name) : undefined);
180
+ return { key: col.key === true, notNull, engineGives, hasDefault, defaultExpr };
181
+ }
182
+ function defaultExpression(rest, from, column) {
183
+ let i = from;
184
+ while (i < rest.length && /\s/.test(rest[i]))
185
+ i++;
186
+ const start = i;
187
+ const c = rest[i];
188
+ let end = -1;
189
+ if (c !== undefined && QUOTES.has(c)) {
190
+ let j = i + 1;
191
+ for (;;) {
192
+ while (j < rest.length && rest[j] !== c)
193
+ j++;
194
+ if (j >= rest.length)
195
+ break;
196
+ if (rest[j + 1] === c) {
197
+ j += 2;
198
+ continue;
199
+ }
200
+ end = j + 1;
201
+ break;
202
+ }
203
+ }
204
+ else if (c === "(") {
205
+ const close = groupEnd(rest, i);
206
+ if (close >= 0)
207
+ end = close + 1;
208
+ }
209
+ else if (c !== undefined) {
210
+ const word = /^[+-]?[A-Za-z0-9_.$]+/.exec(rest.slice(i));
211
+ if (word) {
212
+ end = i + word[0].length;
213
+ if (rest[end] === "(") {
214
+ const close = groupEnd(rest, end);
215
+ end = close >= 0 ? close + 1 : -1;
216
+ }
217
+ }
218
+ }
219
+ if (end < 0 || end === start)
220
+ throw new Error(`cannot read the DEFAULT expression of column ${column}: ${rest.trim()}`);
221
+ return rest.slice(start, end);
222
+ }
223
+ export function declaredDefault(col) {
224
+ return declarationOf(col).defaultExpr();
225
+ }
226
+ export function declaresNotNull(col) {
227
+ const d = declarationOf(col);
228
+ return d.key || d.notNull;
229
+ }
230
+ export function columnFill(col) {
231
+ const d = declarationOf(col);
232
+ if (d.key)
233
+ return "key";
234
+ return d.notNull && !d.engineGives && !d.hasDefault ? "value" : "self";
235
+ }
236
+ function nullableForm(ddl) {
237
+ const at = /(?:\bCONSTRAINT\s+\S+\s+)?\bNOT\s+NULL\b/i.exec(maskNested(ddl));
238
+ if (!at)
239
+ return ddl;
240
+ return (ddl.slice(0, at.index) + " " + ddl.slice(at.index + at[0].length)).replace(/\s+/g, " ").trim();
241
+ }
100
242
  export async function expectedTableShapes(dialect) {
101
243
  const shapes = new Map();
102
244
  for (const stmt of await recordEnsureStatements(dialect)) {
@@ -114,19 +256,78 @@ export function diffSchema(expected, live) {
114
256
  continue;
115
257
  const missing = shape.columns.filter((c) => !cols.has(c.name));
116
258
  const known = new Set(shape.columns.map((c) => c.name));
117
- const ghost = [...cols].filter((c) => !known.has(c)).sort();
118
- if (missing.length > 0 || ghost.length > 0)
119
- out.push({ table, missing, ghost });
259
+ const ghost = [...cols.keys()].filter((c) => !known.has(c)).sort();
260
+ const tightened = shape.columns.filter((c) => cols.get(c.name)?.nullable === true && declaresNotNull(c));
261
+ if (missing.length > 0 || ghost.length > 0 || tightened.length > 0)
262
+ out.push({ table, missing, ghost, tightened });
120
263
  }
121
264
  return out;
122
265
  }
123
- export function describeMismatchedTables(mismatches) {
266
+ function tightenLines(dialect, table, c) {
267
+ switch (dialect) {
268
+ case "pg":
269
+ return [` ALTER TABLE ${table} ALTER COLUMN ${columnRef(c)} SET NOT NULL;`];
270
+ case "mysql":
271
+ return [` SET SESSION sql_mode = CONCAT_WS(',', @@SESSION.sql_mode, 'STRICT_ALL_TABLES');`, ` ALTER TABLE ${table} MODIFY COLUMN ${c.ddl};`];
272
+ default: {
273
+ const unreachable = dialect;
274
+ throw new Error(`unknown SQL dialect ${String(unreachable)}`);
275
+ }
276
+ }
277
+ }
278
+ const columnRef = (c) => c.ddl.split(/[\s(]/, 1)[0];
279
+ function backfillComment(table, column) {
280
+ return ` -- rows already in ${table} need a value for ${column} that this build cannot choose: UPDATE ${table} SET ${column} = … WHERE ${column} IS NULL;`;
281
+ }
282
+ export function missingColumnLines(dialect, table, c) {
283
+ const fill = columnFill(c);
284
+ switch (fill) {
285
+ case "self":
286
+ return [` ALTER TABLE ${table} ADD COLUMN ${c.ddl};`];
287
+ case "value":
288
+ return [` ALTER TABLE ${table} ADD COLUMN ${nullableForm(c.ddl)};`, backfillComment(table, columnRef(c)), ...tightenLines(dialect, table, c)];
289
+ case "key":
290
+ return [` table ${table}: column ${c.name} is part of the primary key — adding it to rows already in ${table} changes their identity; this build has no statement for it.`];
291
+ default: {
292
+ const unreachable = fill;
293
+ throw new Error(`unknown column fill ${String(unreachable)}`);
294
+ }
295
+ }
296
+ }
297
+ function tightenedColumnLines(dialect, table, c) {
298
+ const fill = columnFill(c);
299
+ switch (fill) {
300
+ case "key":
301
+ return [` table ${table}: column ${c.name} is part of the primary key and allows NULL in the database — rows already in ${table} may hold NULL in their key; this build has no statement for it.`];
302
+ case "value":
303
+ return [backfillComment(table, columnRef(c)), ...tightenLines(dialect, table, c)];
304
+ case "self": {
305
+ if (!declaresNotNull(c))
306
+ throw new Error(`schema mismatch for ${table}.${c.name}: a column this build declares nullable cannot be tightened`);
307
+ const defaultExpr = declaredDefault(c);
308
+ const ref = columnRef(c);
309
+ return defaultExpr === undefined
310
+ ? tightenLines(dialect, table, c)
311
+ : [` UPDATE ${table} SET ${ref} = ${defaultExpr} WHERE ${ref} IS NULL;`, ...tightenLines(dialect, table, c)];
312
+ }
313
+ default: {
314
+ const unreachable = fill;
315
+ throw new Error(`unknown column fill ${String(unreachable)}`);
316
+ }
317
+ }
318
+ }
319
+ export function describeMismatchedTables(dialect, mismatches) {
124
320
  const lines = [];
125
321
  for (const m of mismatches) {
126
322
  if (m.missing.length > 0) {
127
323
  lines.push(` table ${m.table}: MISSING column(s) ${m.missing.map((c) => c.name).join(", ")} — the database is OLDER than this build.`);
128
324
  for (const c of m.missing)
129
- lines.push(` ALTER TABLE ${m.table} ADD COLUMN ${c.ddl};`);
325
+ lines.push(...missingColumnLines(dialect, m.table, c));
326
+ }
327
+ if (m.tightened.length > 0) {
328
+ lines.push(` table ${m.table}: column(s) ${m.tightened.map((c) => c.name).join(", ")} allow NULL in the database, but this build declares them NOT NULL — the database is OLDER than this build.`);
329
+ for (const c of m.tightened)
330
+ lines.push(...tightenedColumnLines(dialect, m.table, c));
130
331
  }
131
332
  if (m.ghost.length > 0) {
132
333
  lines.push(` table ${m.table}: UNKNOWN column(s) ${m.ghost.join(", ")} — the database is NEWER than this build (a rolling window where an old replica reached an upgraded database).`);
@@ -142,7 +343,7 @@ export function describeSchemaMismatch(dialect, mismatches) {
142
343
  "Schema policy: the code is the single source of truth, and the column check that produced this refusal never alters a database —",
143
344
  "so a drifted database is a deployment-order problem, not something the process may quietly work around.",
144
345
  "",
145
- ...describeMismatchedTables(mismatches),
346
+ ...describeMismatchedTables(dialect, mismatches),
146
347
  ];
147
348
  return lines.join("\n");
148
349
  }
@@ -11,7 +11,10 @@ export interface OlderWayOut {
11
11
  * 🔴 **没有销毁性的一条**:对带数据的库,任何「删库 / 重建」的指路都是教人销毁数据。
12
12
  */
13
13
  export declare function schemaWaysOut(older: OlderWayOut): readonly string[];
14
- /** 缺列方向的出路段(整库对账与单表探针共用;逐字钉在 `test/schema-consistency.test.ts` ⑤)。 */
14
+ /**
15
+ * 旧方向的出路段(整库对账与单表探针共用;逐字钉在 `test/schema-consistency.test.ts` ⑤)。「旧」= 缺列,或声明非空而库里仍允许 NULL 的列;
16
+ * 打印的是语句集,不只是 ADD COLUMN:要值列的值只有部署者知道(回填那一步以注释行给出),所以这一条把「值归部署者」和「打印的语句全部生效之前拒启不松」写明。
17
+ */
15
18
  export declare const SCHEMA_MISMATCH_WAYS_OUT: readonly string[];
16
19
  /** 探针读口:一条 SQL → `{ rows }`(各 `assert*Schema` 的 `query` 形)。 */
17
20
  export type ProbeQuery = (sql: string) => Promise<{
@@ -8,8 +8,8 @@ export function schemaWaysOut(older) {
8
8
  ];
9
9
  }
10
10
  export const SCHEMA_MISMATCH_WAYS_OUT = schemaWaysOut({
11
- when: "missing columns",
12
- action: "run the ALTER TABLE … ADD COLUMN statements printed above yourself",
11
+ when: "missing columns, or columns that allow NULL where this build declares NOT NULL",
12
+ action: "run the statements printed above yourself (where a column needs a value this build cannot choose for rows already in the table, the printed comment says so and that value is yours; this refusal stays until every printed statement has taken effect)",
13
13
  });
14
14
  export async function describeProbedTableDrift(query, dialect, tables) {
15
15
  const d = dialect === "pg" ? "pg" : "mysql";
@@ -18,9 +18,9 @@ export async function describeProbedTableDrift(query, dialect, tables) {
18
18
  try {
19
19
  const sc = await import("./schema-consistency.js");
20
20
  const diff = sc.diffSchema(await sc.expectedTableShapes(d), await readLiveColumns(read, d));
21
- const missingOnly = diff.filter((m) => tables.includes(m.table) && m.missing.length > 0).map((m) => ({ ...m, ghost: [] }));
21
+ const missingOnly = diff.filter((m) => tables.includes(m.table) && m.missing.length > 0).map((m) => ({ ...m, ghost: [], tightened: [] }));
22
22
  if (missingOnly.length > 0)
23
- return sc.describeMismatchedTables(missingOnly).join("\n");
23
+ return sc.describeMismatchedTables(d, missingOnly).join("\n");
24
24
  why = "this build's table definitions list no column that the database lacks on that table, so the probe and the definitions disagree";
25
25
  }
26
26
  catch (err) {
@@ -2,6 +2,15 @@ import type { PgQueryFn } from "./pg-query.js";
2
2
  import type { SqlDialect } from "./sql-driver.js";
3
3
  /** advisory lock 语句 —— 与 schema 无关,录制时跳过(但要答成功,否则 ensure* 走降级告警路径)。 */
4
4
  export declare const LOCK_RE: RegExp;
5
+ /**
6
+ * [ref] `ensureIndex` 的**索引在场**探针(MySQL 臂)。答「在场」——因为**新建库**上这批索引本来就随
7
+ * `CREATE TABLE` 的内联 `KEY` 一起到货,而基线按定义 =「启动时对一个新库真会执行的东西」。答"零行"会让
8
+ * 录制里凭空多出 68 条**新建库上永不发生**的 `ALTER TABLE … ADD INDEX`,基线就成了一份撒谎的产物。
9
+ * ⚠️ 这条特判**只**放行索引探针:任何别的 `information_schema` 探针照旧答零行 ⇒ 残留的「探列→ALTER」
10
+ * seam 仍会真的发出 ALTER 并被基线生成器的 `SeamViolation`(`scripts/dump-schema.ts`)当场抓住
11
+ * (SCHEMA POLICY 的那半一个字没松)。
12
+ */
13
+ export declare const INDEX_PROBE_RE: RegExp;
5
14
  /**
6
15
  * **「一个新库对 ensure 探针怎么答」的唯一属主**(合并复审 车HB 后收口:此前生成器录制器、`test/ensure-schema.test.ts`
7
16
  * 的假池、`test/schema-baseline-generated.test.ts` ③c 的假驱动各抄一份,[ref] 加了索引探针 + PG 锁改 `got === true`
@@ -14,7 +14,7 @@ import { ensureTiDBUsageWindowSchema, ensurePgUsageWindowSchema } from "../store
14
14
  import { ensureTiDBTaskListSchema, ensurePgTaskListSchema } from "./task-list-store-sql.js";
15
15
  import { ensureTiDBDeviceSchema, ensurePgDeviceSchema } from "./device-store-sql.js";
16
16
  export const LOCK_RE = /GET_LOCK|RELEASE_LOCK|pg_(try_)?advisory/i;
17
- const INDEX_PROBE_RE = /FROM information_schema\.statistics\b/i;
17
+ export const INDEX_PROBE_RE = /^\s*SHOW\s+INDEX\s+FROM\b/i;
18
18
  const PG_INDEX_VALID_RE = /FROM pg_index i WHERE i\.indexrelid = to_regclass/i;
19
19
  function newDatabaseSessionMetaKeyCollation() {
20
20
  const stmt = SCHEMA_STATEMENTS.find((s) => s.includes("CREATE TABLE IF NOT EXISTS session_meta ("));
@@ -7,6 +7,7 @@ export const CENTRAL_SCHEMA_INDEXES = [
7
7
  { table: "task_active", name: "idx_task_active_task", columns: ["task_id"] },
8
8
  { table: "checkpoint", name: "idx_checkpoint_status_deadline", columns: ["status", "deadline"] },
9
9
  { table: "checkpoint", name: "idx_checkpoint_session_status", columns: ["session_id", "status"] },
10
+ { table: "checkpoint", name: "idx_checkpoint_host_session_status", columns: ["host_session_id", "status"] },
10
11
  { table: "resume_anchor", name: "idx_resume_anchor_session", columns: ["session_id"] },
11
12
  { table: "approval_nonce", name: "idx_approval_nonce_expires", columns: ["expires_at_ms"] },
12
13
  { table: "user_input_acceptance", name: "idx_user_input_acceptance_session", columns: ["session_id", "state", "accepted_at_ms"] },
@@ -17,6 +18,7 @@ export const CENTRAL_SCHEMA_INDEXES = [
17
18
  { table: "snapshot_blob", name: "idx_snapshot_blob_created", columns: ["created_at"] },
18
19
  { table: "file_history_version", name: "idx_file_history_version_blob", columns: ["blob_hash"] },
19
20
  { table: "file_history_boundary_file", name: "idx_file_history_bf_key", columns: ["scope", "key_hash"] },
21
+ { table: "file_history_boundary", name: "uq_file_history_boundary_seq", columns: ["scope", "publish_seq"], unique: true },
20
22
  { table: "file_history_blob", name: "idx_file_history_blob_created", columns: ["created_at"] },
21
23
  { table: "workflow_run", name: "idx_wfrun_scope_created", columns: ["scope", "created_at_ms"] },
22
24
  { table: "workflow_run", name: "idx_wfrun_scope_status", columns: ["scope", "status"] },
@@ -24,6 +26,7 @@ export const CENTRAL_SCHEMA_INDEXES = [
24
26
  { table: "workflow_park_decision", name: "idx_wfparkdec_host", columns: ["host_session_id"] },
25
27
  { table: "workflow_park_decision", name: "idx_wfparkdec_run", columns: ["run_id"] },
26
28
  { table: "workflow_completion_inbox", name: "idx_wfinbox_session_seq", columns: ["session_id", "seq"] },
29
+ { table: "workflow_completion_inbox", name: "uq_wfinbox_seq", columns: ["seq"], unique: true },
27
30
  { table: "workflow_inbox_fence", name: "idx_wffence_until", columns: ["until_ms"] },
28
31
  { table: "workflow_notify_journal", name: "idx_wfnotify_acked", columns: ["acked"] },
29
32
  { table: "shared_memory_store", name: "idx_shared_memory_store_scope", columns: ["scope_key", "store_id"] },
@@ -1,20 +1,29 @@
1
1
  /**
2
- * 库里**实际**的列集 —— 唯一读者([ref] 列册探针 `schema-consistency.ts` 的对账读它;`ensure-index.ts` 的索引补建在失败之后判「是不是这张表
2
+ * 库里**实际**的列册 —— 唯一读者([ref] 列册探针 `schema-consistency.ts` 的对账读它;`ensure-index.ts` 的索引补建在失败之后判「是不是这张表
3
3
  * 缺这条索引的列」也读它)。叶子模块:不值依赖任何模块(列册探针那边经录制驱动 / 建表腿值依赖 `ensure-index.ts`,读者若住在那边,
4
4
  * `ensure-index.ts` 读它就是一个运行时环)。方言词是 `ensure-index.ts` 的闭集(类型边,擦除)。
5
+ *
6
+ * 一个读者、一次读:同一张目录视图的同一批行同时回答「哪些列在」(键)与「它允许 NULL 吗」(值)。两方言的「读哪张表 / 哪个 schema」
7
+ * (MySQL 协议 = 连接上的库;PG = `search_path` 次序里的首次命中)只在这里写一遍;只问列在不在的读者(索引补建、退役 schema 判)用 `Map.has`,不看值。
5
8
  */
6
9
  import type { SqlDialect } from "./sql-driver.js";
7
10
  /** 探针读口:一条 SQL → 行数组(两方言由调用方各自绑)。 */
8
11
  export type SchemaProbeRead = (sql: string) => Promise<Array<Record<string, unknown>>>;
12
+ /** 库里一列的实况。`nullable` = 目录的 `is_nullable` 是 `YES`(两个目录都是 `YES` / `NO` 的闭集;读数里没有 `n` 或不是 `YES` ⇒ 不算可空,只有目录明说可空的列才被判)。 */
13
+ export interface LiveColumn {
14
+ readonly nullable: boolean;
15
+ }
16
+ /** 库里实际的列册:表名 → (列名 → 实况)。读者交出的是只读视图(消费方只问 `has` / `get`)。 */
17
+ export type LiveColumns = ReadonlyMap<string, ReadonlyMap<string, LiveColumn>>;
9
18
  /**
10
- * 库里实际的列集(表名 → 列名集合)。
19
+ * 库里实际的列册(表名 → 列名 → { nullable })。
11
20
  *
12
21
  * 🔴 **PG 侧读的是「查询真正会解析到的那个关系」,不是 `current_schema()`**(codex 对抗复审本轮 [medium]
13
22
  * 采纳):店里的 SQL 全是**不限定 schema** 的裸表名,它按 `search_path` **逐个** schema 解析,命中第一个;
14
23
  * 而 `current_schema()` 只是路径的第一段。两者不等的部署是真的存在(角色的 `search_path` 配了多段),那时
15
24
  * 只读第一段会让探针对「表其实住在路径后段、而且缺列」这一形**完全沉默**。⇒ 按 `current_schemas(false)`
16
- * 的**顺序**取每张表的第一次命中 —— 探针于是与执行器看同一张表。MySQL 协议没有这个概念(库 = 连接上的
17
- * `DATABASE()`),那条臂一个字不变。
25
+ * 的**顺序**取每张表的第一次命中 —— 探针于是与执行器看同一张表(列在不在、可不可空对同一张表说话)。MySQL 协议没有这个概念(库 = 连接上的
26
+ * `DATABASE()`),那条臂只有选择列多一格。
18
27
  */
19
- export declare function readLiveColumns(read: SchemaProbeRead, dialect: SqlDialect): Promise<Map<string, Set<string>>>;
28
+ export declare function readLiveColumns(read: SchemaProbeRead, dialect: SqlDialect): Promise<LiveColumns>;
20
29
  //# sourceMappingURL=schema-live-columns.d.ts.map
@@ -1,8 +1,8 @@
1
1
  export async function readLiveColumns(read, dialect) {
2
2
  const live = new Map();
3
3
  if (dialect !== "pg") {
4
- for (const row of await read("SELECT table_name AS t, column_name AS c FROM information_schema.columns WHERE table_schema = DATABASE()")) {
5
- addColumn(live, row["t"], row["c"], "fold");
4
+ for (const row of await read("SELECT table_name AS t, column_name AS c, is_nullable AS n FROM information_schema.columns WHERE table_schema = DATABASE()")) {
5
+ addColumn(live, row["t"], row["c"], row["n"], "fold");
6
6
  }
7
7
  return live;
8
8
  }
@@ -13,7 +13,7 @@ export async function readLiveColumns(read, dialect) {
13
13
  order.set(s, Number(row["ord"]));
14
14
  }
15
15
  const winner = new Map();
16
- for (const row of await read("SELECT table_schema AS s, table_name AS t, column_name AS c FROM information_schema.columns WHERE table_schema = ANY (current_schemas(false))")) {
16
+ for (const row of await read("SELECT table_schema AS s, table_name AS t, column_name AS c, is_nullable AS n FROM information_schema.columns WHERE table_schema = ANY (current_schemas(false))")) {
17
17
  const t = String(row["t"] ?? "");
18
18
  const rank = order.get(String(row["s"] ?? "")) ?? Number.MAX_SAFE_INTEGER;
19
19
  const held = winner.get(t);
@@ -23,20 +23,20 @@ export async function readLiveColumns(read, dialect) {
23
23
  winner.set(t, rank);
24
24
  live.delete(t);
25
25
  }
26
- addColumn(live, t, row["c"], "verbatim");
26
+ addColumn(live, t, row["c"], row["n"], "verbatim");
27
27
  }
28
28
  return live;
29
29
  }
30
- function addColumn(live, table, column, mode) {
30
+ function addColumn(live, table, column, isNullable, mode) {
31
31
  const t = mode === "fold" ? String(table ?? "").toLowerCase() : String(table ?? "");
32
32
  const c = mode === "fold" ? String(column ?? "").toLowerCase() : String(column ?? "");
33
33
  if (t === "" || c === "")
34
34
  return;
35
- let set = live.get(t);
36
- if (set === undefined) {
37
- set = new Set();
38
- live.set(t, set);
35
+ let columns = live.get(t);
36
+ if (columns === undefined) {
37
+ columns = new Map();
38
+ live.set(t, columns);
39
39
  }
40
- set.add(c);
40
+ columns.set(c, { nullable: String(isNullable ?? "").toUpperCase() === "YES" });
41
41
  }
42
42
  //# sourceMappingURL=schema-live-columns.js.map
@@ -3,6 +3,7 @@ import { uuidv7 } from "@sema-agent/core";
3
3
  import { stripControlAndBidi } from "@sema-agent/settings-schema";
4
4
  import { presignS3CopyUrl, presignS3Url } from "./s3-presign.js";
5
5
  import { OBJECT_STORE_IO_TIMEOUT_MS } from "./blob-backend.js";
6
+ import { createEgressFetch } from "../egress-redirect.js";
6
7
  export const PRESIGN_MAX_TTL_SEC = 604_800;
7
8
  export function scopeSegment(secretKey, scope) {
8
9
  if (scope === undefined || scope === "")
@@ -27,7 +28,7 @@ export function sanitizeSendFileName(name) {
27
28
  return clean.length > 0 ? clean : "file";
28
29
  }
29
30
  export function createSendUserFileIssuer(cfg, deps) {
30
- const f = deps?.fetchImpl ?? fetch;
31
+ const f = createEgressFetch("declare the final object-store address as MINIO_ENDPOINT / S3_ENDPOINT", deps?.fetchImpl);
31
32
  const bounded = () => ({ signal: AbortSignal.timeout(OBJECT_STORE_IO_TIMEOUT_MS) });
32
33
  const upload = deps?.upload ??
33
34
  (async (bucket, key, bytes) => {