@sema-agent/server 1.323.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 +58 -2
  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,10 +1,26 @@
1
+ /**
2
+ * 鉴权桥 verifier(REGISTRY-REBUILD §5 M3 service 半场)——验 registry 铸的用户 access JWT,
3
+ * `sub` 直喂既有 x-agent-principal 体系。规范=`@sema-agent/registry-core/api/auth-bridge` R1-R10(零 IO 纯契约,
4
+ * 决策函数直接复用);本模块补齐 IO+crypto 半场:JWKS 拉取/缓存、RS256 真验签(node:crypto,零新依赖)。
5
+ *
6
+ * 信任模型:worker 已信 registry 的 effective config,同一信任根延伸到它的 JWKS——零新配置项
7
+ * (issuer/jwksUrl 默认从 SEMA_REGISTRY_URL 派生;split 部署可 env 显式覆盖)。既有 SERVICE_AUTH_TOKEN(S)
8
+ * 分支不动:bearer 长得像 JWT(三段 base64url)才走本分支(looksLikeJwt=路由预过滤,非校验)。
9
+ *
10
+ * R10:本模块任何路径不 log token/签名段/密钥材料——只 log kid + 错误码 + iss。
11
+ */
1
12
  import { createPublicKey, verify as cryptoVerify } from "node:crypto";
2
13
  import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, REGISTRY_JWKS_PATH, RegistryJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/registry-core/api/auth-bridge";
3
14
  export { looksLikeJwt } from "@sema-agent/registry-core/api/auth-bridge";
4
15
  const DEFAULT_JWKS_TTL_SEC = 15 * 60;
16
+ /** JWKS 响应体字节上限(一个配错或超大响应的端点不应让 worker 无界缓冲;正常 JWKS 千字节级)。 */
5
17
  const MAX_JWKS_BYTES = 256 * 1024;
18
+ /** 整 token 长度上限(签名段无独立上限,故对整 bearer 统一设限;正常 JWT ~1KiB)。 */
6
19
  const MAX_TOKEN_CHARS = 16 * 1024;
20
+ /** 单段解码上限(header/payload)。 */
7
21
  const MAX_SEGMENT_BYTES = 64 * 1024;
22
+ /** base64url 字符集严格校验——Node 的 base64url 解码会容忍集外字符(仍解出同一字节),而契约要求"三段
23
+ * base64url"形态严格,故解码前每段必须匹配该字符集。 */
8
24
  const B64URL_RE = /^[A-Za-z0-9_-]+$/;
9
25
  function b64urlJson(seg) {
10
26
  if (seg.length > MAX_SEGMENT_BYTES || !B64URL_RE.test(seg))
@@ -18,6 +34,10 @@ function b64urlJson(seg) {
18
34
  }
19
35
  }
20
36
  const stripSlash = (s) => s.replace(/\/+$/, "");
37
+ /**
38
+ * registry-JWT verifier(单例,进程级 JWKS 缓存)。`verify(bearer)` 全程不 throw——一切异常折为
39
+ * AUTH_BRIDGE_ERROR_CODES(HTTP 面由调用方恒答 generic 401,码只进日志/metrics,R9)。
40
+ */
21
41
  export function createRegistryJwtVerifier(opts) {
22
42
  const issuer = stripSlash(opts.issuer);
23
43
  const jwksUrl = opts.jwksUrl ?? `${issuer}${REGISTRY_JWKS_PATH}`;
@@ -27,12 +47,14 @@ export function createRegistryJwtVerifier(opts) {
27
47
  const jwksTtlSec = opts.jwksTtlSec ?? DEFAULT_JWKS_TTL_SEC;
28
48
  const doFetch = opts.fetchImpl ?? fetch;
29
49
  const now = opts.nowMs ?? Date.now;
50
+ // 进程级缓存(R3/R8 的状态面;shouldForceJwksRefresh/jwksWithinOfflineGrace 消费的快照即它)。
30
51
  const keys = new Map();
31
52
  let lastFetchAttemptMs;
32
53
  let lastFetchSuccessMs;
33
- let inflight;
54
+ let inflight; // 并发 verify 合并成一次拉取(大量未知 kid 时不重复拉取)
34
55
  const fail = (error, kid) => {
35
56
  opts.metrics?.inc("auth_bridge_verify_total", { outcome: error });
57
+ // R10:仅 kid+码+iss。kid 来自**调用方可控**的 token header(16K token 上限内可到 ~10KB)——截断防日志放大。
36
58
  opts.logger?.warn?.("auth_bridge_rejected", { error, ...(kid ? { kid: kid.slice(0, 128) } : {}), iss: issuer });
37
59
  return { ok: false, error };
38
60
  };
@@ -45,16 +67,19 @@ export function createRegistryJwtVerifier(opts) {
45
67
  const res = await doFetch(jwksUrl, { redirect: "error", signal: AbortSignal.timeout(10_000) });
46
68
  if (!res.ok)
47
69
  throw new Error(`jwks HTTP ${res.status}`);
70
+ // 先看 Content-Length 早拒;chunked/无 CL 的响应会整体读入后按字节拒(非流式截断——jwksUrl 是
71
+ // operator 钉死的可信 registry + redirect:"error" + 10s timeout,瞬时内存风险接受,诚实记档)。
48
72
  const cl = Number(res.headers.get("content-length"));
49
73
  if (Number.isFinite(cl) && cl > MAX_JWKS_BYTES)
50
74
  throw new Error("jwks content-length too large");
51
75
  const buf = Buffer.from(await res.arrayBuffer());
52
76
  if (buf.byteLength > MAX_JWKS_BYTES)
53
77
  throw new Error("jwks body too large");
54
- const doc = RegistryJwks.parse(JSON.parse(buf.toString("utf8")));
78
+ const doc = RegistryJwks.parse(JSON.parse(buf.toString("utf8"))); // zod:形状不对=拉取失败(R8 路),绝不采用半坏文档
55
79
  const next = new Map();
56
80
  for (const k of doc.keys) {
57
81
  try {
82
+ // 公钥成员 only(契约警告:即便 registry 出 bug 带了私有成员也绝不使用/回显)。
58
83
  next.set(k.kid, createPublicKey({ key: { kty: "RSA", n: k.n, e: k.e }, format: "jwk" }));
59
84
  }
60
85
  catch {
@@ -67,6 +92,7 @@ export function createRegistryJwtVerifier(opts) {
67
92
  lastFetchSuccessMs = now();
68
93
  }
69
94
  catch (e) {
95
+ // 失败=保留旧缓存(R8 离线宽限判定在 verify 侧);只记账不 throw。
70
96
  opts.logger?.warn?.("auth_bridge_jwks_fetch_failed", { iss: issuer, error: String(e).slice(0, 200) });
71
97
  }
72
98
  finally {
@@ -76,6 +102,8 @@ export function createRegistryJwtVerifier(opts) {
76
102
  return inflight;
77
103
  }
78
104
  async function verify(bearer) {
105
+ // 延迟观测(auth_bridge_verify_seconds):热路径(kid 命中)应为亚毫秒级;冷路径(JWKS 拉取)带一次
106
+ // 网络 RTT——首请求/轮换时的尾延迟在这根直方图上可见,不用猜。
79
107
  const t0 = now();
80
108
  try {
81
109
  return await verifyInner(bearer);
@@ -88,43 +116,57 @@ export function createRegistryJwtVerifier(opts) {
88
116
  if (bearer.length > MAX_TOKEN_CHARS)
89
117
  return fail("malformed");
90
118
  const parts = bearer.split(".");
119
+ // 三段非空 + 每段 base64url 字符集(b64urlJson 已校验 header/payload;签名段在此单独校验)。
91
120
  if (parts.length !== 3 || parts.some((p) => p.length === 0) || !B64URL_RE.test(parts[2]))
92
121
  return fail("malformed");
93
122
  const header = b64urlJson(parts[0]);
94
123
  const payload = b64urlJson(parts[1]);
95
124
  if (!header || !payload)
96
125
  return fail("malformed");
126
+ // R1 — alg 固定在调用侧:只接受 RS256,不读 token 的 alg 字段来决定验法(none/HS*/ES*/PS* 一律拒)。
127
+ // 错误码归类跟契约(AUTH_BRIDGE_ERROR_CODES 注释):disallowed alg / 缺 kid = `malformed`
128
+ // (invalid_signature 留给"键在、验签不过"——异源复审对齐,跨侧 metrics 口径一致)。
97
129
  if (header.alg !== AUTH_BRIDGE_ALGS[0])
98
130
  return fail("malformed");
99
131
  const kid = typeof header.kid === "string" ? header.kid : undefined;
100
132
  if (!kid)
101
133
  return fail("malformed");
134
+ // R4 — issuer 先于取键比较(iss 不对根本不必碰 JWKS)。
102
135
  const iss = typeof payload.iss === "string" ? stripSlash(payload.iss) : undefined;
103
136
  if (iss !== issuer)
104
137
  return fail("unknown_issuer", kid);
138
+ // R5 — 时间窗(60s 偏移;exp 必须在)。
105
139
  if (classifyTimeClaims(payload, Math.floor(now() / 1000), clockSkewSec) !== "ok")
106
140
  return fail("expired", kid);
141
+ // R2/R3 — 取键。热路径:kid 命中 ⇒ 直用,零 fetch(TTL 陈旧只在无在途拉取且过节流时【后台】刷一次
142
+ // [void,不 await],不阻塞验证)。kid miss ⇒ 先 await 任何在途拉取(并发请求不应被 lastFetchAttemptMs
143
+ // 节流跳过而错过正在完成的刷新),再查;仍 miss 且过节流 ⇒ 强制刷一次。
107
144
  const snapshot = () => ({ cachedKids: [...keys.keys()], lastFetchAttemptMs, nowMs: now() });
108
145
  if (keys.has(kid)) {
109
146
  const ttlStale = lastFetchSuccessMs === undefined || now() - lastFetchSuccessMs > jwksTtlSec * 1000;
110
147
  if (ttlStale && !inflight && (lastFetchAttemptMs === undefined || now() - lastFetchAttemptMs >= refreshMin * 1000)) {
111
- void refreshJwks();
148
+ void refreshJwks(); // 后台刷新,当前请求继续用现有 key
112
149
  }
113
150
  }
114
151
  else {
115
152
  if (inflight)
116
- await inflight;
153
+ await inflight; // 有在途拉取:等它完成再查(可能正好带来这个 kid)
117
154
  if (!keys.has(kid) && shouldForceJwksRefresh(kid, snapshot(), { jwksRefreshMinIntervalSec: refreshMin }))
118
155
  await refreshJwks();
119
156
  }
120
157
  const key = keys.get(kid);
121
158
  if (!key) {
159
+ // R8 — kid 仍未命中:有【活】缓存(有成功拉取且在 24h 宽限内)⇒ 键该在却不在=token 与当前键集不符
160
+ // (invalid_signature)。从没成功拉过 / 超宽限 ⇒ jwks_unavailable(失败即拒:不用 `keys.size>0` 兜底,
161
+ // 因为超宽限的陈旧缓存 size>0 时也不应把 unavailable 归成 invalid_signature)。
122
162
  const graceOk = lastFetchSuccessMs !== undefined && jwksWithinOfflineGrace({ lastFetchSuccessMs, nowMs: now() }, { offlineGraceSec });
123
163
  return graceOk ? fail("invalid_signature", kid) : fail("jwks_unavailable", kid);
124
164
  }
125
165
  if (lastFetchSuccessMs !== undefined && !jwksWithinOfflineGrace({ lastFetchSuccessMs, nowMs: now() }, { offlineGraceSec })) {
166
+ // 缓存超出 24h 离线宽限——即便 kid 命中也拒(R8:宽限后不再使用陈旧键)。
126
167
  return fail("jwks_unavailable", kid);
127
168
  }
169
+ // 真验签(RS256 = RSASSA-PKCS1-v1_5 + SHA-256 over `header.payload`)。
128
170
  let sigOk = false;
129
171
  try {
130
172
  sigOk = cryptoVerify("RSA-SHA256", Buffer.from(`${parts[0]}.${parts[1]}`, "utf8"), key, Buffer.from(parts[2], "base64url"));
@@ -134,6 +176,7 @@ export function createRegistryJwtVerifier(opts) {
134
176
  }
135
177
  if (!sigOk)
136
178
  return fail("invalid_signature", kid);
179
+ // R6/R7/R9 — 身份映射(契约纯函数)。
137
180
  const mapped = toVerifiedIdentity(payload, opts.audience ? { audience: opts.audience } : undefined);
138
181
  if (!mapped.ok)
139
182
  return fail(mapped.error, kid);
@@ -1,14 +1,33 @@
1
+ /**
2
+ * AUTH KEY-SET parsing (design/158 A4) — the env→key-set decoders for the two D-G credential planes, moved VERBATIM
3
+ * out of security.ts: {@link parseApprovalHmacKeys} (APPROVAL_HMAC_KEYS — the rotating HMAC secret set, decision
4
+ * INTEGRITY) and {@link parsePrincipalJwks} (PRINCIPAL_JWT_PUBKEYS — the rotating issuer public-key set, principal
5
+ * IDENTITY). config.ts consumes ONLY these two functions + their row types at env-load time, and importing them from
6
+ * security.ts made the base config layer value-depend on the whole 55KiB auth module (lens2 §F). This file is a pure
7
+ * leaf (JSON.parse + shape filters, zero repo imports); the VERIFIERS that consume the parsed key-sets
8
+ * (verifyApprovalHmac / verifyPrincipalJwt) stay in security.ts, which re-exports these four names for compat.
9
+ */
10
+ /** One key in the rotating HMAC key-set. `kid` lets the verifier pick the signing key (or fall back to trying the
11
+ * whole set); `status` lets sema-registry rotate without breaking in-flight approvals: `active` = sign + verify,
12
+ * `retiring` = verify-only (kept for the overlap window so a MAC signed with the old key still verifies). */
1
13
  export interface ApprovalHmacKey {
2
14
  kid: string;
3
15
  key: string;
4
16
  status?: "active" | "retiring";
5
17
  }
18
+ /** Parse APPROVAL_HMAC_KEYS — a sema-registry-managed, rotating key-SET, as a JSON array of {kid,key,status}.
19
+ * Empty / unset / unparseable ⇒ `[]` ⇒ HMAC verification is OFF (D-G inactive; back-compat, BFF-only door). */
6
20
  export declare function parseApprovalHmacKeys(raw: string | undefined): ApprovalHmacKey[];
21
+ /** One issuer public key in the rotating principal JWKS (mirror of the HMAC key-set rotation discipline). The
22
+ * `alg` is PINNED per key — the JWT header's alg MUST match it, killing alg-confusion (`none`, HS-with-the-pubkey).
23
+ * `key` is a PEM (SPKI) public key. PUBLIC, non-secret. */
7
24
  export interface PrincipalJwtKey {
8
25
  kid: string;
9
26
  alg: "EdDSA" | "RS256" | "ES256";
10
27
  key: string;
11
28
  status?: "active" | "retiring";
12
29
  }
30
+ /** Parse PRINCIPAL_JWT_PUBKEYS — a JSON array of {kid,alg,key,status}. Empty/unset/malformed ⇒ [] ⇒ no trust
31
+ * anchor ⇒ the direct door cannot open (D-G inactive). Each entry must have kid + a pinned alg + a PEM key. */
13
32
  export declare function parsePrincipalJwks(raw: string | undefined): PrincipalJwtKey[];
14
33
  //# sourceMappingURL=auth-keys.d.ts.map
package/dist/auth-keys.js CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * AUTH KEY-SET parsing (design/158 A4) — the env→key-set decoders for the two D-G credential planes, moved VERBATIM
3
+ * out of security.ts: {@link parseApprovalHmacKeys} (APPROVAL_HMAC_KEYS — the rotating HMAC secret set, decision
4
+ * INTEGRITY) and {@link parsePrincipalJwks} (PRINCIPAL_JWT_PUBKEYS — the rotating issuer public-key set, principal
5
+ * IDENTITY). config.ts consumes ONLY these two functions + their row types at env-load time, and importing them from
6
+ * security.ts made the base config layer value-depend on the whole 55KiB auth module (lens2 §F). This file is a pure
7
+ * leaf (JSON.parse + shape filters, zero repo imports); the VERIFIERS that consume the parsed key-sets
8
+ * (verifyApprovalHmac / verifyPrincipalJwt) stay in security.ts, which re-exports these four names for compat.
9
+ */
10
+ /** Parse APPROVAL_HMAC_KEYS — a sema-registry-managed, rotating key-SET, as a JSON array of {kid,key,status}.
11
+ * Empty / unset / unparseable ⇒ `[]` ⇒ HMAC verification is OFF (D-G inactive; back-compat, BFF-only door). */
1
12
  export function parseApprovalHmacKeys(raw) {
2
13
  if (!raw)
3
14
  return [];
@@ -11,6 +22,8 @@ export function parseApprovalHmacKeys(raw) {
11
22
  return [];
12
23
  }
13
24
  }
25
+ /** Parse PRINCIPAL_JWT_PUBKEYS — a JSON array of {kid,alg,key,status}. Empty/unset/malformed ⇒ [] ⇒ no trust
26
+ * anchor ⇒ the direct door cannot open (D-G inactive). Each entry must have kid + a pinned alg + a PEM key. */
14
27
  export function parsePrincipalJwks(raw) {
15
28
  if (!raw)
16
29
  return [];
@@ -12,8 +12,13 @@ interface RunnerEnv {
12
12
  minFreeGb: number;
13
13
  }
14
14
  declare function loadEnv(): RunnerEnv;
15
+ /** The real image-api HTTP client. Authenticates claim/heartbeat with the runner bearer; ingest additionally
16
+ * carries the per-bake ingest secret header (so image-api can reject a stale/rogue runner — §P2.4e). */
15
17
  declare function makeApiClient(env: RunnerEnv): ImageApiClient;
18
+ /** The real child spawner: `setsid`-style detached process GROUP so a cancel/deadline kill signals the whole tree
19
+ * (channel-close / a plain kill of the immediate child does NOT stop a detached build — §P2.11). */
16
20
  declare function makeSpawner(): ChildSpawner;
21
+ /** The real host ops: fs manifest read, df /data, recipe checkout, and the thin docker-push big-blob retry. */
17
22
  declare function makeHostOps(env: RunnerEnv): HostOps;
18
23
  declare function main(): Promise<void>;
19
24
  export { main, loadEnv, makeApiClient, makeSpawner, makeHostOps };
@@ -1,3 +1,12 @@
1
+ /**
2
+ * bake-runner ENTRYPOINT (IMAGE-API-DESIGN.md §P2.0/§P2.12) — the privileged build-host daemon. It wires the REAL I/O
3
+ * (HTTP to image-api, the setsid-detached build.sh child, the fs manifest read, git checkout, df) into the
4
+ * I/O-injected `BakeRunner` core (./runner.ts). This process runs ONLY on the build-host build host — it CANNOT be
5
+ * unit-run here (no docker/ctr/recipes); the testable logic is the pure protocol + the runner orchestration.
6
+ *
7
+ * Crown-jewel discipline (§P2.4e): the only secrets are BAKE_RUNNER_TOKEN (the operator-principal bearer for
8
+ * claim/heartbeat) and the per-bake ingest secret minted by image-api at claim — neither is ever logged.
9
+ */
1
10
  import { spawn, exec as execCb } from "node:child_process";
2
11
  import { readFile } from "node:fs/promises";
3
12
  import { promisify } from "node:util";
@@ -24,9 +33,13 @@ function loadEnv() {
24
33
  minFreeGb: Number(process.env.IMAGE_BAKE_MIN_FREE_GB || "20"),
25
34
  };
26
35
  }
36
+ /** The real image-api HTTP client. Authenticates claim/heartbeat with the runner bearer; ingest additionally
37
+ * carries the per-bake ingest secret header (so image-api can reject a stale/rogue runner — §P2.4e). */
27
38
  function makeApiClient(env) {
28
39
  const auth = { authorization: `Bearer ${env.token}`, "content-type": "application/json" };
29
40
  return {
41
+ // Long-poll claim (§P2.12): the bare `POST …/bakes/claim` finds the oldest queued bake AND leases it in one
42
+ // call (the discovery + the single-flight CAS server-side). 204 ⇒ the queue is empty (the runner idle-polls).
30
43
  async claimNext() {
31
44
  const res = await fetch(`${env.imageApiBase}/v1/images/bakes/claim`, {
32
45
  method: "POST",
@@ -34,7 +47,7 @@ function makeApiClient(env) {
34
47
  body: JSON.stringify({ runnerId: env.runnerId }),
35
48
  });
36
49
  if (res.status === 204 || res.status === 409)
37
- return null;
50
+ return null; // empty queue, or lost the single-flight CAS
38
51
  if (!res.ok)
39
52
  return null;
40
53
  const c = (await res.json());
@@ -61,10 +74,11 @@ function makeApiClient(env) {
61
74
  return {
62
75
  accepted: res.ok && body.accepted !== false,
63
76
  cancelRequested: body.cancelRequested === true,
64
- leaseValid: res.status !== 409,
77
+ leaseValid: res.status !== 409, // a 409 on ingest = the lease/claim no longer ours
65
78
  };
66
79
  },
67
80
  async heartbeat(bakeId, ingestSecret) {
81
+ // A heartbeat is a no-frame ingest: image-api advances the lease and echoes the cancel flag (§P2.7/§P2.11).
68
82
  const res = await fetch(`${env.imageApiBase}/v1/images/bakes/${encodeURIComponent(bakeId)}/ingest`, {
69
83
  method: "POST",
70
84
  headers: { ...auth, "x-bake-ingest-secret": ingestSecret },
@@ -79,9 +93,13 @@ function makeApiClient(env) {
79
93
  },
80
94
  };
81
95
  }
96
+ /** The real child spawner: `setsid`-style detached process GROUP so a cancel/deadline kill signals the whole tree
97
+ * (channel-close / a plain kill of the immediate child does NOT stop a detached build — §P2.11). */
82
98
  function makeSpawner() {
83
99
  return {
84
100
  spawn(opts) {
101
+ // detached:true → the child becomes a process-group leader (its pgid == its pid); `process.kill(-pid, sig)`
102
+ // then signals the WHOLE group. We DON'T `unref()` — the runner waits on the exit promise.
85
103
  const child = spawn(opts.argv[0], opts.argv.slice(1), {
86
104
  cwd: opts.cwd,
87
105
  detached: true,
@@ -93,12 +111,13 @@ function makeSpawner() {
93
111
  bufferLines(child.stderr, opts.onStderrLine);
94
112
  const exited = new Promise((resolve) => {
95
113
  child.on("exit", (code, signal) => resolve({ code, signal }));
96
- child.on("error", () => resolve({ code: 127, signal: null }));
114
+ child.on("error", () => resolve({ code: 127, signal: null })); // spawn failed (build.sh missing, etc.)
97
115
  });
98
116
  const handle = {
99
117
  pgid,
100
118
  exited,
101
119
  killGroup(signal) {
120
+ // Negative pid → signal the process GROUP (the detached tree), not just the immediate child.
102
121
  if (pgid > 0)
103
122
  process.kill(-pgid, signal);
104
123
  },
@@ -107,6 +126,8 @@ function makeSpawner() {
107
126
  },
108
127
  };
109
128
  }
129
+ /** Split a readable stream into lines, invoking `onLine` per complete line (the runner parses ONLY stdout as JSON;
130
+ * stderr lines are the failure tail). Carries a partial trailing line across chunks; flushes it on stream end. */
110
131
  function bufferLines(stream, onLine) {
111
132
  if (!stream)
112
133
  return;
@@ -126,6 +147,7 @@ function bufferLines(stream, onLine) {
126
147
  onLine(buf);
127
148
  });
128
149
  }
150
+ /** The real host ops: fs manifest read, df /data, recipe checkout, and the thin docker-push big-blob retry. */
129
151
  function makeHostOps(env) {
130
152
  return {
131
153
  async readManifest(path) {
@@ -136,6 +158,14 @@ function makeHostOps(env) {
136
158
  return stdout;
137
159
  },
138
160
  async checkoutRecipe(ref) {
161
+ // The recipe dir is a git checkout of the service repo pinned to the runner's deployed commit (NOT a frozen
162
+ // copy) so build.sh's `git rev-parse` gitsha is REAL and the manifest's recipeGitSha is replay-sufficient.
163
+ // A fixed ref (the deployed image's commit) → fetch + checkout is idempotent; a non-default ref is fetched.
164
+ // 🔴 A ref may be a branch/tag (fetchable by name) OR a BARE COMMIT SHA — and `git fetch origin <sha>` fails
165
+ // on most servers ("couldn't find remote ref <sha>"; only refs are fetchable). So try the cheap shallow
166
+ // ref-fetch, and on failure fall back to fetching the repo and checking the SHA out of the local history
167
+ // (the init-container clone usually already contains it). RECIPE_REF=HEAD skips this entirely (uses the
168
+ // checkout as-is — the prod path, the init-container pins the commit). [live-caught on center's prod deploy]
139
169
  if (ref && ref !== "HEAD") {
140
170
  const dir = shellSafe(env.recipeDir);
141
171
  try {
@@ -146,9 +176,14 @@ function makeHostOps(env) {
146
176
  await exec(`git -C ${dir} fetch origin && git -C ${dir} checkout --quiet --detach ${shellSafe(ref)}`);
147
177
  }
148
178
  }
179
+ // build.sh resolves itself relative to its own dir; the cwd for the spawn is the recipe checkout root so the
180
+ // path RECIPE_DIR + BUILD_SH_PATH is the script the runner invokes.
149
181
  return env.recipeDir;
150
182
  },
151
183
  async dockerPushRetry(tag, attempts) {
184
+ // Thin `docker push` wrapper (NOT build.sh --replay — that re-bakes + hits the dup-check, exit 10). Retries a
185
+ // flaky big-blob registry layer push with backoff (born on SWR — deprecated; pool now docker.io/claybobby);
186
+ // NO_PROXY (incl. the registry domain) lives in this process's env.
152
187
  for (let i = 0; i < attempts; i++) {
153
188
  try {
154
189
  await exec(`docker push ${shellSafe(tag)}`);
@@ -166,6 +201,8 @@ function makeHostOps(env) {
166
201
  },
167
202
  };
168
203
  }
204
+ /** Shell-quote a single argument for the `exec` string forms above (df/git/docker take server-fixed paths/refs, but
205
+ * a defensive quote keeps a surprising RECIPE_DIR/ref from breaking the command — argv to build.sh is a vector). */
169
206
  function shellSafe(s) {
170
207
  return `'${s.replace(/'/g, "'\\''")}'`;
171
208
  }
@@ -184,7 +221,7 @@ async function main() {
184
221
  recipeRef: env.recipeRef,
185
222
  heartbeatMs: env.heartbeatMs,
186
223
  minFreeGb: env.minFreeGb,
187
- });
224
+ }); // NB: the token + per-bake ingest secret are NEVER logged (§P2.4e)
188
225
  const runner = new BakeRunner({
189
226
  api: makeApiClient(env),
190
227
  spawner: makeSpawner(),
@@ -205,9 +242,11 @@ async function main() {
205
242
  process.on("SIGINT", () => shutdown("SIGINT"));
206
243
  await runner.loop();
207
244
  }
245
+ // Only run when invoked directly (not when imported by a test).
208
246
  const invokedDirectly = process.argv[1] !== undefined && /bake-runner[/\\]main\.(ts|js)$/.test(process.argv[1]);
209
247
  if (invokedDirectly) {
210
248
  main().catch((err) => {
249
+ // eslint-disable-next-line no-console
211
250
  console.error(JSON.stringify({ ts: new Date().toISOString(), level: "error", msg: "bake_runner_fatal", err: String(err) }));
212
251
  process.exit(1);
213
252
  });
@@ -1,3 +1,16 @@
1
+ /**
2
+ * bake-runner PURE protocol layer (IMAGE-API-DESIGN.md §P2.12) — the line→frame mapping + the small policy
3
+ * helpers, factored free of I/O so they are unit-testable WITHOUT the privileged build-host build host (the runner
4
+ * itself can only be exercised live; this is the part a unit test pins).
5
+ *
6
+ * The runner spawns `build.sh <vetted argv> --json` and forwards each STDOUT line to image-api's ingest. build.sh
7
+ * emits a small set of JSON object lines (`resolved | state | step | image | manifest | done`) on stdout and tees
8
+ * the raw `docker build` output to `$BUILD_DIR/build.log` (NOT onto stdout). On failure it does `tail -40 build.log
9
+ * >&2` — that is STDERR, the failure tail, NOT JSON; we parse JSON ONLY from stdout (a naive JSON.parse over both
10
+ * crashes the parser — §P2.5). Each forwarded frame carries an incrementing `lineOrd` (at-least-once ingest dedupe;
11
+ * image-api's `uq_line` ignores a re-sent ordinal — §P2.10).
12
+ */
13
+ /** One build.sh stdout line, already JSON-parsed into an object (or a marker for an unparseable line). */
1
14
  export type BuildShEvent = {
2
15
  event: "resolved";
3
16
  [k: string]: unknown;
@@ -29,21 +42,65 @@ export type BuildShEvent = {
29
42
  event: string;
30
43
  [k: string]: unknown;
31
44
  };
45
+ /** The frame the runner POSTs to `…/ingest` (image-api maps it to an event-log row). `lineOrd` is the dedupe key. */
32
46
  export interface IngestFrame {
47
+ /** build.sh's `event` (or "log" for an unparseable/raw line). */
33
48
  event: string;
49
+ /** Monotonic per-bake ordinal — image-api dedupes on (bakeId, lineOrd) so an at-least-once re-send is a no-op. */
34
50
  lineOrd: number;
51
+ /** The remaining build.sh fields (event already lifted out), passed through verbatim. */
35
52
  [k: string]: unknown;
36
53
  }
54
+ /**
55
+ * Parse ONE raw stdout line into a build.sh event, or null when it is not a JSON object line (a blank line, a
56
+ * stray non-JSON print). build.sh's protocol is strictly one JSON OBJECT per stdout line (`jq -nc`), so anything
57
+ * that is not a `{…}` object is treated as non-protocol noise the caller forwards as a `log` frame (NOT crashed on).
58
+ */
37
59
  export declare function parseBuildShLine(raw: string): BuildShEvent | null;
60
+ /**
61
+ * Map ONE stdout line → the ingest frame the runner POSTs (the PURE core a unit test pins). A parseable protocol
62
+ * line is forwarded under its own `event`; an unparseable stdout line becomes an `info` log frame (build.sh's
63
+ * structured stdout is naturally quiet, so this is rare — usually a generator print). The raw `docker build` tail
64
+ * never reaches here: it is on stderr (the runner only feeds stdout through this) — §P2.5.
65
+ */
38
66
  export declare function lineToFrame(raw: string, lineOrd: number): IngestFrame;
67
+ /**
68
+ * Synthesize the `docker-build status:running elapsedSec` heartbeat step (§P2.2) — emitted every ~30s during the
69
+ * long, silent `docker build` (with logs off) so a resuming reader sees forward motion instead of a dead spinner.
70
+ * It is a synthesized frame, so it still carries a `lineOrd` (image-api dedupes the same way).
71
+ */
39
72
  export declare function dockerBuildTickFrame(lineOrd: number, elapsedSec: number): IngestFrame;
73
+ /**
74
+ * Synthesize the terminal `done` the runner sends when build.sh did NOT emit one (a hard cancel/timeout kill —
75
+ * build.sh has no SIGTERM trap, so a killed process never prints `done:CANCELLED`/`done:FAILED`; the runner MUST
76
+ * synthesize it — §P2.11). `cancelled` → `CANCELLED`; a timeout → `FAILED exitCode:124`.
77
+ */
40
78
  export declare function synthDoneFrame(lineOrd: number, kind: "cancelled" | "timeout", detail?: {
41
79
  error?: string;
42
80
  }): IngestFrame;
81
+ /**
82
+ * The runner-side terminal `done` for a build.sh CHILD that exited non-zero WITHOUT printing its own `done` (build.sh
83
+ * normally dies via `die()` which DOES print a `done:FAILED`, but a SIGKILL or a crash before the trap can leave the
84
+ * child exiting non-zero silently). The runner backstops with a FAILED done carrying the child exit code + the
85
+ * captured stderr failure tail (the `tail -40 build.log` build.sh prints on failure), redacted by image-api on store.
86
+ */
43
87
  export declare function exitDoneFrame(lineOrd: number, exitCode: number, stderrTail: string): IngestFrame;
88
+ /** Keep only the last `n` lines of a (possibly long) stderr tail — bounds the error string we forward. */
44
89
  export declare function lastLines(text: string, n: number): string;
90
+ /**
91
+ * The profile-aware HARD DEADLINE (§P2.7/§P2.11) the runner enforces by killing the process group. flutter/full are
92
+ * the heavy profiles (~60min); everything else ~45min. A bands build ("custom") is treated as heavy if it includes
93
+ * a heavy band. The reaper backstops this; the runner is the primary enforcer (it owns the child).
94
+ */
45
95
  export declare function deadlineMsForProfile(profile: string, bands: string[] | null | undefined): number;
96
+ /** Parse `df -P -BG /data` (POSIX, 1G blocks) → free GiB on the build-host data fs. Returns null if unparseable
97
+ * (the caller then fails OPEN — a df parse miss must not block a bake; the reaper still guards a mid-build fill). */
46
98
  export declare function parseDfFreeGb(dfOutput: string): number | null;
99
+ /** The path build.sh's `done`/`manifest` line points at (a build-host FS path). The done carries `manifest:<path>`, the
100
+ * manifest event carries `path` — the runner reads whichever is present off disk for the auto-register body. */
47
101
  export declare function manifestPathFromLine(doneLine: Record<string, unknown>, lastManifestPath: string | null): string | null;
102
+ /** Pull the post-push runtime digest the auto-register should key on. build.sh rewrites DIGEST from RepoDigests[0]
103
+ * AFTER a push, so the `done`/`image` line's `digest` is already the post-push registry RepoDigest on a push bake and the
104
+ * LOCAL_ID on a no-push bake — the runner forwards it verbatim; this just normalizes the field name (§P2.10). */
48
105
  export declare function digestFromDoneLine(doneLine: Record<string, unknown>, lastImageDigest: string | null): string | null;
49
106
  //# sourceMappingURL=protocol.d.ts.map
@@ -1,7 +1,24 @@
1
+ /**
2
+ * bake-runner PURE protocol layer (IMAGE-API-DESIGN.md §P2.12) — the line→frame mapping + the small policy
3
+ * helpers, factored free of I/O so they are unit-testable WITHOUT the privileged build-host build host (the runner
4
+ * itself can only be exercised live; this is the part a unit test pins).
5
+ *
6
+ * The runner spawns `build.sh <vetted argv> --json` and forwards each STDOUT line to image-api's ingest. build.sh
7
+ * emits a small set of JSON object lines (`resolved | state | step | image | manifest | done`) on stdout and tees
8
+ * the raw `docker build` output to `$BUILD_DIR/build.log` (NOT onto stdout). On failure it does `tail -40 build.log
9
+ * >&2` — that is STDERR, the failure tail, NOT JSON; we parse JSON ONLY from stdout (a naive JSON.parse over both
10
+ * crashes the parser — §P2.5). Each forwarded frame carries an incrementing `lineOrd` (at-least-once ingest dedupe;
11
+ * image-api's `uq_line` ignores a re-sent ordinal — §P2.10).
12
+ */
13
+ /**
14
+ * Parse ONE raw stdout line into a build.sh event, or null when it is not a JSON object line (a blank line, a
15
+ * stray non-JSON print). build.sh's protocol is strictly one JSON OBJECT per stdout line (`jq -nc`), so anything
16
+ * that is not a `{…}` object is treated as non-protocol noise the caller forwards as a `log` frame (NOT crashed on).
17
+ */
1
18
  export function parseBuildShLine(raw) {
2
19
  const s = raw.trim();
3
20
  if (s.length === 0 || s[0] !== "{")
4
- return null;
21
+ return null; // fast reject: protocol lines are JSON objects
5
22
  let parsed;
6
23
  try {
7
24
  parsed = JSON.parse(s);
@@ -13,26 +30,49 @@ export function parseBuildShLine(raw) {
13
30
  return null;
14
31
  const obj = parsed;
15
32
  if (typeof obj.event !== "string")
16
- return null;
33
+ return null; // not a protocol line → caller forwards as a log frame
17
34
  return obj;
18
35
  }
36
+ /**
37
+ * Map ONE stdout line → the ingest frame the runner POSTs (the PURE core a unit test pins). A parseable protocol
38
+ * line is forwarded under its own `event`; an unparseable stdout line becomes an `info` log frame (build.sh's
39
+ * structured stdout is naturally quiet, so this is rare — usually a generator print). The raw `docker build` tail
40
+ * never reaches here: it is on stderr (the runner only feeds stdout through this) — §P2.5.
41
+ */
19
42
  export function lineToFrame(raw, lineOrd) {
20
43
  const ev = parseBuildShLine(raw);
21
44
  if (ev === null) {
45
+ // Non-protocol stdout noise → an info log frame (NOT crashed on, NOT a raw docker tail — that is stderr).
22
46
  return { event: "log", lineOrd, level: "info", line: raw.replace(/\s+$/, "") };
23
47
  }
24
48
  const { event, ...rest } = ev;
25
49
  return { event, lineOrd, ...rest };
26
50
  }
51
+ /**
52
+ * Synthesize the `docker-build status:running elapsedSec` heartbeat step (§P2.2) — emitted every ~30s during the
53
+ * long, silent `docker build` (with logs off) so a resuming reader sees forward motion instead of a dead spinner.
54
+ * It is a synthesized frame, so it still carries a `lineOrd` (image-api dedupes the same way).
55
+ */
27
56
  export function dockerBuildTickFrame(lineOrd, elapsedSec) {
28
57
  return { event: "step", lineOrd, step: "docker-build", status: "running", elapsedSec };
29
58
  }
59
+ /**
60
+ * Synthesize the terminal `done` the runner sends when build.sh did NOT emit one (a hard cancel/timeout kill —
61
+ * build.sh has no SIGTERM trap, so a killed process never prints `done:CANCELLED`/`done:FAILED`; the runner MUST
62
+ * synthesize it — §P2.11). `cancelled` → `CANCELLED`; a timeout → `FAILED exitCode:124`.
63
+ */
30
64
  export function synthDoneFrame(lineOrd, kind, detail) {
31
65
  if (kind === "cancelled") {
32
66
  return { event: "done", lineOrd, status: "CANCELLED", exitCode: null, error: detail?.error ?? "cancelled by operator" };
33
67
  }
34
68
  return { event: "done", lineOrd, status: "FAILED", exitCode: 124, error: detail?.error ?? "bake hard-deadline exceeded (killed)" };
35
69
  }
70
+ /**
71
+ * The runner-side terminal `done` for a build.sh CHILD that exited non-zero WITHOUT printing its own `done` (build.sh
72
+ * normally dies via `die()` which DOES print a `done:FAILED`, but a SIGKILL or a crash before the trap can leave the
73
+ * child exiting non-zero silently). The runner backstops with a FAILED done carrying the child exit code + the
74
+ * captured stderr failure tail (the `tail -40 build.log` build.sh prints on failure), redacted by image-api on store.
75
+ */
36
76
  export function exitDoneFrame(lineOrd, exitCode, stderrTail) {
37
77
  const tail = stderrTail.trim();
38
78
  return {
@@ -43,10 +83,16 @@ export function exitDoneFrame(lineOrd, exitCode, stderrTail) {
43
83
  error: tail.length > 0 ? `build.sh exited ${exitCode}: ${lastLines(tail, 12)}` : `build.sh exited ${exitCode}`,
44
84
  };
45
85
  }
86
+ /** Keep only the last `n` lines of a (possibly long) stderr tail — bounds the error string we forward. */
46
87
  export function lastLines(text, n) {
47
88
  const lines = text.split(/\r?\n/).filter((l) => l.length > 0);
48
89
  return lines.slice(Math.max(0, lines.length - n)).join("\n");
49
90
  }
91
+ /**
92
+ * The profile-aware HARD DEADLINE (§P2.7/§P2.11) the runner enforces by killing the process group. flutter/full are
93
+ * the heavy profiles (~60min); everything else ~45min. A bands build ("custom") is treated as heavy if it includes
94
+ * a heavy band. The reaper backstops this; the runner is the primary enforcer (it owns the child).
95
+ */
50
96
  export function deadlineMsForProfile(profile, bands) {
51
97
  const HEAVY_MS = 60 * 60 * 1000;
52
98
  const NORMAL_MS = 45 * 60 * 1000;
@@ -58,19 +104,25 @@ export function deadlineMsForProfile(profile, bands) {
58
104
  return HEAVY_MS;
59
105
  return NORMAL_MS;
60
106
  }
107
+ /** Parse `df -P -BG /data` (POSIX, 1G blocks) → free GiB on the build-host data fs. Returns null if unparseable
108
+ * (the caller then fails OPEN — a df parse miss must not block a bake; the reaper still guards a mid-build fill). */
61
109
  export function parseDfFreeGb(dfOutput) {
110
+ // `df -P -BG <path>` prints a header line then one data line; the "Available" column is field index 3 (0-based),
111
+ // a value like "812G". POSIX `-P` guarantees one physical line per fs (no wrapping), so field positions are fixed.
62
112
  const lines = dfOutput.trim().split(/\r?\n/);
63
113
  if (lines.length < 2)
64
114
  return null;
65
115
  const data = lines[lines.length - 1].trim().split(/\s+/);
66
116
  if (data.length < 4)
67
117
  return null;
68
- const avail = data[3];
118
+ const avail = data[3]; // Filesystem 1G-blocks Used Available …
69
119
  const m = /^(\d+)G?$/.exec(avail);
70
120
  if (!m)
71
121
  return null;
72
122
  return Number(m[1]);
73
123
  }
124
+ /** The path build.sh's `done`/`manifest` line points at (a build-host FS path). The done carries `manifest:<path>`, the
125
+ * manifest event carries `path` — the runner reads whichever is present off disk for the auto-register body. */
74
126
  export function manifestPathFromLine(doneLine, lastManifestPath) {
75
127
  if (typeof doneLine.manifest === "string" && doneLine.manifest.length > 0)
76
128
  return doneLine.manifest;
@@ -78,6 +130,9 @@ export function manifestPathFromLine(doneLine, lastManifestPath) {
78
130
  return doneLine.path;
79
131
  return lastManifestPath;
80
132
  }
133
+ /** Pull the post-push runtime digest the auto-register should key on. build.sh rewrites DIGEST from RepoDigests[0]
134
+ * AFTER a push, so the `done`/`image` line's `digest` is already the post-push registry RepoDigest on a push bake and the
135
+ * LOCAL_ID on a no-push bake — the runner forwards it verbatim; this just normalizes the field name (§P2.10). */
81
136
  export function digestFromDoneLine(doneLine, lastImageDigest) {
82
137
  if (typeof doneLine.digest === "string" && doneLine.digest.length > 0)
83
138
  return doneLine.digest;