@sema-agent/server 1.322.0 → 2.0.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 (539) hide show
  1. package/dist/approval-hmac.d.ts +40 -0
  2. package/dist/approval-hmac.js +67 -0
  3. package/dist/approval.d.ts +31 -0
  4. package/dist/approval.js +72 -4
  5. package/dist/audit.d.ts +26 -0
  6. package/dist/audit.js +40 -1
  7. package/dist/auth-bridge.d.ts +10 -0
  8. package/dist/auth-bridge.js +47 -4
  9. package/dist/auth-keys.d.ts +19 -0
  10. package/dist/auth-keys.js +13 -0
  11. package/dist/bake-runner/main.d.ts +5 -0
  12. package/dist/bake-runner/main.js +43 -4
  13. package/dist/bake-runner/protocol.d.ts +57 -0
  14. package/dist/bake-runner/protocol.js +58 -3
  15. package/dist/bake-runner/runner.d.ts +54 -0
  16. package/dist/bake-runner/runner.js +87 -5
  17. package/dist/bench/l8/artifact.d.ts +63 -0
  18. package/dist/bench/l8/artifact.js +61 -2
  19. package/dist/bench/l8/escape.d.ts +36 -0
  20. package/dist/bench/l8/escape.js +25 -0
  21. package/dist/bench/l8/index.d.ts +14 -0
  22. package/dist/bench/l8/index.js +14 -0
  23. package/dist/bench/l8/probes.d.ts +74 -0
  24. package/dist/bench/l8/probes.js +60 -0
  25. package/dist/bench/l8/run-probes.d.ts +43 -0
  26. package/dist/bench/l8/run-probes.js +45 -2
  27. package/dist/bench/s1/arms.d.ts +126 -0
  28. package/dist/bench/s1/arms.js +188 -13
  29. package/dist/bench/s1/live-deps.d.ts +66 -0
  30. package/dist/bench/s1/live-deps.js +249 -11
  31. package/dist/bench/s1/oracle.d.ts +49 -0
  32. package/dist/bench/s1/oracle.js +36 -1
  33. package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
  34. package/dist/bench/s1/repair-oracle-adapter.js +30 -0
  35. package/dist/bench/s1/reviewer.d.ts +38 -0
  36. package/dist/bench/s1/reviewer.js +34 -0
  37. package/dist/bench/s1/row.d.ts +77 -0
  38. package/dist/bench/s1/row.js +62 -0
  39. package/dist/bench/s1/run-firm.d.ts +47 -0
  40. package/dist/bench/s1/run-firm.js +70 -4
  41. package/dist/bench/s1/runner-ctx.d.ts +71 -0
  42. package/dist/bench/s1/runner-ctx.js +36 -0
  43. package/dist/bench/s1/tasks.d.ts +108 -0
  44. package/dist/bench/s1/tasks.js +115 -0
  45. package/dist/boot-reclaim.d.ts +19 -0
  46. package/dist/boot-reclaim.js +20 -0
  47. package/dist/brain.d.ts +25 -0
  48. package/dist/brain.js +61 -1
  49. package/dist/budget.d.ts +66 -0
  50. package/dist/budget.js +128 -4
  51. package/dist/capabilities/builtin-tools.d.ts +3 -0
  52. package/dist/capabilities/builtin-tools.js +3 -0
  53. package/dist/capabilities/center-plugins.d.ts +17 -1
  54. package/dist/capabilities/center-plugins.js +45 -4
  55. package/dist/capabilities/center-prompts.d.ts +46 -0
  56. package/dist/capabilities/center-prompts.js +57 -3
  57. package/dist/capabilities/code-review-council.d.ts +28 -0
  58. package/dist/capabilities/code-review-council.js +40 -7
  59. package/dist/capabilities/collab-wire.d.ts +2 -0
  60. package/dist/capabilities/collab-workflows.d.ts +7 -0
  61. package/dist/capabilities/collab-workflows.js +44 -1
  62. package/dist/capabilities/oa-tools.d.ts +6 -0
  63. package/dist/capabilities/oa-tools.js +10 -0
  64. package/dist/capabilities/prompt.d.ts +14 -0
  65. package/dist/capabilities/prompt.js +14 -0
  66. package/dist/capabilities/prompts/code-review.d.ts +14 -0
  67. package/dist/capabilities/prompts/code-review.js +14 -0
  68. package/dist/capabilities/prompts/identity.d.ts +6 -0
  69. package/dist/capabilities/prompts/identity.js +6 -0
  70. package/dist/capabilities/prompts/team.d.ts +4 -0
  71. package/dist/capabilities/prompts/team.js +4 -0
  72. package/dist/capabilities/repo-tools.d.ts +11 -0
  73. package/dist/capabilities/repo-tools.js +8 -0
  74. package/dist/capabilities/sandbox-file-send.d.ts +95 -0
  75. package/dist/capabilities/sandbox-file-send.js +91 -3
  76. package/dist/capabilities/scenarios.d.ts +130 -0
  77. package/dist/capabilities/scenarios.js +180 -7
  78. package/dist/capabilities/select-environment-tool.d.ts +7 -0
  79. package/dist/capabilities/select-environment-tool.js +30 -0
  80. package/dist/capabilities/send-user-file-tool.d.ts +33 -0
  81. package/dist/capabilities/send-user-file-tool.js +65 -1
  82. package/dist/capabilities/skills.d.ts +29 -0
  83. package/dist/capabilities/skills.js +13 -2
  84. package/dist/capabilities/team.d.ts +22 -0
  85. package/dist/capabilities/team.js +22 -2
  86. package/dist/capabilities/tool-defer.d.ts +26 -0
  87. package/dist/capabilities/tool-defer.js +3 -0
  88. package/dist/config-center/apply-effective.d.ts +65 -0
  89. package/dist/config-center/apply-effective.js +204 -12
  90. package/dist/config-center/http-client.d.ts +34 -0
  91. package/dist/config-center/http-client.js +68 -0
  92. package/dist/config-center/restart-signal.d.ts +22 -0
  93. package/dist/config-center/restart-signal.js +39 -0
  94. package/dist/config-center/skills-mcp.d.ts +20 -1
  95. package/dist/config-center/skills-mcp.js +42 -7
  96. package/dist/config-center/types.d.ts +92 -1
  97. package/dist/config-lkg.d.ts +12 -0
  98. package/dist/config-lkg.js +41 -0
  99. package/dist/config-provider.d.ts +78 -0
  100. package/dist/config-provider.js +165 -2
  101. package/dist/config-types.d.ts +546 -0
  102. package/dist/config.d.ts +64 -0
  103. package/dist/config.js +455 -60
  104. package/dist/degenerate-instrument.d.ts +38 -0
  105. package/dist/degenerate-instrument.js +55 -3
  106. package/dist/elicitation.d.ts +39 -0
  107. package/dist/elicitation.js +87 -3
  108. package/dist/env-facts.d.ts +61 -0
  109. package/dist/env-facts.js +73 -7
  110. package/dist/fleet/fleet-bus.d.ts +185 -0
  111. package/dist/fleet/fleet-bus.js +333 -27
  112. package/dist/fleet/subagent-tail-bus.d.ts +11 -0
  113. package/dist/fleet/subagent-tail-bus.js +33 -2
  114. package/dist/fleet-client.d.ts +38 -0
  115. package/dist/fleet-client.js +44 -9
  116. package/dist/fleet-lease.d.ts +46 -0
  117. package/dist/fleet-lease.js +73 -5
  118. package/dist/hooks/branch-transcript.d.ts +8 -0
  119. package/dist/hooks/branch-transcript.js +33 -0
  120. package/dist/hooks/cc-stop-prompt.d.ts +42 -0
  121. package/dist/hooks/cc-stop-prompt.js +43 -1
  122. package/dist/hooks/hook-llm.d.ts +15 -0
  123. package/dist/hooks/hook-llm.js +47 -0
  124. package/dist/hooks/hook-runner.d.ts +89 -0
  125. package/dist/hooks/hook-runner.js +327 -18
  126. package/dist/http/idempotency.d.ts +31 -0
  127. package/dist/http/idempotency.js +34 -0
  128. package/dist/http/principal-gate.d.ts +17 -0
  129. package/dist/http/principal-gate.js +35 -3
  130. package/dist/http/route-ctx.d.ts +36 -0
  131. package/dist/http/routes/approvals-assistant.d.ts +25 -0
  132. package/dist/http/routes/approvals-assistant.js +253 -23
  133. package/dist/http/routes/attachments.js +22 -4
  134. package/dist/http/routes/capabilities.d.ts +7 -0
  135. package/dist/http/routes/capabilities.js +202 -1
  136. package/dist/http/routes/fleet.d.ts +6 -0
  137. package/dist/http/routes/fleet.js +94 -5
  138. package/dist/http/routes/images.d.ts +17 -0
  139. package/dist/http/routes/images.js +222 -14
  140. package/dist/http/routes/leader.d.ts +7 -0
  141. package/dist/http/routes/leader.js +10 -0
  142. package/dist/http/routes/memory-policy.d.ts +6 -0
  143. package/dist/http/routes/memory-policy.js +38 -6
  144. package/dist/http/routes/notify-wake.d.ts +10 -0
  145. package/dist/http/routes/notify-wake.js +19 -3
  146. package/dist/http/routes/observability.d.ts +6 -0
  147. package/dist/http/routes/observability.js +19 -2
  148. package/dist/http/routes/runs.d.ts +15 -0
  149. package/dist/http/routes/runs.js +464 -41
  150. package/dist/http/routes/session-sync.d.ts +15 -0
  151. package/dist/http/routes/session-sync.js +229 -19
  152. package/dist/http/routes/sessions-list.d.ts +6 -0
  153. package/dist/http/routes/sessions-list.js +35 -4
  154. package/dist/http/routes/sessions.d.ts +14 -0
  155. package/dist/http/routes/sessions.js +176 -31
  156. package/dist/http/routes/side-query.d.ts +8 -0
  157. package/dist/http/routes/side-query.js +26 -1
  158. package/dist/http/routes/tasks.d.ts +18 -0
  159. package/dist/http/routes/tasks.js +501 -38
  160. package/dist/http/routes/trace-usage.d.ts +10 -0
  161. package/dist/http/routes/trace-usage.js +66 -14
  162. package/dist/http/routes/workflows.d.ts +12 -0
  163. package/dist/http/routes/workflows.js +180 -19
  164. package/dist/http/run-meta.d.ts +11 -0
  165. package/dist/http/run-meta.js +6 -0
  166. package/dist/http/send.d.ts +19 -0
  167. package/dist/http/send.js +11 -0
  168. package/dist/http/server.d.ts +255 -0
  169. package/dist/http/server.js +921 -75
  170. package/dist/http/sse-log.d.ts +15 -0
  171. package/dist/http/sse-log.js +16 -0
  172. package/dist/http/tar.d.ts +9 -0
  173. package/dist/http/tar.js +21 -5
  174. package/dist/http/wire-gate.d.ts +9 -0
  175. package/dist/http/wire-gate.js +9 -0
  176. package/dist/http/wire-types.d.ts +187 -0
  177. package/dist/http/workspace-content.d.ts +8 -0
  178. package/dist/http/workspace-content.js +10 -0
  179. package/dist/images/bake-validate.d.ts +63 -0
  180. package/dist/images/bake-validate.js +71 -1
  181. package/dist/images/manifest.d.ts +19 -0
  182. package/dist/images/manifest.js +6 -1
  183. package/dist/index.d.ts +1 -5
  184. package/dist/index.js +10 -5
  185. package/dist/key-resolver.d.ts +23 -0
  186. package/dist/key-resolver.js +27 -2
  187. package/dist/leader/diffout.d.ts +23 -0
  188. package/dist/leader/diffout.js +8 -1
  189. package/dist/leader/diffup.d.ts +32 -0
  190. package/dist/leader/diffup.js +43 -0
  191. package/dist/leader/endpoint.d.ts +20 -0
  192. package/dist/leader/endpoint.js +25 -2
  193. package/dist/leader/fanout.d.ts +60 -0
  194. package/dist/leader/fanout.js +29 -3
  195. package/dist/leader/grader-env-factory.d.ts +74 -0
  196. package/dist/leader/grader-env-factory.js +62 -3
  197. package/dist/leader/leader.d.ts +97 -0
  198. package/dist/leader/leader.js +151 -4
  199. package/dist/leader/merge.d.ts +94 -0
  200. package/dist/leader/merge.js +112 -9
  201. package/dist/leader/planner.d.ts +52 -0
  202. package/dist/leader/planner.js +47 -3
  203. package/dist/leader/repair-oracle.d.ts +61 -0
  204. package/dist/leader/repair-oracle.js +59 -1
  205. package/dist/leader/repair-wire.d.ts +78 -0
  206. package/dist/leader/repair-wire.js +79 -2
  207. package/dist/leader/wire.d.ts +79 -0
  208. package/dist/leader/wire.js +255 -8
  209. package/dist/lsp/e2b-bridge.d.ts +16 -0
  210. package/dist/lsp/e2b-bridge.js +32 -4
  211. package/dist/lsp/e2b-manager.d.ts +10 -0
  212. package/dist/lsp/e2b-manager.js +18 -2
  213. package/dist/lsp/lsp-frames.d.ts +12 -0
  214. package/dist/lsp/lsp-frames.js +12 -0
  215. package/dist/lsp/manager.d.ts +12 -0
  216. package/dist/lsp/manager.js +35 -2
  217. package/dist/lsp/types.d.ts +10 -0
  218. package/dist/lsp/ws-transport.d.ts +12 -0
  219. package/dist/lsp/ws-transport.js +53 -5
  220. package/dist/lsp-evict.d.ts +14 -0
  221. package/dist/lsp-evict.js +15 -1
  222. package/dist/main.js +2132 -96
  223. package/dist/memory-export.d.ts +1 -0
  224. package/dist/memory-export.js +4 -0
  225. package/dist/memory-scope.d.ts +49 -0
  226. package/dist/memory-scope.js +87 -4
  227. package/dist/memory-sync-client.d.ts +24 -0
  228. package/dist/memory-sync-client.js +41 -2
  229. package/dist/memory-sync.d.ts +23 -0
  230. package/dist/memory-sync.js +70 -1
  231. package/dist/model-select.d.ts +39 -0
  232. package/dist/model-select.js +42 -1
  233. package/dist/observability/cost-quota.d.ts +20 -0
  234. package/dist/observability/cost-quota.js +4 -0
  235. package/dist/observability/cost-taxonomy.d.ts +45 -0
  236. package/dist/observability/cost-taxonomy.js +34 -0
  237. package/dist/observability/logger.d.ts +1 -0
  238. package/dist/observability/logger.js +6 -0
  239. package/dist/observability/metrics.d.ts +13 -0
  240. package/dist/observability/metrics.js +63 -0
  241. package/dist/observability/otel-exporter.d.ts +9 -0
  242. package/dist/observability/otel-exporter.js +11 -3
  243. package/dist/observability/principal-context.d.ts +9 -0
  244. package/dist/observability/principal-context.js +9 -0
  245. package/dist/observability/prompt-manifest.d.ts +37 -0
  246. package/dist/observability/prompt-manifest.js +35 -1
  247. package/dist/observability/rate-limit.d.ts +10 -0
  248. package/dist/observability/rate-limit.js +1 -0
  249. package/dist/observability/tool-trace.d.ts +24 -0
  250. package/dist/observability/tool-trace.js +41 -1
  251. package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
  252. package/dist/orchestration/hardened-vm-runner.js +119 -4
  253. package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
  254. package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
  255. package/dist/orchestration/hardened-vm-worker.js +27 -0
  256. package/dist/orchestration/subagent-steer.d.ts +44 -0
  257. package/dist/orchestration/subagent-steer.js +45 -1
  258. package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
  259. package/dist/orchestration/workflow-agent-steer.js +80 -1
  260. package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
  261. package/dist/orchestration/workflow-completion-inbox.js +283 -32
  262. package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
  263. package/dist/orchestration/workflow-notify-journal.js +187 -13
  264. package/dist/parked-decide.d.ts +61 -0
  265. package/dist/parked-decide.js +58 -1
  266. package/dist/per-task-image.d.ts +54 -0
  267. package/dist/per-task-image.js +41 -0
  268. package/dist/plan-cache-probe.d.ts +35 -0
  269. package/dist/plan-cache-probe.js +18 -3
  270. package/dist/plugins/approval-exemption-store.d.ts +7 -0
  271. package/dist/plugins/approval-exemption-store.js +28 -2
  272. package/dist/plugins/approval-store-sql.d.ts +64 -0
  273. package/dist/plugins/approval-store-sql.js +32 -0
  274. package/dist/plugins/background-agent-store-sql.d.ts +55 -0
  275. package/dist/plugins/background-agent-store-sql.js +91 -4
  276. package/dist/plugins/background-shell-support.d.ts +98 -0
  277. package/dist/plugins/background-shell-support.js +117 -13
  278. package/dist/plugins/blob-backend.d.ts +104 -0
  279. package/dist/plugins/blob-backend.js +163 -6
  280. package/dist/plugins/breaker-state-sql.d.ts +65 -1
  281. package/dist/plugins/breaker-state-sql.js +46 -8
  282. package/dist/plugins/caching-session-store.d.ts +42 -0
  283. package/dist/plugins/caching-session-store.js +63 -3
  284. package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
  285. package/dist/plugins/checkpoint-store-sql.js +239 -11
  286. package/dist/plugins/file-outcome-sink.d.ts +4 -0
  287. package/dist/plugins/file-outcome-sink.js +9 -0
  288. package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
  289. package/dist/plugins/file-resume-anchor-store.js +43 -4
  290. package/dist/plugins/file-run-store.d.ts +90 -0
  291. package/dist/plugins/file-run-store.js +145 -13
  292. package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
  293. package/dist/plugins/file-snapshot-store-sql.js +178 -10
  294. package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
  295. package/dist/plugins/file-workflow-journal-store.js +10 -0
  296. package/dist/plugins/fork-routing-session-store.d.ts +47 -0
  297. package/dist/plugins/fork-routing-session-store.js +51 -3
  298. package/dist/plugins/host-platform.d.ts +69 -0
  299. package/dist/plugins/host-platform.js +81 -2
  300. package/dist/plugins/image-bake-store-sql.d.ts +136 -1
  301. package/dist/plugins/image-bake-store-sql.js +241 -7
  302. package/dist/plugins/image-index-sql.d.ts +46 -0
  303. package/dist/plugins/image-index-sql.js +113 -4
  304. package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
  305. package/dist/plugins/k8s-bg-scripts.js +88 -4
  306. package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
  307. package/dist/plugins/k8s-exec-protocol.js +41 -0
  308. package/dist/plugins/local-checkpoint-store.d.ts +40 -0
  309. package/dist/plugins/local-checkpoint-store.js +86 -7
  310. package/dist/plugins/local-session-store.d.ts +157 -0
  311. package/dist/plugins/local-session-store.js +289 -34
  312. package/dist/plugins/local-task-attachment-store.js +14 -2
  313. package/dist/plugins/mailbox-store-sql.d.ts +38 -0
  314. package/dist/plugins/mailbox-store-sql.js +39 -6
  315. package/dist/plugins/memory-engine-pg.d.ts +30 -0
  316. package/dist/plugins/memory-engine-pg.js +122 -4
  317. package/dist/plugins/memory-engine-tidb.d.ts +26 -0
  318. package/dist/plugins/memory-engine-tidb.js +115 -5
  319. package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
  320. package/dist/plugins/memory-engine-vector-util.js +5 -0
  321. package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
  322. package/dist/plugins/memory-resume-anchor-store.js +17 -0
  323. package/dist/plugins/memory-run-store.d.ts +63 -0
  324. package/dist/plugins/memory-run-store.js +73 -8
  325. package/dist/plugins/memory-session-policy-store.d.ts +17 -0
  326. package/dist/plugins/memory-session-policy-store.js +17 -0
  327. package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
  328. package/dist/plugins/memory-sync-store-pg.js +45 -2
  329. package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
  330. package/dist/plugins/memory-sync-store-tidb.js +31 -1
  331. package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
  332. package/dist/plugins/outcome-ledger-sql.js +97 -3
  333. package/dist/plugins/pg-approval-store.d.ts +7 -0
  334. package/dist/plugins/pg-approval-store.js +7 -0
  335. package/dist/plugins/pg-breaker-state.d.ts +6 -0
  336. package/dist/plugins/pg-breaker-state.js +6 -0
  337. package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
  338. package/dist/plugins/pg-checkpoint-store.js +8 -0
  339. package/dist/plugins/pg-cost-quota.d.ts +17 -0
  340. package/dist/plugins/pg-cost-quota.js +6 -0
  341. package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
  342. package/dist/plugins/pg-file-snapshot-store.js +6 -0
  343. package/dist/plugins/pg-image-bake.d.ts +9 -0
  344. package/dist/plugins/pg-image-bake.js +9 -0
  345. package/dist/plugins/pg-image-index.d.ts +9 -0
  346. package/dist/plugins/pg-image-index.js +9 -0
  347. package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
  348. package/dist/plugins/pg-outcome-ledger.js +9 -0
  349. package/dist/plugins/pg-pool.d.ts +50 -0
  350. package/dist/plugins/pg-pool.js +78 -0
  351. package/dist/plugins/pg-query.d.ts +11 -0
  352. package/dist/plugins/pg-rate-limiter.d.ts +23 -0
  353. package/dist/plugins/pg-rate-limiter.js +12 -2
  354. package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
  355. package/dist/plugins/pg-resume-anchor-store.js +5 -0
  356. package/dist/plugins/pg-run-store.d.ts +7 -0
  357. package/dist/plugins/pg-run-store.js +7 -0
  358. package/dist/plugins/pg-safe-json.d.ts +13 -0
  359. package/dist/plugins/pg-safe-json.js +40 -4
  360. package/dist/plugins/pg-session-policy-store.d.ts +5 -0
  361. package/dist/plugins/pg-session-policy-store.js +5 -0
  362. package/dist/plugins/pg-session-storage.d.ts +72 -0
  363. package/dist/plugins/pg-session-storage.js +152 -20
  364. package/dist/plugins/pg-session-store.d.ts +10 -0
  365. package/dist/plugins/pg-session-store.js +10 -0
  366. package/dist/plugins/pg-tool-result-store.d.ts +7 -0
  367. package/dist/plugins/pg-tool-result-store.js +7 -0
  368. package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
  369. package/dist/plugins/pg-workflow-journal-store.js +7 -0
  370. package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
  371. package/dist/plugins/pg-workflow-run-store.js +7 -0
  372. package/dist/plugins/posix-shell-fs.d.ts +3 -0
  373. package/dist/plugins/posix-shell-fs.js +31 -1
  374. package/dist/plugins/remote-env-adb.d.ts +25 -0
  375. package/dist/plugins/remote-env-adb.js +95 -12
  376. package/dist/plugins/remote-env-e2b.d.ts +146 -0
  377. package/dist/plugins/remote-env-e2b.js +371 -40
  378. package/dist/plugins/remote-env-file-error.d.ts +34 -0
  379. package/dist/plugins/remote-env-file-error.js +37 -0
  380. package/dist/plugins/remote-env-host.d.ts +151 -0
  381. package/dist/plugins/remote-env-host.js +468 -70
  382. package/dist/plugins/remote-env-k8s.d.ts +135 -0
  383. package/dist/plugins/remote-env-k8s.js +318 -32
  384. package/dist/plugins/remote-env-local-docker.d.ts +65 -0
  385. package/dist/plugins/remote-env-local-docker.js +149 -24
  386. package/dist/plugins/remote-env-ssh.d.ts +35 -0
  387. package/dist/plugins/remote-env-ssh.js +117 -20
  388. package/dist/plugins/remote-scratchpad.d.ts +38 -0
  389. package/dist/plugins/remote-scratchpad.js +32 -2
  390. package/dist/plugins/remote-shell.d.ts +22 -0
  391. package/dist/plugins/remote-shell.js +27 -1
  392. package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
  393. package/dist/plugins/resume-anchor-store-sql.js +11 -0
  394. package/dist/plugins/roster-store-sql.d.ts +27 -0
  395. package/dist/plugins/roster-store-sql.js +54 -0
  396. package/dist/plugins/run-store-sql.d.ts +194 -0
  397. package/dist/plugins/run-store-sql.js +210 -9
  398. package/dist/plugins/s3-presign.d.ts +20 -0
  399. package/dist/plugins/s3-presign.js +49 -2
  400. package/dist/plugins/scheduler-support.d.ts +12 -0
  401. package/dist/plugins/scheduler-support.js +75 -3
  402. package/dist/plugins/send-file-ledger.d.ts +15 -0
  403. package/dist/plugins/send-file-ledger.js +53 -4
  404. package/dist/plugins/send-user-file.d.ts +77 -0
  405. package/dist/plugins/send-user-file.js +92 -4
  406. package/dist/plugins/session-policy-store-sql.d.ts +15 -0
  407. package/dist/plugins/session-policy-store-sql.js +75 -3
  408. package/dist/plugins/session-store.d.ts +45 -0
  409. package/dist/plugins/session-store.js +51 -0
  410. package/dist/plugins/sql-driver.d.ts +77 -0
  411. package/dist/plugins/sql-driver.js +4 -0
  412. package/dist/plugins/sql-escape.d.ts +8 -0
  413. package/dist/plugins/sql-escape.js +8 -0
  414. package/dist/plugins/sql-row-helpers.d.ts +25 -0
  415. package/dist/plugins/sql-row-helpers.js +25 -0
  416. package/dist/plugins/store-backend.d.ts +103 -0
  417. package/dist/plugins/store-backend.js +120 -27
  418. package/dist/plugins/store-contracts.d.ts +62 -0
  419. package/dist/plugins/store-contracts.js +3 -0
  420. package/dist/plugins/task-attachment-store.d.ts +60 -0
  421. package/dist/plugins/task-attachment-store.js +49 -3
  422. package/dist/plugins/task-list-store-sql.d.ts +25 -0
  423. package/dist/plugins/task-list-store-sql.js +21 -0
  424. package/dist/plugins/tidb-approval-store.d.ts +6 -0
  425. package/dist/plugins/tidb-approval-store.js +6 -0
  426. package/dist/plugins/tidb-breaker-state.d.ts +5 -0
  427. package/dist/plugins/tidb-breaker-state.js +5 -0
  428. package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
  429. package/dist/plugins/tidb-checkpoint-store.js +7 -0
  430. package/dist/plugins/tidb-cost-quota.d.ts +6 -0
  431. package/dist/plugins/tidb-cost-quota.js +1 -0
  432. package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
  433. package/dist/plugins/tidb-file-snapshot-store.js +6 -0
  434. package/dist/plugins/tidb-image-bake.d.ts +8 -0
  435. package/dist/plugins/tidb-image-bake.js +8 -0
  436. package/dist/plugins/tidb-image-index.d.ts +8 -0
  437. package/dist/plugins/tidb-image-index.js +8 -0
  438. package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
  439. package/dist/plugins/tidb-outcome-ledger.js +10 -0
  440. package/dist/plugins/tidb-pool.d.ts +56 -0
  441. package/dist/plugins/tidb-pool.js +181 -1
  442. package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
  443. package/dist/plugins/tidb-rate-limiter.js +5 -2
  444. package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
  445. package/dist/plugins/tidb-resume-anchor-store.js +5 -0
  446. package/dist/plugins/tidb-run-store.d.ts +7 -0
  447. package/dist/plugins/tidb-run-store.js +7 -0
  448. package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
  449. package/dist/plugins/tidb-session-policy-store.js +5 -0
  450. package/dist/plugins/tidb-session-storage.d.ts +43 -0
  451. package/dist/plugins/tidb-session-storage.js +62 -3
  452. package/dist/plugins/tidb-session-store.d.ts +142 -0
  453. package/dist/plugins/tidb-session-store.js +264 -16
  454. package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
  455. package/dist/plugins/tidb-tool-result-store.js +7 -0
  456. package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
  457. package/dist/plugins/tidb-workflow-journal-store.js +7 -0
  458. package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
  459. package/dist/plugins/tidb-workflow-run-store.js +8 -0
  460. package/dist/plugins/tool-result-store-sql.d.ts +58 -0
  461. package/dist/plugins/tool-result-store-sql.js +38 -2
  462. package/dist/plugins/web-search.d.ts +35 -0
  463. package/dist/plugins/web-search.js +45 -9
  464. package/dist/plugins/workflow-journal-limits.d.ts +10 -0
  465. package/dist/plugins/workflow-journal-limits.js +10 -0
  466. package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
  467. package/dist/plugins/workflow-journal-store-sql.js +59 -3
  468. package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
  469. package/dist/plugins/workflow-run-store-sql.js +84 -6
  470. package/dist/plugins/worktree-isolation.d.ts +45 -0
  471. package/dist/plugins/worktree-isolation.js +105 -6
  472. package/dist/plugins/write-behind-counter.d.ts +56 -1
  473. package/dist/plugins/write-behind-counter.js +53 -14
  474. package/dist/principal-jwt.d.ts +24 -0
  475. package/dist/principal-jwt.js +60 -5
  476. package/dist/project-memory.d.ts +22 -0
  477. package/dist/project-memory.js +144 -15
  478. package/dist/prompts-domain-validate.d.ts +28 -0
  479. package/dist/prompts-domain-validate.js +42 -1
  480. package/dist/question.d.ts +33 -0
  481. package/dist/question.js +69 -2
  482. package/dist/resource-suspend.d.ts +21 -0
  483. package/dist/resource-suspend.js +16 -0
  484. package/dist/router/route-orchestration.d.ts +78 -0
  485. package/dist/router/route-orchestration.js +77 -0
  486. package/dist/run-local.d.ts +32 -0
  487. package/dist/run-local.js +172 -8
  488. package/dist/runs.d.ts +189 -4
  489. package/dist/runs.js +465 -24
  490. package/dist/runtime-caps-resolver.d.ts +106 -0
  491. package/dist/runtime-caps-resolver.js +89 -4
  492. package/dist/runtime-governance.d.ts +84 -0
  493. package/dist/runtime-governance.js +127 -1
  494. package/dist/sandbox-pkg-source.d.ts +23 -0
  495. package/dist/sandbox-pkg-source.js +37 -0
  496. package/dist/sealed-key.d.ts +54 -0
  497. package/dist/sealed-key.js +68 -3
  498. package/dist/security.d.ts +108 -0
  499. package/dist/security.js +145 -6
  500. package/dist/sema-registry.d.ts +21 -0
  501. package/dist/sema-registry.js +21 -0
  502. package/dist/session-leaf-bus.d.ts +31 -0
  503. package/dist/session-leaf-bus.js +32 -0
  504. package/dist/session-sync-content.d.ts +46 -0
  505. package/dist/session-sync-content.js +47 -1
  506. package/dist/session-sync-kernel.d.ts +89 -0
  507. package/dist/session-sync-kernel.js +48 -3
  508. package/dist/session-sync.d.ts +125 -0
  509. package/dist/session-sync.js +181 -8
  510. package/dist/session-titler.d.ts +26 -0
  511. package/dist/session-titler.js +41 -7
  512. package/dist/session-watch.d.ts +53 -1
  513. package/dist/session-watch.js +73 -9
  514. package/dist/sighup-idle.d.ts +30 -0
  515. package/dist/sighup-idle.js +12 -1
  516. package/dist/spec-fields.d.ts +91 -3
  517. package/dist/spec-fields.js +116 -4
  518. package/dist/task-cwd.d.ts +50 -0
  519. package/dist/task-cwd.js +68 -1
  520. package/dist/task-mcp.d.ts +47 -0
  521. package/dist/task-mcp.js +29 -0
  522. package/dist/task-settings.d.ts +175 -0
  523. package/dist/task-settings.js +226 -11
  524. package/dist/task-workflow.d.ts +67 -0
  525. package/dist/task-workflow.js +75 -8
  526. package/dist/tool-approval.d.ts +91 -0
  527. package/dist/tool-approval.js +215 -0
  528. package/dist/trace/artifacts.d.ts +9 -0
  529. package/dist/trace/artifacts.js +30 -5
  530. package/dist/trace/core-keyset-guard.d.ts +18 -0
  531. package/dist/trace/ledger-sink.d.ts +43 -0
  532. package/dist/trace/ledger-sink.js +64 -5
  533. package/dist/trace/project.d.ts +133 -0
  534. package/dist/trace/project.js +189 -2
  535. package/dist/trace/redact.d.ts +19 -0
  536. package/dist/trace/redact.js +66 -9
  537. package/dist/usage-analytics.d.ts +26 -0
  538. package/dist/usage-analytics.js +26 -3
  539. package/package.json +1 -1
@@ -1,43 +1,109 @@
1
+ /**
2
+ * design/103 — shared support for the remote (TOB) `BackgroundShellCapability` implementations.
3
+ *
4
+ * core defines the seam (`@sema-agent/core` `BackgroundShellCapability` + `hasBackgroundShell`) and ships the TOC
5
+ * reference (`NodeExecutionEnv`). This module centralises the **security + lifecycle red-lines** that EVERY remote
6
+ * adapter (E2B, kata/k8s, …) must enforce identically, so a transport author only writes the 4 transport
7
+ * primitives and cannot accidentally re-implement (or skip) an invariant:
8
+ *
9
+ * - **opaque shellId** — a fresh `bg_<n>_<uuid>` brand, NEVER derived from the provider's job/pid (越权红线,
10
+ * design/103 §3.8). The provider id lives only inside the driver state.
11
+ * - **owned-id isolation** — `poll`/`kill` look the shellId up in THIS manager's registry; an id from another env
12
+ * (or a forged one) is `not_found`, never resolved against the provider (design/103 §3.8 / interface 越权契约).
13
+ * - **maxConcurrent** — counts only `running` shells (terminal entries are kept for residual polling but free their
14
+ * slot, so "KillShell one first" is actionable — matches the TOC `maxConcurrent 终态占槽` review fix).
15
+ * - **timeout hard wall** — a control-plane timer kills the shell and flips it to `killed` at the bounded BG
16
+ * timeout (design/103 §3.6); the driver may set an additional provider-level backstop ≥ this wall.
17
+ * - **dispose** — kills + cleans up EVERY shell, best-effort, MUST NOT throw, idempotent (design/103 §3.7).
18
+ *
19
+ * The two transports legitimately take different "按-id-可重读" paths (design/103 §5.2): E2B holds a resident
20
+ * `CommandHandle` reader feeding a control-plane tail buffer (path ②); kata/k8s buffers into pod-side files
21
+ * re-read by byte cursor on each poll (path ①). Both are expressed through {@link BackgroundShellDriver}.
22
+ */
1
23
  import { BackgroundShellError } from "@sema-agent/core";
2
24
  import type { BackgroundShellId, BackgroundPoll, BackgroundSpawnOptions, Result } from "@sema-agent/core";
3
25
  import { StringDecoder } from "node:string_decoder";
26
+ /** Per-端 background capability bounds, surfaced as `backgroundCapabilities` on the env (design/103 §3.1/§3.6).
27
+ *
28
+ * ⚠️ 有据不接:core 契约的 `retainBackgroundProcesses` 能力字段【有意】不在此声明(2026-07-08 定谳):
29
+ * TB 的声明与兑现全在 core 自己 runtime 内闭环(sema-tb bin 进程内 TOC local env 声明,core task-registry
30
+ * settle/reap 双门控读取)——service env 全程不在链上;k8s/e2b 隔离 env 拆机进程必然消亡,声明只是名义。
31
+ * 接单信号=「远端 TB / 常驻服务题落到 service host env」,届时切片很薄(dispose `{except}` 管道已通,
32
+ * retain 只是 env 级常开白名单)。 */
4
33
  export interface BackgroundCaps {
5
34
  readonly supported: boolean;
6
35
  readonly maxConcurrent: number;
7
36
  readonly defaultBgTimeoutSec: number;
8
37
  readonly maxBgTimeoutSec: number;
9
38
  }
39
+ /** One stream's adopt-mode drain state. `pendingBytes` = queued-undrained (≤ cap); `totalBytes` = cursor metadata. */
10
40
  export interface BgMemStream {
11
41
  chunks: string[];
12
42
  pendingBytes: number;
13
43
  totalBytes: number;
14
44
  droppedBytes: number;
45
+ /** Per-stream stateful UTF-8 decoder for Buffer inputs (WS frames / pipe chunks split at arbitrary byte offsets —
46
+ * a multibyte codepoint straddling two chunks must NOT decode to U+FFFD; the incomplete tail rides to the next
47
+ * write). Mirrors the fg-path `StringDecoder` (remote-env-k8s.ts runExec, council BUG#1). Undefined until first
48
+ * Buffer feed. STRING inputs (E2B-style, already decoded by the SDK) bypass it. */
15
49
  decoder?: StringDecoder;
16
50
  }
51
+ /** Fresh drain buffer pre-seeded with the output captured before adoption (rides the first poll). `initialDropped` =
52
+ * bytes the fg segment's rolling-tail already evicted (surfaced as `truncated` on the first drain — the seed text is
53
+ * RAW, so the truncation marker is NOT baked into the stream content: review LOW, avoids double-marking + accounting
54
+ * pollution). */
17
55
  export declare function seedMemStream(text: string, initialDropped?: number): BgMemStream;
56
+ /** Append a live chunk, evicting the OLDEST queued chunks beyond `cap` (counted → surfaced as `truncated`). A Buffer
57
+ * goes through the per-stream StringDecoder (multibyte-safe across chunk boundaries); a string passes through. */
18
58
  export declare function feedMemStream(s: BgMemStream, d: Buffer | string, cap: number): void;
59
+ /** Drain everything queued since the last read (a driver `read`); resets the pending queue + dropped counter. */
19
60
  export declare function drainMemStream(s: BgMemStream): {
20
61
  text: string;
21
62
  dropped: number;
22
63
  };
64
+ /** Context handed to {@link BackgroundShellDriver.launch}. */
23
65
  export interface LaunchCtx {
66
+ /**
67
+ * Push-model terminal notification (E2B `CommandHandle.wait()` resolves/rejects): the driver invokes this exactly
68
+ * once when the process ends. Pull-model drivers (k8s, which discovers termination during {@link
69
+ * BackgroundShellDriver.read}) simply never call it and return `terminal` from `read` instead. The manager
70
+ * ignores either source once a shell has left `running` (kill/timeout win).
71
+ */
24
72
  onTerminal(failed: boolean, exitCode?: number): void;
73
+ /** Bounded effective BG timeout (sec) the driver MAY use as a provider-level backstop. ≥ the manager hard wall. */
25
74
  readonly bgTimeoutSec: number;
26
75
  }
76
+ /** One poll's worth of driver output: raw increment since the driver's own cursor + head-evict accounting. */
27
77
  export interface DriverPoll {
78
+ /** New stdout since last read (RAW — core's `BashOutput` tool applies `filter` + display truncation). */
28
79
  stdout: string;
80
+ /** New stderr since last read. */
29
81
  stderr: string;
82
+ /** Total output bytes the process has produced from start (cursor metadata; design/103 §3.4). */
30
83
  bytesFromStart: number;
84
+ /** Bytes permanently lost to head-eviction before this read's cursor (0 if none). */
31
85
  bytesDroppedBeforeCursor: number;
86
+ /**
87
+ * Pull-model termination signal (k8s): the process is no longer running. `undefined` ⇒ still running / unknown.
88
+ * Push-model drivers (E2B) leave this `undefined` and use {@link LaunchCtx.onTerminal} instead.
89
+ */
32
90
  terminal?: {
33
91
  failed: boolean;
34
92
  exitCode?: number;
35
93
  };
36
94
  }
95
+ /**
96
+ * Transport primitives a remote adapter implements. The driver owns its per-shell state `S` (handles, tail buffers,
97
+ * pod-side cursors) and the transport mechanics; the {@link BackgroundShellManager} owns all the shared invariants.
98
+ */
37
99
  export interface BackgroundShellDriver<S> {
100
+ /** Launch a detached process. Return per-shell transport state. MUST NOT block on exit. Throw `BackgroundShellError` on failure. */
38
101
  launch(command: string, options: BackgroundSpawnOptions | undefined, ctx: LaunchCtx): Promise<S>;
102
+ /** Read incremental output (+ maybe terminal). Safe to call repeatedly across independent poll calls. */
39
103
  read(state: S): Promise<DriverPoll>;
104
+ /** Transport-level kill (best-effort, idempotent — killing an already-dead process is a no-op). */
40
105
  kill(state: S): Promise<void>;
106
+ /** Best-effort cleanup of ONE shell's transport resources (kill + remove temp dirs/handles). Should not throw. */
41
107
  disposeOne(state: S): Promise<void>;
42
108
  }
43
109
  export declare class BackgroundShellManager<S> {
@@ -46,18 +112,50 @@ export declare class BackgroundShellManager<S> {
46
112
  private readonly shells;
47
113
  private counter;
48
114
  constructor(driver: BackgroundShellDriver<S>, caps: BackgroundCaps);
115
+ /** [1116] 六轮复审:destroy 端判「还有 shell 依赖 spool 文件吗」——running(驻留 keep-alive)与
116
+ * terminal 残余(dispose 前仍可轮询)都算;有=env 不得整树删 spool 根(逐 shell 清理归 dispose 面)。 */
49
117
  hasShells(): boolean;
118
+ /** Count live shells; KillShell/timeout flip a shell out of `running` and free its slot. */
50
119
  private liveCount;
120
+ /** Bound heap: evict the OLDEST terminal entries (never a running one) once the registry exceeds the retention cap. */
51
121
  private evictOldTerminal;
52
122
  spawn(command: string, options?: BackgroundSpawnOptions): Promise<Result<{
53
123
  shellId: BackgroundShellId;
54
124
  }, BackgroundShellError>>;
125
+ /**
126
+ * design/116 detach (clay 排,1.81): adopt an EXTERNALLY-created RUNNING process as a background shell — the
127
+ * mid-flight ctrl+b path, where the process was spawned by a FOREGROUND `exec` and must move under this
128
+ * manager's ownership instead of being killed. The `builder` receives the same {@link LaunchCtx} a driver
129
+ * `launch` would (terminal notification + the bounded BG timeout it may use as a backstop) and returns the
130
+ * driver state the normal `read`/`kill`/`disposeOne` primitives operate on — after adoption the shell is
131
+ * indistinguishable from a spawned one (poll/kill/dispose/timeout wall all apply). Returns `undefined` when
132
+ * the live-shell limit is hit OR the builder throws: detach REFUSED, the caller keeps the process running in
133
+ * the foreground (core NodeExecutionEnv semantics — never a silently dropped process).
134
+ *
135
+ * 🔴 SYNCHRONOUS by contract (double-review of the first async cut, 3 confirmed findings): the builder must
136
+ * attach the live child's pipe listeners in the SAME synchronous tick it snapshots the seed, with NO `await`
137
+ * before registration — otherwise (a) output produced during an async open/mkdir window is lost, (b) file fds
138
+ * leak on natural exit, and (c) an exec-settle can race the async adoption and orphan a shell. A sync builder
139
+ * (memory-buffered, no files) closes all three: no Node data/close event can interleave a synchronous block.
140
+ *
141
+ * 🔴 builder side-effect contract (Fable-5 review #5): the catch below returns undefined WITHOUT undoing any
142
+ * side effects the builder already performed (listener attach, stream reroute). A builder must therefore be
143
+ * all-or-nothing: put every operation that can throw BEFORE the first side effect, or clean up on the throw
144
+ * path itself. Today's three lane builders are entirely non-throwing (listener attach + object construction).
145
+ */
55
146
  adoptSync(builder: (ctx: LaunchCtx) => S, timeoutSec?: number): {
56
147
  shellId: BackgroundShellId;
57
148
  } | undefined;
149
+ /** The shared spawn/adopt body: limit check, opaque id, terminal-latch buffering, BG-timeout hard wall. */
58
150
  private register;
59
151
  poll(shellId: BackgroundShellId): Promise<Result<BackgroundPoll, BackgroundShellError>>;
60
152
  kill(shellId: BackgroundShellId): Promise<Result<void, BackgroundShellError>>;
153
+ /** Kill + clean up EVERY shell. Best-effort, MUST NOT throw, idempotent (design/103 §3.7).
154
+ *
155
+ * core `except` 契约(background-shell.d.ts:core runtask 尾调 `{except: keepAlive}`):
156
+ * 这些 shellId **留活**——session 驻留 persistent Monitor 的进程,其全部意义就是跨 turn 存活;run-end
157
+ * 全灭会留下「registry handle 活着、进程死了」的孤儿 watch。留活条目连注册表一起保留(poll/kill 继续
158
+ * 可用,timeout 墙钟 timer 不清=到点照杀)。无参=既有全灭行为(suspend/review 前的 dispose 不带 except)。 */
61
159
  dispose(opts?: {
62
160
  except?: readonly BackgroundShellId[];
63
161
  }): Promise<void>;
@@ -1,16 +1,44 @@
1
+ /**
2
+ * design/103 — shared support for the remote (TOB) `BackgroundShellCapability` implementations.
3
+ *
4
+ * core defines the seam (`@sema-agent/core` `BackgroundShellCapability` + `hasBackgroundShell`) and ships the TOC
5
+ * reference (`NodeExecutionEnv`). This module centralises the **security + lifecycle red-lines** that EVERY remote
6
+ * adapter (E2B, kata/k8s, …) must enforce identically, so a transport author only writes the 4 transport
7
+ * primitives and cannot accidentally re-implement (or skip) an invariant:
8
+ *
9
+ * - **opaque shellId** — a fresh `bg_<n>_<uuid>` brand, NEVER derived from the provider's job/pid (越权红线,
10
+ * design/103 §3.8). The provider id lives only inside the driver state.
11
+ * - **owned-id isolation** — `poll`/`kill` look the shellId up in THIS manager's registry; an id from another env
12
+ * (or a forged one) is `not_found`, never resolved against the provider (design/103 §3.8 / interface 越权契约).
13
+ * - **maxConcurrent** — counts only `running` shells (terminal entries are kept for residual polling but free their
14
+ * slot, so "KillShell one first" is actionable — matches the TOC `maxConcurrent 终态占槽` review fix).
15
+ * - **timeout hard wall** — a control-plane timer kills the shell and flips it to `killed` at the bounded BG
16
+ * timeout (design/103 §3.6); the driver may set an additional provider-level backstop ≥ this wall.
17
+ * - **dispose** — kills + cleans up EVERY shell, best-effort, MUST NOT throw, idempotent (design/103 §3.7).
18
+ *
19
+ * The two transports legitimately take different "按-id-可重读" paths (design/103 §5.2): E2B holds a resident
20
+ * `CommandHandle` reader feeding a control-plane tail buffer (path ②); kata/k8s buffers into pod-side files
21
+ * re-read by byte cursor on each poll (path ①). Both are expressed through {@link BackgroundShellDriver}.
22
+ */
1
23
  import { BackgroundShellError } from "@sema-agent/core";
2
24
  import { randomUUID } from "node:crypto";
3
25
  import { StringDecoder } from "node:string_decoder";
4
26
  const ok = (value) => ({ ok: true, value });
5
27
  const fail = (error) => ({ ok: false, error });
28
+ /** Fresh drain buffer pre-seeded with the output captured before adoption (rides the first poll). `initialDropped` =
29
+ * bytes the fg segment's rolling-tail already evicted (surfaced as `truncated` on the first drain — the seed text is
30
+ * RAW, so the truncation marker is NOT baked into the stream content: review LOW, avoids double-marking + accounting
31
+ * pollution). */
6
32
  export function seedMemStream(text, initialDropped = 0) {
7
33
  const n = Buffer.byteLength(text, "utf8");
8
34
  return { chunks: text ? [text] : [], pendingBytes: n, totalBytes: n, droppedBytes: initialDropped };
9
35
  }
36
+ /** Append a live chunk, evicting the OLDEST queued chunks beyond `cap` (counted → surfaced as `truncated`). A Buffer
37
+ * goes through the per-stream StringDecoder (multibyte-safe across chunk boundaries); a string passes through. */
10
38
  export function feedMemStream(s, d, cap) {
11
39
  const text = typeof d === "string" ? d : (s.decoder ??= new StringDecoder("utf8")).write(d);
12
40
  if (!text)
13
- return;
41
+ return; // decoder buffered an incomplete-codepoint tail → nothing to enqueue this frame
14
42
  const n = Buffer.byteLength(text, "utf8");
15
43
  s.chunks.push(text);
16
44
  s.pendingBytes += n;
@@ -21,14 +49,21 @@ export function feedMemStream(s, d, cap) {
21
49
  s.pendingBytes -= db;
22
50
  s.droppedBytes += db;
23
51
  }
52
+ // A SINGLE chunk larger than the cap (a giant WS frame / one enormous SDK string) is not covered by the
53
+ // drop-oldest loop above (it never evicts the last chunk) — trim its HEAD so the retained bytes stay ~cap
54
+ // instead of max(cap, largestChunk) (the cap comment otherwise promised more than the
55
+ // code delivered). Byte-slice like RollingTailBuffer's partial head-drop: a multibyte codepoint cut at the trim
56
+ // point decodes to replacement char(s) at the very start of the retained tail (may exceed cap by a few bytes on
57
+ // re-measure) — harmless, the stream is already marked truncated.
24
58
  if (s.pendingBytes > cap && s.chunks.length === 1) {
25
59
  const only = Buffer.from(s.chunks[0], "utf8");
26
60
  const over = only.length - cap;
27
61
  s.chunks[0] = only.subarray(over).toString("utf8");
28
- s.pendingBytes = Buffer.byteLength(s.chunks[0], "utf8");
62
+ s.pendingBytes = Buffer.byteLength(s.chunks[0], "utf8"); // re-measure: the cut may add a replacement char
29
63
  s.droppedBytes += over;
30
64
  }
31
65
  }
66
+ /** Drain everything queued since the last read (a driver `read`); resets the pending queue + dropped counter. */
32
67
  export function drainMemStream(s) {
33
68
  const text = s.chunks.join("");
34
69
  s.chunks = [];
@@ -37,6 +72,17 @@ export function drainMemStream(s) {
37
72
  s.droppedBytes = 0;
38
73
  return { text, dropped };
39
74
  }
75
+ /**
76
+ * Drives the {@link BackgroundShellCapability} contract over a {@link BackgroundShellDriver}. One instance per env
77
+ * (its registry == that env's owned shells), so cross-env / forged ids never resolve.
78
+ */
79
+ /**
80
+ * Recent terminal (exited/killed/failed) shells are kept pollable for residual output until dispose (design/103),
81
+ * but an unbounded run that spawns thousands of short background shells would otherwise accumulate them — and each
82
+ * E2B entry pins an 8MB tail buffer — until the task ends (workflow MED, worker-heap bound). Cap how many terminal
83
+ * entries linger: evicting the OLDEST → a later poll of it is `not_found` ("already reaped"), which the BashOutput
84
+ * tool already handles gracefully.
85
+ */
40
86
  const RETAIN_TERMINAL = 32;
41
87
  export class BackgroundShellManager {
42
88
  driver;
@@ -47,9 +93,12 @@ export class BackgroundShellManager {
47
93
  this.driver = driver;
48
94
  this.caps = caps;
49
95
  }
96
+ /** [1116] 六轮复审:destroy 端判「还有 shell 依赖 spool 文件吗」——running(驻留 keep-alive)与
97
+ * terminal 残余(dispose 前仍可轮询)都算;有=env 不得整树删 spool 根(逐 shell 清理归 dispose 面)。 */
50
98
  hasShells() {
51
99
  return this.shells.size > 0;
52
100
  }
101
+ /** Count live shells; KillShell/timeout flip a shell out of `running` and free its slot. */
53
102
  liveCount() {
54
103
  let n = 0;
55
104
  for (const e of this.shells.values())
@@ -57,6 +106,7 @@ export class BackgroundShellManager {
57
106
  n++;
58
107
  return n;
59
108
  }
109
+ /** Bound heap: evict the OLDEST terminal entries (never a running one) once the registry exceeds the retention cap. */
60
110
  evictOldTerminal() {
61
111
  const max = this.caps.maxConcurrent + RETAIN_TERMINAL;
62
112
  if (this.shells.size <= max)
@@ -65,7 +115,7 @@ export class BackgroundShellManager {
65
115
  if (this.shells.size <= max)
66
116
  break;
67
117
  if (e.status === "running")
68
- continue;
118
+ continue; // never evict a live shell
69
119
  this.shells.delete(id);
70
120
  if (e.timer)
71
121
  clearTimeout(e.timer);
@@ -75,11 +125,33 @@ export class BackgroundShellManager {
75
125
  async spawn(command, options) {
76
126
  return this.register((ctx) => this.driver.launch(command, options, ctx), options?.timeout);
77
127
  }
128
+ /**
129
+ * design/116 detach (clay 排,1.81): adopt an EXTERNALLY-created RUNNING process as a background shell — the
130
+ * mid-flight ctrl+b path, where the process was spawned by a FOREGROUND `exec` and must move under this
131
+ * manager's ownership instead of being killed. The `builder` receives the same {@link LaunchCtx} a driver
132
+ * `launch` would (terminal notification + the bounded BG timeout it may use as a backstop) and returns the
133
+ * driver state the normal `read`/`kill`/`disposeOne` primitives operate on — after adoption the shell is
134
+ * indistinguishable from a spawned one (poll/kill/dispose/timeout wall all apply). Returns `undefined` when
135
+ * the live-shell limit is hit OR the builder throws: detach REFUSED, the caller keeps the process running in
136
+ * the foreground (core NodeExecutionEnv semantics — never a silently dropped process).
137
+ *
138
+ * 🔴 SYNCHRONOUS by contract (double-review of the first async cut, 3 confirmed findings): the builder must
139
+ * attach the live child's pipe listeners in the SAME synchronous tick it snapshots the seed, with NO `await`
140
+ * before registration — otherwise (a) output produced during an async open/mkdir window is lost, (b) file fds
141
+ * leak on natural exit, and (c) an exec-settle can race the async adoption and orphan a shell. A sync builder
142
+ * (memory-buffered, no files) closes all three: no Node data/close event can interleave a synchronous block.
143
+ *
144
+ * 🔴 builder side-effect contract (Fable-5 review #5): the catch below returns undefined WITHOUT undoing any
145
+ * side effects the builder already performed (listener attach, stream reroute). A builder must therefore be
146
+ * all-or-nothing: put every operation that can throw BEFORE the first side effect, or clean up on the throw
147
+ * path itself. Today's three lane builders are entirely non-throwing (listener attach + object construction).
148
+ */
78
149
  adoptSync(builder, timeoutSec) {
79
150
  if (this.liveCount() >= this.caps.maxConcurrent)
80
- return undefined;
151
+ return undefined; // refused → exec keeps the foreground
152
+ // Bounded BG timeout — never unbounded (design/103 §3.6). `maxBgTimeoutSec` is the fail-closed ceiling.
81
153
  const bgTimeoutSec = Math.min(Math.max(1, timeoutSec ?? this.caps.defaultBgTimeoutSec), this.caps.maxBgTimeoutSec);
82
- const shellId = `bg_${++this.counter}_${randomUUID()}`;
154
+ const shellId = `bg_${++this.counter}_${randomUUID()}`; // opaque — never the provider pid (§3.8)
83
155
  const applyTerminal = (e, failed, exitCode) => {
84
156
  if (e.status !== "running")
85
157
  return;
@@ -89,6 +161,8 @@ export class BackgroundShellManager {
89
161
  if (e.timer)
90
162
  clearTimeout(e.timer);
91
163
  };
164
+ // terminal-latch: an already-exited adopted child fires onTerminal DURING the builder (before shells.set) —
165
+ // buffer it, drain after registration (else the shell lies "running" until the timeout wall).
92
166
  let entry;
93
167
  let pending;
94
168
  const onTerminal = (failed, exitCode) => {
@@ -99,10 +173,10 @@ export class BackgroundShellManager {
99
173
  };
100
174
  let state;
101
175
  try {
102
- state = builder({ onTerminal, bgTimeoutSec });
176
+ state = builder({ onTerminal, bgTimeoutSec }); // SYNC — no await, no interleaving event
103
177
  }
104
178
  catch {
105
- return undefined;
179
+ return undefined; // adoption failed → exec keeps the foreground (never a dropped process)
106
180
  }
107
181
  const timer = setTimeout(() => {
108
182
  const e = this.shells.get(shellId);
@@ -119,21 +193,29 @@ export class BackgroundShellManager {
119
193
  this.evictOldTerminal();
120
194
  return { shellId };
121
195
  }
196
+ /** The shared spawn/adopt body: limit check, opaque id, terminal-latch buffering, BG-timeout hard wall. */
122
197
  async register(launch, timeoutSec) {
123
198
  if (this.liveCount() >= this.caps.maxConcurrent) {
124
199
  return fail(new BackgroundShellError("limit_exceeded", `Too many running background shells (max ${this.caps.maxConcurrent}); KillShell one first.`));
125
200
  }
201
+ // Bounded BG timeout — never unbounded (design/103 §3.6). `maxBgTimeoutSec` is the fail-closed ceiling.
126
202
  const bgTimeoutSec = Math.min(Math.max(1, timeoutSec ?? this.caps.defaultBgTimeoutSec), this.caps.maxBgTimeoutSec);
203
+ // Opaque brand — NOT derived from the provider job/pid (design/103 §3.8 越权红线).
127
204
  const shellId = `bg_${++this.counter}_${randomUUID()}`;
128
205
  const applyTerminal = (e, failed, exitCode) => {
129
206
  if (e.status !== "running")
130
- return;
207
+ return; // kill / timeout already classified it (terminal-latch)
131
208
  e.status = failed ? "failed" : "exited";
132
209
  if (exitCode !== undefined)
133
210
  e.exitCode = exitCode;
134
211
  if (e.timer)
135
212
  clearTimeout(e.timer);
136
213
  };
214
+ // 🔴 A FAST-exiting process can settle `handle.wait()` and fire `onTerminal` (a microtask) BEFORE this method's
215
+ // post-`launch` continuation registers the entry — so onTerminal MUST buffer into `pendingTerminal` when the
216
+ // entry isn't live yet, and the continuation drains it after `shells.set` (else the shell would lie "running"
217
+ // until the timeout, wedging a maxConcurrent slot). (An ADOPTED child can equally have already
218
+ // exited between the detach request and adoption — the same latch covers it.)
137
219
  let entry;
138
220
  let pendingTerminal;
139
221
  const onTerminal = (failed, exitCode) => {
@@ -153,21 +235,32 @@ export class BackgroundShellManager {
153
235
  const e = this.shells.get(shellId);
154
236
  if (!e || e.status !== "running")
155
237
  return;
156
- e.status = "killed";
238
+ e.status = "killed"; // BG timeout is a HARD wall → killed (design/103 §3.6)
157
239
  void this.driver.kill(e.state).catch(() => { });
158
240
  }, bgTimeoutSec * 1000);
159
241
  timer.unref?.();
160
242
  entry = { state, status: "running", timer };
161
243
  this.shells.set(shellId, entry);
162
244
  if (pendingTerminal)
163
- applyTerminal(entry, pendingTerminal.failed, pendingTerminal.exitCode);
164
- this.evictOldTerminal();
245
+ applyTerminal(entry, pendingTerminal.failed, pendingTerminal.exitCode); // process already exited during launch
246
+ this.evictOldTerminal(); // bound the heap (recent terminal shells stay pollable; old ones are reaped)
165
247
  return ok({ shellId });
166
248
  }
167
249
  async poll(shellId) {
168
250
  const entry = this.shells.get(shellId);
251
+ // Owned-id isolation: unknown / cross-env / forged id → not_found, never leak existence (design/103 §3.8).
169
252
  if (!entry)
170
253
  return fail(new BackgroundShellError("not_found", `Unknown background shell: ${shellId}`));
254
+ // 🔴 **状态快照必须在 read 之前取**(2026-07-26,一条整天间歇红的 CI 追下来的真缺陷)。
255
+ // push 模型的终态是**异步**落地的(host: `child.on("close") → ctx.onTerminal`;E2B: `wait()` resolve),
256
+ // 所以「先 read 再读 entry.status」存在这个窗口:
257
+ // 读完输出(尾巴还没写完)→ 进程写完尾巴并结束 → status 变终态 → 返回 `{stdout: 缺尾巴, status: 终态}`。
258
+ // 而 `BashOutput` 这类消费方**看到终态就停止轮询** ⇒ 那段尾巴此后没有任何人会去读 = **静默丢输出**。
259
+ // (单跑时窗口极窄——隔离跑 12/12 全绿;高并行负载下两个 await 之间被调度出去,窗口变宽就复现。)
260
+ // ⇒ 只把「read **之前**就已经是终态」或「本次 read **自己**带回 terminal」这两种情况报为终态:
261
+ // 前者说明这次读发生在进程结束之后(输出必然完整),后者是同一次读里的一致视图(输出与终态同源)。
262
+ // 终态若是在读**之后**才到的,这一拍如实报 `running` —— 消费方多轮询一拍即可拿到尾巴 + 终态。
263
+ // 代价:最多多一拍轮询。收益:「终态 ⇒ 输出已完整」这条消费方真正依赖的保证成立。
171
264
  const statusBeforeRead = entry.status;
172
265
  let r;
173
266
  try {
@@ -176,6 +269,7 @@ export class BackgroundShellManager {
176
269
  catch (e) {
177
270
  return fail(e instanceof BackgroundShellError ? e : new BackgroundShellError("io", e instanceof Error ? e.message : String(e), e));
178
271
  }
272
+ // Pull-model terminal reconciliation (k8s): apply only if not already classified by kill/timeout.
179
273
  if (r.terminal && entry.status === "running") {
180
274
  entry.status = r.terminal.failed ? "failed" : "exited";
181
275
  if (r.terminal.exitCode !== undefined)
@@ -183,12 +277,14 @@ export class BackgroundShellManager {
183
277
  if (entry.timer)
184
278
  clearTimeout(entry.timer);
185
279
  }
280
+ // 见上方旁注:读之后才到的终态,本拍不报(下一拍的快照就是终态,那时输出已完整)。
186
281
  const reportTerminal = statusBeforeRead !== "running" || r.terminal !== undefined;
187
282
  const reportedStatus = reportTerminal ? entry.status : "running";
188
283
  return ok({
189
284
  stdout: r.stdout,
190
285
  stderr: r.stderr,
191
286
  status: reportedStatus,
287
+ // exitCode 只随终态一起报——报 running 却带 exitCode 会让消费方读出自相矛盾的一拍。
192
288
  ...(reportTerminal && entry.exitCode !== undefined ? { exitCode: entry.exitCode } : {}),
193
289
  ...(r.bytesDroppedBeforeCursor > 0 ? { truncated: true, bytesDroppedBeforeCursor: r.bytesDroppedBeforeCursor } : {}),
194
290
  bytesFromStart: r.bytesFromStart,
@@ -206,24 +302,31 @@ export class BackgroundShellManager {
206
302
  await this.driver.kill(entry.state);
207
303
  }
208
304
  catch {
305
+ /* idempotent: killing an already-dead shell is a no-op success (design/103 §4.3) */
209
306
  }
210
307
  }
211
308
  return ok(undefined);
212
309
  }
310
+ /** Kill + clean up EVERY shell. Best-effort, MUST NOT throw, idempotent (design/103 §3.7).
311
+ *
312
+ * core `except` 契约(background-shell.d.ts:core runtask 尾调 `{except: keepAlive}`):
313
+ * 这些 shellId **留活**——session 驻留 persistent Monitor 的进程,其全部意义就是跨 turn 存活;run-end
314
+ * 全灭会留下「registry handle 活着、进程死了」的孤儿 watch。留活条目连注册表一起保留(poll/kill 继续
315
+ * 可用,timeout 墙钟 timer 不清=到点照杀)。无参=既有全灭行为(suspend/review 前的 dispose 不带 except)。 */
213
316
  async dispose(opts) {
214
317
  const keep = opts?.except?.length ? new Set(opts.except) : undefined;
215
318
  const doomed = [];
216
319
  if (keep) {
217
320
  for (const [id, entry] of [...this.shells]) {
218
321
  if (keep.has(id))
219
- continue;
322
+ continue; // 留活:不 kill、不清 timer、不出注册表
220
323
  this.shells.delete(id);
221
324
  doomed.push(entry);
222
325
  }
223
326
  }
224
327
  else {
225
328
  doomed.push(...this.shells.values());
226
- this.shells.clear();
329
+ this.shells.clear(); // idempotent: a second dispose iterates nothing
227
330
  }
228
331
  for (const entry of doomed) {
229
332
  try {
@@ -234,6 +337,7 @@ export class BackgroundShellManager {
234
337
  await this.driver.disposeOne(entry.state);
235
338
  }
236
339
  catch {
340
+ /* best-effort; disposeBackgroundShells MUST never throw (design/103 §3.7) */
237
341
  }
238
342
  }
239
343
  }
@@ -1,26 +1,76 @@
1
1
  import type { Pool as MysqlPool } from "mysql2/promise";
2
2
  import type { Pool as PgPool } from "pg";
3
+ /** (a)(clay 拍 a+c,2026-07-27)tidb 方言的默认 per-blob 帽 = **6 MiB,TiDB 自己的默认
4
+ * `txn-entry-size-limit`**。两堵墙真库实测(k3s8 tidb-test v7.5.1 默认配置,2026-07-27 探针):
5
+ * 7MiB=`entry too large`(entry 墙,默认 6291456)、31MiB=同、32MiB=`max_allowed_packet`(包墙,
6
+ * 64MiB ÷ ~2× 文本协议膨胀)——矮墙是 entry 的 6MiB,不是先前推测的包墙 ~31MiB。帽=诚实拒绝:
7
+ * 超限 blob 在 query 之前 typed 拒(消费面 HTTP 413 / capture warn 拿到可行动信息);**帽拒绝的
8
+ * 在默认配置下本来也落不进去 ⇒ 零回归**。调大过 entry 限/packet 的部署用 SNAPSHOT_BLOB_SQL_MAX_BYTES
9
+ * 放宽(两方言都生效)。**pg 方言默认不设帽**(扩展协议无这两堵墙,不人为降档)。D-1 附件战役同墙
10
+ * 教训:task-attachment-store.ts:19。 */
3
11
  export declare const SQL_BLOB_DEFAULT_MAX_BYTES = 6291456;
12
+ /** typed 判别错:blob 超过 SQL 店的承载帽。判别码供店侧结果映射/HTTP 面/日志使用——绝不能与
13
+ * transient 写失败混在一类(那类是可重试的 502;这类重试永远不会成功)。 */
4
14
  export declare class BlobTooLargeError extends Error {
5
15
  readonly code: "blob_too_large_for_sql";
6
16
  constructor(byteLen: number, capBytes: number);
7
17
  }
18
+ /**
19
+ * The content-addressed byte store. All four methods are keyed on the sha256 `hash` of the bytes:
20
+ * - putBlob: store bytes (idempotent — a repeat for the same hash is a no-op-equivalent; the SQL twin refreshes
21
+ * created_at so a just-written/re-used blob is GC-grace-protected). MinIO PUTs the object AND upserts the SQL INDEX.
22
+ * - getBlob: the bytes for `hash`, or undefined if absent. A TRANSIENT backend fault THROWS (so a restore/import fails
23
+ * LOUD, not a silent "missing blob"); only a genuine absence / corruption is undefined.
24
+ * - hasBlobs: the subset of `hashes` that already exist — a single SQL `IN(...)` over the index for BOTH backends
25
+ * (migration idempotency + reap probing + the §10 import presence pre-check; cheaper than a HEAD-per-hash on MinIO).
26
+ * - deleteBlobs: byte-delete the given hashes (called ONLY by the async sweep reaper). Honors the SAME created_at
27
+ * grace window as the SQL backend (MinIO reads the index's created_at) — delete-in-use is impossible. Returns the
28
+ * count ACTUALLY deleted (the grace-passed subset), so the sweep reports real work, not the pre-grace orphan count.
29
+ */
8
30
  export interface BlobBackend {
9
31
  putBlob(hash: string, bytes: Uint8Array): Promise<void>;
10
32
  getBlob(hash: string): Promise<Uint8Array | undefined>;
11
33
  hasBlobs(hashes: string[]): Promise<Set<string>>;
12
34
  deleteBlobs(hashes: string[]): Promise<number>;
13
35
  }
36
+ /**
37
+ * SQL BlobBackend — the `snapshot_blob` table ops EXTRACTED VERBATIM from the tidb/pg file-snapshot stores (the
38
+ * created_at-refreshing upsert, the bytes SELECT, the grace-window orphan DELETE→deleteBlobs, a has via SELECT). Two
39
+ * dialect twins selected by `dialect`. Keeping the SQL byte-identical means the existing behaviour + the env-gated
40
+ * real-DB integration suite are unchanged when MinIO is unset (the DEFAULT backend the file-snapshot stores construct).
41
+ *
42
+ * NOTE deleteBlobs here is the BYTE delete ONLY — it does NOT do the `NOT IN (SELECT … snapshot_manifest)` orphan
43
+ * filter (that reference check stays in the file-snapshot store, which computes the orphan hash SET from the manifest
44
+ * and hands it here). The grace-window `created_at < cutoff` guard is RETAINED on the delete so a just-written blob
45
+ * that a concurrent in-flight snapshot still needs is never byte-deleted (delete-in-use is data loss; under-delete is
46
+ * harmless — the next sweep collects it).
47
+ */
14
48
  export declare class SqlBlobBackend implements BlobBackend {
15
49
  private readonly dialect;
16
50
  private readonly pool;
51
+ /** Effective per-blob cap: explicit ctor value wins; else tidb=SQL_BLOB_DEFAULT_MAX_BYTES, pg=uncapped. */
17
52
  private readonly capBytes;
18
53
  constructor(dialect: "tidb" | "pg", pool: MysqlPool | PgPool, maxBytes?: number);
54
+ /** The created_at-refreshing content-addressed upsert — VERBATIM the tidb/pg stores' `putBlobRow`. Refreshes
55
+ * created_at even on a dedup hit so a re-used/just-written blob is "touched=now" and GC-grace-protected.
56
+ * (a): an over-cap blob is REJECTED (typed {@link BlobTooLargeError}) BEFORE the driver ever sees the bytes —
57
+ * the alternative is an inscrutable packet-limit error deep in the driver, and on the HTTP face a 502 that
58
+ * invites the peer to retry a blob that can never land. */
19
59
  putBlob(hash: string, bytes: Uint8Array): Promise<void>;
60
+ /** The bytes for `hash` (undefined if absent) — VERBATIM the tidb/pg stores' getBlob SELECT. A pool/query error
61
+ * PROPAGATES (a transient DB fault is loud, not a silent "missing blob" — parity with the MinIO backend's throw). */
20
62
  getBlob(hash: string): Promise<Uint8Array | undefined>;
63
+ /** The subset of `hashes` that exist — a single `blob_hash IN (...)` SELECT (idempotency / reap probe). */
21
64
  hasBlobs(hashes: string[]): Promise<Set<string>>;
65
+ /** Byte-delete the given hashes (the orphan SET is computed by the caller from snapshot_manifest). Retains the
66
+ * grace-window guard so a just-written blob a concurrent in-flight snapshot needs is never delete-in-use — VERBATIM
67
+ * the tidb/pg stores' gcOrphanBlobs delete, minus the `NOT IN (SELECT … manifest)` clause (the caller already
68
+ * excluded referenced hashes). Best-effort: a delete error is swallowed (under-delete is harmless). */
22
69
  deleteBlobs(hashes: string[]): Promise<number>;
23
70
  }
71
+ /** SHARED index op(workspace 浏览面 #3,[1894]②)—— per-blob 字节数,读 SQL INDEX 的 `byte_len`
72
+ * 列(sqlHasBlobs 同款单 IN 查询;MinIO 后端的 bytes-NULL 索引行同样带 byte_len,两后端同源)。
73
+ * tree/file 面的 size 投影与「超限先拒后拉」都靠它——绝不为拿大小去 getBlob 整块字节。 */
24
74
  export declare function sqlBlobSizes(dialect: "tidb" | "pg", pool: MysqlPool | PgPool, hashes: string[]): Promise<Map<string, number>>;
25
75
  export interface MinioBlobBackendConfig {
26
76
  endpoint: string;
@@ -28,14 +78,38 @@ export interface MinioBlobBackendConfig {
28
78
  accessKey: string;
29
79
  secretKey: string;
30
80
  region?: string;
81
+ /** Key prefix for blob objects, e.g. "blobs/". Object key = keyPrefix + hash. Default "blobs/". */
31
82
  keyPrefix?: string;
83
+ /** Presigned-URL TTL (seconds). Default 3600 (1h) — must comfortably exceed a ~64 MiB single-PUT/GET on a slow link
84
+ * (a SigV4 X-Amz-Expires bounds the WHOLE transfer from X-Amz-Date; a too-short TTL fails mid-stream). */
32
85
  presignTtlSec?: number;
86
+ /** 测试注入口(listObjects 分页钉用);生产缺省 global fetch。 */
33
87
  fetchImpl?: typeof fetch;
34
88
  }
89
+ /**
90
+ * MinIO BlobBackend — content-addressed bytes in an S3-compatible object store, via the zero-dependency
91
+ * {@link presignS3Url} SigV4 generator + `fetch` (NO S3 SDK; the repo's no-SDK posture). The object key is
92
+ * `keyPrefix + hash` (content-addressed → idempotent PUT, dedup across snapshots is automatic).
93
+ *
94
+ * THE SQL INDEX: the bytes go to MinIO, but a `snapshot_blob` INDEX row `(blob_hash, byte_len, created_at)` with bytes
95
+ * NULL is kept in SQL (same pool/dialect). This is what makes the orphan-reference computation + the created_at grace
96
+ * window + the §10 presence pre-check work identically to the SQL backend (see the file header). hasBlobs reads the
97
+ * index; putBlob PUTs then upserts the index (created_at-refresh on conflict); deleteBlobs deletes the grace-passed
98
+ * index rows AND the matching MinIO objects (called ONLY from the async sweep reaper).
99
+ *
100
+ * INTEGRITY (security-critical): getBlob VERIFIES sha256(bytes) === hash before returning. A content-addressed store's
101
+ * whole safety rests on bytes-match-hash; a mismatch means corruption (network) or POISONING (a hostile object written
102
+ * under a hash it doesn't match) — treated as ABSENT (undefined), NEVER returning wrong bytes. This mirrors the
103
+ * importManifest content-address check the SQL stores already do.
104
+ */
35
105
  export declare class MinioBlobBackend implements BlobBackend {
36
106
  private readonly cfg;
37
107
  private readonly keyPrefix;
38
108
  private readonly ttl;
109
+ /** The SQL index pool+dialect, or undefined for an index-LESS backend (the migration script + the unit suite, which
110
+ * exercise ONLY the object I/O — put/get/has-by-HEAD/delete — with no DB). When undefined, hasBlobs falls back to a
111
+ * HEAD-per-hash probe and deleteBlobs ignores the grace window (the script is a stop-the-world copy, not the live GC
112
+ * path). The file-snapshot stores ALWAYS pass the pool, so the live reference-tracking always has the index. */
39
113
  private readonly indexPool?;
40
114
  private readonly indexDialect?;
41
115
  constructor(cfg: MinioBlobBackendConfig, index?: {
@@ -44,16 +118,46 @@ export declare class MinioBlobBackend implements BlobBackend {
44
118
  });
45
119
  private objectKey;
46
120
  private presign;
121
+ /** PUT the bytes under the content-addressed key, THEN upsert the SQL INDEX row (bytes NULL, created_at refresh on
122
+ * conflict — the SAME grace discipline as SqlBlobBackend, so a just-PUT blob an in-flight snapshot needs is touched=
123
+ * now and protected). Idempotent (same hash ⇒ overwrite-with-identical-bytes + created_at bump). A non-2xx PUT throws
124
+ * (an upload failure must surface — a silent drop would later read_failed on restore). The PUT happens BEFORE the
125
+ * index upsert so an index row never claims a blob the object store doesn't hold (an index row with no object would
126
+ * let hasBlobs report a phantom present; the reverse — an object with no index — is harmless and pruned by a bucket
127
+ * lifecycle if it ever happens). NOTE no post-PUT read-back verify on the LIVE path (perf): content-addressing
128
+ * catches a corrupted PUT at the next getBlob sha-check (fail-closed); the one-time migration script DOES read-back. */
47
129
  putBlob(hash: string, bytes: Uint8Array): Promise<void>;
130
+ /** GET the bytes for `hash`, then VERIFY content-address (sha256(bytes)===hash). THREE branches (finding 11):
131
+ * - 404 → undefined (genuinely ABSENT — the file-snapshot store treats undefined as a missing blob).
132
+ * - sha256 MISMATCH → undefined (corruption/poisoning; treat corrupt-as-absent, fail-CLOSED, NEVER wrong bytes).
133
+ * - a NON-2xx-NON-404 (5xx/throttle) OR a network/fetch REJECT → THROW (a TRANSIENT fault must fail LOUD so the
134
+ * restore/import surfaces an error, NOT silently drop a file as "missing"; the SQL backend likewise propagates a
135
+ * pool error). The snapshot store's restore() wraps applyManifest so this throw becomes a {ok:false} restore_failed. */
48
136
  getBlob(hash: string): Promise<Uint8Array | undefined>;
137
+ /** The subset of `hashes` present — reads the SQL INDEX (cheaper than a HEAD-per-hash AND consistent with the SQL
138
+ * backend). Falls back to a presigned HEAD per hash ONLY in object-only mode (no index pool: the migration / unit
139
+ * path). The caller passes DISTINCT hashes (migration idempotency batch / reap orphan set / §10 presence pre-check). */
49
140
  hasBlobs(hashes: string[]): Promise<Set<string>>;
141
+ /** D-1 孤儿对象 GC(clay 拍 2026-07-28):列举本后端 keyPrefix 下的全部对象(ListObjectsV2 分页,
142
+ * 零依赖 XML 取 <Key>/<LastModified>/<NextContinuationToken>)。**server 端 sweep 专用**——presign 的
143
+ * bucket-GET 列举能力绝不外发。响应非 2xx 即 throw(sweep 调用方自 catch:列举失败=本轮跳过,
144
+ * 绝不把「列不出来」当「没有孤儿」)。 */
50
145
  listObjects(): AsyncGenerator<{
51
146
  hash: string;
52
147
  lastModifiedMs: number;
53
148
  }>;
149
+ /** 单对象 HEAD 探针(复审 B-F1 的删前复查面):返回当前 LastModified(缺席=对象已不在)。
150
+ * put 会 PUT 同键 ⇒ 刷新 LastModified,所以「删前再 HEAD 一次」能看见「刚刚被重新引用」的对象。 */
54
151
  headObject(hash: string): Promise<{
55
152
  lastModifiedMs: number;
56
153
  } | undefined>;
154
+ /** Byte-delete the given hashes — called ONLY from the async sweepOrphanBlobs reaper (NEVER the synchronous purge
155
+ * path). Honors the SAME created_at grace window as the SQL backend: with an index, DELETE the grace-passed index
156
+ * rows first (the index's created_at is the authoritative age — an S3 object carries no service-controlled timestamp
157
+ * the backend reads), then delete the MinIO objects ONLY for those grace-passed hashes (so a just-PUT blob an
158
+ * in-flight snapshot needs is NOT delete-in-use). ERROR-TOLERANT + BOUNDED: each object delete is independent (a
159
+ * failure is skipped → retried next sweep), at most MINIO_OP_CONCURRENCY in flight (no FD/throttle storm). In
160
+ * object-only mode (no index pool: the migration/unit cleanup path) it deletes every given hash with no grace. */
57
161
  deleteBlobs(hashes: string[]): Promise<number>;
58
162
  }
59
163
  //# sourceMappingURL=blob-backend.d.ts.map