@sema-agent/server 1.323.0 → 2.0.1

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 (565) 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/budget-tracing.d.ts +48 -0
  46. package/dist/boot/budget-tracing.js +86 -0
  47. package/dist/boot/config-center.d.ts +62 -0
  48. package/dist/boot/config-center.js +995 -0
  49. package/dist/boot/coordinators.d.ts +33 -0
  50. package/dist/boot/coordinators.js +97 -0
  51. package/dist/boot/execution-env.d.ts +26 -0
  52. package/dist/boot/execution-env.js +370 -0
  53. package/dist/boot/leader.d.ts +27 -0
  54. package/dist/boot/leader.js +81 -0
  55. package/dist/boot/reapers.d.ts +53 -0
  56. package/dist/boot/reapers.js +252 -0
  57. package/dist/boot/resolve-spec.d.ts +70 -0
  58. package/dist/boot/resolve-spec.js +1072 -0
  59. package/dist/boot/runner-deps.d.ts +101 -0
  60. package/dist/boot/runner-deps.js +343 -0
  61. package/dist/boot/runtime-caps.d.ts +21 -0
  62. package/dist/boot/runtime-caps.js +62 -0
  63. package/dist/boot/session-faces.d.ts +57 -0
  64. package/dist/boot/session-faces.js +157 -0
  65. package/dist/boot/shutdown.d.ts +50 -0
  66. package/dist/boot/shutdown.js +129 -0
  67. package/dist/boot/stores.d.ts +32 -0
  68. package/dist/boot/stores.js +361 -0
  69. package/dist/boot/workflow-orchestration.d.ts +46 -0
  70. package/dist/boot/workflow-orchestration.js +150 -0
  71. package/dist/boot-reclaim.d.ts +19 -0
  72. package/dist/boot-reclaim.js +20 -0
  73. package/dist/brain.d.ts +25 -0
  74. package/dist/brain.js +61 -1
  75. package/dist/budget.d.ts +66 -0
  76. package/dist/budget.js +128 -4
  77. package/dist/capabilities/builtin-tools.d.ts +3 -0
  78. package/dist/capabilities/builtin-tools.js +3 -0
  79. package/dist/capabilities/center-plugins.d.ts +17 -1
  80. package/dist/capabilities/center-plugins.js +45 -4
  81. package/dist/capabilities/center-prompts.d.ts +46 -0
  82. package/dist/capabilities/center-prompts.js +57 -3
  83. package/dist/capabilities/code-review-council.d.ts +28 -0
  84. package/dist/capabilities/code-review-council.js +40 -7
  85. package/dist/capabilities/collab-wire.d.ts +2 -0
  86. package/dist/capabilities/collab-workflows.d.ts +7 -0
  87. package/dist/capabilities/collab-workflows.js +44 -1
  88. package/dist/capabilities/oa-tools.d.ts +6 -0
  89. package/dist/capabilities/oa-tools.js +10 -0
  90. package/dist/capabilities/prompt.d.ts +14 -0
  91. package/dist/capabilities/prompt.js +14 -0
  92. package/dist/capabilities/prompts/code-review.d.ts +14 -0
  93. package/dist/capabilities/prompts/code-review.js +14 -0
  94. package/dist/capabilities/prompts/identity.d.ts +6 -0
  95. package/dist/capabilities/prompts/identity.js +6 -0
  96. package/dist/capabilities/prompts/team.d.ts +4 -0
  97. package/dist/capabilities/prompts/team.js +4 -0
  98. package/dist/capabilities/repo-tools.d.ts +11 -0
  99. package/dist/capabilities/repo-tools.js +8 -0
  100. package/dist/capabilities/sandbox-file-send.d.ts +95 -0
  101. package/dist/capabilities/sandbox-file-send.js +91 -3
  102. package/dist/capabilities/scenarios.d.ts +130 -0
  103. package/dist/capabilities/scenarios.js +180 -7
  104. package/dist/capabilities/select-environment-tool.d.ts +7 -0
  105. package/dist/capabilities/select-environment-tool.js +30 -0
  106. package/dist/capabilities/send-user-file-tool.d.ts +33 -0
  107. package/dist/capabilities/send-user-file-tool.js +65 -1
  108. package/dist/capabilities/skills.d.ts +29 -0
  109. package/dist/capabilities/skills.js +13 -2
  110. package/dist/capabilities/team.d.ts +22 -0
  111. package/dist/capabilities/team.js +22 -2
  112. package/dist/capabilities/tool-defer.d.ts +26 -0
  113. package/dist/capabilities/tool-defer.js +3 -0
  114. package/dist/config-center/apply-effective.d.ts +65 -0
  115. package/dist/config-center/apply-effective.js +204 -12
  116. package/dist/config-center/http-client.d.ts +34 -0
  117. package/dist/config-center/http-client.js +68 -0
  118. package/dist/config-center/restart-signal.d.ts +22 -0
  119. package/dist/config-center/restart-signal.js +39 -0
  120. package/dist/config-center/skills-mcp.d.ts +20 -1
  121. package/dist/config-center/skills-mcp.js +42 -7
  122. package/dist/config-center/types.d.ts +92 -1
  123. package/dist/config-lkg.d.ts +12 -0
  124. package/dist/config-lkg.js +41 -0
  125. package/dist/config-provider.d.ts +78 -0
  126. package/dist/config-provider.js +165 -2
  127. package/dist/config-types.d.ts +585 -1
  128. package/dist/config.d.ts +78 -2
  129. package/dist/config.js +874 -301
  130. package/dist/degenerate-instrument.d.ts +38 -0
  131. package/dist/degenerate-instrument.js +55 -3
  132. package/dist/elicitation.d.ts +39 -0
  133. package/dist/elicitation.js +87 -3
  134. package/dist/env-facts.d.ts +61 -0
  135. package/dist/env-facts.js +73 -7
  136. package/dist/fleet/fleet-bus.d.ts +185 -0
  137. package/dist/fleet/fleet-bus.js +333 -27
  138. package/dist/fleet/subagent-tail-bus.d.ts +11 -0
  139. package/dist/fleet/subagent-tail-bus.js +33 -2
  140. package/dist/fleet-client.d.ts +38 -0
  141. package/dist/fleet-client.js +44 -9
  142. package/dist/fleet-lease.d.ts +46 -0
  143. package/dist/fleet-lease.js +73 -5
  144. package/dist/hooks/branch-transcript.d.ts +8 -0
  145. package/dist/hooks/branch-transcript.js +33 -0
  146. package/dist/hooks/cc-stop-prompt.d.ts +42 -0
  147. package/dist/hooks/cc-stop-prompt.js +43 -1
  148. package/dist/hooks/hook-llm.d.ts +15 -0
  149. package/dist/hooks/hook-llm.js +47 -0
  150. package/dist/hooks/hook-runner.d.ts +89 -0
  151. package/dist/hooks/hook-runner.js +327 -18
  152. package/dist/http/idempotency.d.ts +31 -0
  153. package/dist/http/idempotency.js +34 -0
  154. package/dist/http/principal-gate.d.ts +17 -0
  155. package/dist/http/principal-gate.js +35 -3
  156. package/dist/http/route-ctx.d.ts +36 -0
  157. package/dist/http/routes/approvals-assistant.d.ts +25 -0
  158. package/dist/http/routes/approvals-assistant.js +253 -23
  159. package/dist/http/routes/attachments.js +22 -4
  160. package/dist/http/routes/capabilities.d.ts +7 -0
  161. package/dist/http/routes/capabilities.js +202 -1
  162. package/dist/http/routes/fleet.d.ts +6 -0
  163. package/dist/http/routes/fleet.js +94 -5
  164. package/dist/http/routes/images.d.ts +17 -0
  165. package/dist/http/routes/images.js +222 -14
  166. package/dist/http/routes/leader.d.ts +7 -0
  167. package/dist/http/routes/leader.js +10 -0
  168. package/dist/http/routes/memory-policy.d.ts +6 -0
  169. package/dist/http/routes/memory-policy.js +38 -6
  170. package/dist/http/routes/notify-wake.d.ts +10 -0
  171. package/dist/http/routes/notify-wake.js +19 -3
  172. package/dist/http/routes/observability.d.ts +6 -0
  173. package/dist/http/routes/observability.js +19 -2
  174. package/dist/http/routes/runs.d.ts +15 -0
  175. package/dist/http/routes/runs.js +464 -41
  176. package/dist/http/routes/session-sync.d.ts +15 -0
  177. package/dist/http/routes/session-sync.js +229 -19
  178. package/dist/http/routes/sessions-list.d.ts +6 -0
  179. package/dist/http/routes/sessions-list.js +35 -4
  180. package/dist/http/routes/sessions.d.ts +14 -0
  181. package/dist/http/routes/sessions.js +176 -31
  182. package/dist/http/routes/side-query.d.ts +8 -0
  183. package/dist/http/routes/side-query.js +26 -1
  184. package/dist/http/routes/tasks.d.ts +18 -0
  185. package/dist/http/routes/tasks.js +501 -38
  186. package/dist/http/routes/trace-usage.d.ts +10 -0
  187. package/dist/http/routes/trace-usage.js +66 -14
  188. package/dist/http/routes/workflows.d.ts +12 -0
  189. package/dist/http/routes/workflows.js +180 -19
  190. package/dist/http/run-meta.d.ts +11 -0
  191. package/dist/http/run-meta.js +6 -0
  192. package/dist/http/send.d.ts +19 -0
  193. package/dist/http/send.js +11 -0
  194. package/dist/http/server.d.ts +255 -0
  195. package/dist/http/server.js +921 -75
  196. package/dist/http/sse-log.d.ts +15 -0
  197. package/dist/http/sse-log.js +16 -0
  198. package/dist/http/tar.d.ts +9 -0
  199. package/dist/http/tar.js +21 -5
  200. package/dist/http/wire-gate.d.ts +9 -0
  201. package/dist/http/wire-gate.js +9 -0
  202. package/dist/http/wire-types.d.ts +187 -0
  203. package/dist/http/workspace-content.d.ts +8 -0
  204. package/dist/http/workspace-content.js +10 -0
  205. package/dist/images/bake-validate.d.ts +63 -0
  206. package/dist/images/bake-validate.js +71 -1
  207. package/dist/images/manifest.d.ts +19 -0
  208. package/dist/images/manifest.js +6 -1
  209. package/dist/index.d.ts +1 -5
  210. package/dist/index.js +10 -5
  211. package/dist/key-resolver.d.ts +23 -0
  212. package/dist/key-resolver.js +27 -2
  213. package/dist/leader/diffout.d.ts +23 -0
  214. package/dist/leader/diffout.js +8 -1
  215. package/dist/leader/diffup.d.ts +32 -0
  216. package/dist/leader/diffup.js +43 -0
  217. package/dist/leader/endpoint.d.ts +20 -0
  218. package/dist/leader/endpoint.js +25 -2
  219. package/dist/leader/fanout.d.ts +60 -0
  220. package/dist/leader/fanout.js +29 -3
  221. package/dist/leader/grader-env-factory.d.ts +74 -0
  222. package/dist/leader/grader-env-factory.js +62 -3
  223. package/dist/leader/leader.d.ts +97 -0
  224. package/dist/leader/leader.js +151 -4
  225. package/dist/leader/merge.d.ts +94 -0
  226. package/dist/leader/merge.js +112 -9
  227. package/dist/leader/planner.d.ts +52 -0
  228. package/dist/leader/planner.js +47 -3
  229. package/dist/leader/repair-oracle.d.ts +61 -0
  230. package/dist/leader/repair-oracle.js +59 -1
  231. package/dist/leader/repair-wire.d.ts +78 -0
  232. package/dist/leader/repair-wire.js +79 -2
  233. package/dist/leader/wire.d.ts +79 -0
  234. package/dist/leader/wire.js +255 -8
  235. package/dist/lsp/e2b-bridge.d.ts +16 -0
  236. package/dist/lsp/e2b-bridge.js +32 -4
  237. package/dist/lsp/e2b-manager.d.ts +10 -0
  238. package/dist/lsp/e2b-manager.js +18 -2
  239. package/dist/lsp/lsp-frames.d.ts +12 -0
  240. package/dist/lsp/lsp-frames.js +12 -0
  241. package/dist/lsp/manager.d.ts +12 -0
  242. package/dist/lsp/manager.js +35 -2
  243. package/dist/lsp/types.d.ts +10 -0
  244. package/dist/lsp/ws-transport.d.ts +12 -0
  245. package/dist/lsp/ws-transport.js +53 -5
  246. package/dist/lsp-evict.d.ts +14 -0
  247. package/dist/lsp-evict.js +15 -1
  248. package/dist/main.js +530 -2129
  249. package/dist/memory-export.d.ts +1 -0
  250. package/dist/memory-export.js +4 -0
  251. package/dist/memory-scope.d.ts +49 -0
  252. package/dist/memory-scope.js +87 -4
  253. package/dist/memory-sync-client.d.ts +24 -0
  254. package/dist/memory-sync-client.js +41 -2
  255. package/dist/memory-sync.d.ts +23 -0
  256. package/dist/memory-sync.js +70 -1
  257. package/dist/model-select.d.ts +39 -0
  258. package/dist/model-select.js +42 -1
  259. package/dist/observability/cost-quota.d.ts +20 -0
  260. package/dist/observability/cost-quota.js +4 -0
  261. package/dist/observability/cost-taxonomy.d.ts +45 -0
  262. package/dist/observability/cost-taxonomy.js +34 -0
  263. package/dist/observability/logger.d.ts +1 -0
  264. package/dist/observability/logger.js +6 -0
  265. package/dist/observability/metrics.d.ts +13 -0
  266. package/dist/observability/metrics.js +63 -0
  267. package/dist/observability/otel-exporter.d.ts +9 -0
  268. package/dist/observability/otel-exporter.js +11 -3
  269. package/dist/observability/principal-context.d.ts +9 -0
  270. package/dist/observability/principal-context.js +9 -0
  271. package/dist/observability/prompt-manifest.d.ts +37 -0
  272. package/dist/observability/prompt-manifest.js +35 -1
  273. package/dist/observability/rate-limit.d.ts +10 -0
  274. package/dist/observability/rate-limit.js +1 -0
  275. package/dist/observability/tool-trace.d.ts +24 -0
  276. package/dist/observability/tool-trace.js +41 -1
  277. package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
  278. package/dist/orchestration/hardened-vm-runner.js +119 -4
  279. package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
  280. package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
  281. package/dist/orchestration/hardened-vm-worker.js +27 -0
  282. package/dist/orchestration/subagent-steer.d.ts +44 -0
  283. package/dist/orchestration/subagent-steer.js +45 -1
  284. package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
  285. package/dist/orchestration/workflow-agent-steer.js +80 -1
  286. package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
  287. package/dist/orchestration/workflow-completion-inbox.js +283 -32
  288. package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
  289. package/dist/orchestration/workflow-notify-journal.js +187 -13
  290. package/dist/parked-decide.d.ts +61 -0
  291. package/dist/parked-decide.js +58 -1
  292. package/dist/per-task-image.d.ts +54 -0
  293. package/dist/per-task-image.js +41 -0
  294. package/dist/plan-cache-probe.d.ts +35 -0
  295. package/dist/plan-cache-probe.js +18 -3
  296. package/dist/plugins/approval-exemption-store.d.ts +7 -0
  297. package/dist/plugins/approval-exemption-store.js +28 -2
  298. package/dist/plugins/approval-store-sql.d.ts +64 -0
  299. package/dist/plugins/approval-store-sql.js +32 -0
  300. package/dist/plugins/background-agent-store-sql.d.ts +55 -0
  301. package/dist/plugins/background-agent-store-sql.js +91 -4
  302. package/dist/plugins/background-shell-support.d.ts +98 -0
  303. package/dist/plugins/background-shell-support.js +117 -13
  304. package/dist/plugins/blob-backend.d.ts +104 -0
  305. package/dist/plugins/blob-backend.js +163 -6
  306. package/dist/plugins/breaker-state-sql.d.ts +65 -1
  307. package/dist/plugins/breaker-state-sql.js +46 -8
  308. package/dist/plugins/caching-session-store.d.ts +42 -0
  309. package/dist/plugins/caching-session-store.js +63 -3
  310. package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
  311. package/dist/plugins/checkpoint-store-sql.js +239 -11
  312. package/dist/plugins/file-outcome-sink.d.ts +4 -0
  313. package/dist/plugins/file-outcome-sink.js +9 -0
  314. package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
  315. package/dist/plugins/file-resume-anchor-store.js +43 -4
  316. package/dist/plugins/file-run-store.d.ts +90 -0
  317. package/dist/plugins/file-run-store.js +145 -13
  318. package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
  319. package/dist/plugins/file-snapshot-store-sql.js +178 -10
  320. package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
  321. package/dist/plugins/file-workflow-journal-store.js +10 -0
  322. package/dist/plugins/fork-routing-session-store.d.ts +47 -0
  323. package/dist/plugins/fork-routing-session-store.js +51 -3
  324. package/dist/plugins/host-platform.d.ts +69 -0
  325. package/dist/plugins/host-platform.js +81 -2
  326. package/dist/plugins/image-bake-store-sql.d.ts +136 -1
  327. package/dist/plugins/image-bake-store-sql.js +241 -7
  328. package/dist/plugins/image-index-sql.d.ts +46 -0
  329. package/dist/plugins/image-index-sql.js +113 -4
  330. package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
  331. package/dist/plugins/k8s-bg-scripts.js +88 -4
  332. package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
  333. package/dist/plugins/k8s-exec-protocol.js +41 -0
  334. package/dist/plugins/local-checkpoint-store.d.ts +40 -0
  335. package/dist/plugins/local-checkpoint-store.js +86 -7
  336. package/dist/plugins/local-session-store.d.ts +157 -0
  337. package/dist/plugins/local-session-store.js +289 -34
  338. package/dist/plugins/local-task-attachment-store.js +14 -2
  339. package/dist/plugins/mailbox-store-sql.d.ts +38 -0
  340. package/dist/plugins/mailbox-store-sql.js +39 -6
  341. package/dist/plugins/memory-engine-pg.d.ts +30 -0
  342. package/dist/plugins/memory-engine-pg.js +122 -4
  343. package/dist/plugins/memory-engine-tidb.d.ts +26 -0
  344. package/dist/plugins/memory-engine-tidb.js +115 -5
  345. package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
  346. package/dist/plugins/memory-engine-vector-util.js +5 -0
  347. package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
  348. package/dist/plugins/memory-resume-anchor-store.js +17 -0
  349. package/dist/plugins/memory-run-store.d.ts +63 -0
  350. package/dist/plugins/memory-run-store.js +73 -8
  351. package/dist/plugins/memory-session-policy-store.d.ts +17 -0
  352. package/dist/plugins/memory-session-policy-store.js +17 -0
  353. package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
  354. package/dist/plugins/memory-sync-store-pg.js +45 -2
  355. package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
  356. package/dist/plugins/memory-sync-store-tidb.js +31 -1
  357. package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
  358. package/dist/plugins/outcome-ledger-sql.js +97 -3
  359. package/dist/plugins/pg-approval-store.d.ts +7 -0
  360. package/dist/plugins/pg-approval-store.js +7 -0
  361. package/dist/plugins/pg-breaker-state.d.ts +6 -0
  362. package/dist/plugins/pg-breaker-state.js +6 -0
  363. package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
  364. package/dist/plugins/pg-checkpoint-store.js +8 -0
  365. package/dist/plugins/pg-cost-quota.d.ts +17 -0
  366. package/dist/plugins/pg-cost-quota.js +6 -0
  367. package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
  368. package/dist/plugins/pg-file-snapshot-store.js +6 -0
  369. package/dist/plugins/pg-image-bake.d.ts +9 -0
  370. package/dist/plugins/pg-image-bake.js +9 -0
  371. package/dist/plugins/pg-image-index.d.ts +9 -0
  372. package/dist/plugins/pg-image-index.js +9 -0
  373. package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
  374. package/dist/plugins/pg-outcome-ledger.js +9 -0
  375. package/dist/plugins/pg-pool.d.ts +50 -0
  376. package/dist/plugins/pg-pool.js +78 -0
  377. package/dist/plugins/pg-query.d.ts +11 -0
  378. package/dist/plugins/pg-rate-limiter.d.ts +23 -0
  379. package/dist/plugins/pg-rate-limiter.js +12 -2
  380. package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
  381. package/dist/plugins/pg-resume-anchor-store.js +5 -0
  382. package/dist/plugins/pg-run-store.d.ts +7 -0
  383. package/dist/plugins/pg-run-store.js +7 -0
  384. package/dist/plugins/pg-safe-json.d.ts +13 -0
  385. package/dist/plugins/pg-safe-json.js +40 -4
  386. package/dist/plugins/pg-session-policy-store.d.ts +5 -0
  387. package/dist/plugins/pg-session-policy-store.js +5 -0
  388. package/dist/plugins/pg-session-storage.d.ts +72 -0
  389. package/dist/plugins/pg-session-storage.js +152 -20
  390. package/dist/plugins/pg-session-store.d.ts +10 -0
  391. package/dist/plugins/pg-session-store.js +10 -0
  392. package/dist/plugins/pg-tool-result-store.d.ts +7 -0
  393. package/dist/plugins/pg-tool-result-store.js +7 -0
  394. package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
  395. package/dist/plugins/pg-workflow-journal-store.js +7 -0
  396. package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
  397. package/dist/plugins/pg-workflow-run-store.js +7 -0
  398. package/dist/plugins/posix-shell-fs.d.ts +3 -0
  399. package/dist/plugins/posix-shell-fs.js +31 -1
  400. package/dist/plugins/remote-env-adb.d.ts +25 -0
  401. package/dist/plugins/remote-env-adb.js +95 -12
  402. package/dist/plugins/remote-env-e2b.d.ts +146 -0
  403. package/dist/plugins/remote-env-e2b.js +371 -40
  404. package/dist/plugins/remote-env-file-error.d.ts +34 -0
  405. package/dist/plugins/remote-env-file-error.js +37 -0
  406. package/dist/plugins/remote-env-host.d.ts +151 -0
  407. package/dist/plugins/remote-env-host.js +468 -70
  408. package/dist/plugins/remote-env-k8s.d.ts +135 -0
  409. package/dist/plugins/remote-env-k8s.js +318 -32
  410. package/dist/plugins/remote-env-local-docker.d.ts +65 -0
  411. package/dist/plugins/remote-env-local-docker.js +149 -24
  412. package/dist/plugins/remote-env-ssh.d.ts +35 -0
  413. package/dist/plugins/remote-env-ssh.js +117 -20
  414. package/dist/plugins/remote-scratchpad.d.ts +38 -0
  415. package/dist/plugins/remote-scratchpad.js +32 -2
  416. package/dist/plugins/remote-shell.d.ts +22 -0
  417. package/dist/plugins/remote-shell.js +27 -1
  418. package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
  419. package/dist/plugins/resume-anchor-store-sql.js +11 -0
  420. package/dist/plugins/roster-store-sql.d.ts +27 -0
  421. package/dist/plugins/roster-store-sql.js +54 -0
  422. package/dist/plugins/run-store-sql.d.ts +194 -0
  423. package/dist/plugins/run-store-sql.js +210 -9
  424. package/dist/plugins/s3-presign.d.ts +20 -0
  425. package/dist/plugins/s3-presign.js +49 -2
  426. package/dist/plugins/scheduler-support.d.ts +12 -0
  427. package/dist/plugins/scheduler-support.js +75 -3
  428. package/dist/plugins/send-file-ledger.d.ts +15 -0
  429. package/dist/plugins/send-file-ledger.js +53 -4
  430. package/dist/plugins/send-user-file.d.ts +77 -0
  431. package/dist/plugins/send-user-file.js +92 -4
  432. package/dist/plugins/session-policy-store-sql.d.ts +15 -0
  433. package/dist/plugins/session-policy-store-sql.js +75 -3
  434. package/dist/plugins/session-store.d.ts +45 -0
  435. package/dist/plugins/session-store.js +51 -0
  436. package/dist/plugins/sql-driver.d.ts +77 -0
  437. package/dist/plugins/sql-driver.js +4 -0
  438. package/dist/plugins/sql-escape.d.ts +8 -0
  439. package/dist/plugins/sql-escape.js +8 -0
  440. package/dist/plugins/sql-row-helpers.d.ts +25 -0
  441. package/dist/plugins/sql-row-helpers.js +25 -0
  442. package/dist/plugins/store-backend.d.ts +103 -0
  443. package/dist/plugins/store-backend.js +120 -27
  444. package/dist/plugins/store-contracts.d.ts +62 -0
  445. package/dist/plugins/store-contracts.js +3 -0
  446. package/dist/plugins/task-attachment-store.d.ts +60 -0
  447. package/dist/plugins/task-attachment-store.js +49 -3
  448. package/dist/plugins/task-list-store-sql.d.ts +25 -0
  449. package/dist/plugins/task-list-store-sql.js +21 -0
  450. package/dist/plugins/tidb-approval-store.d.ts +6 -0
  451. package/dist/plugins/tidb-approval-store.js +6 -0
  452. package/dist/plugins/tidb-breaker-state.d.ts +5 -0
  453. package/dist/plugins/tidb-breaker-state.js +5 -0
  454. package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
  455. package/dist/plugins/tidb-checkpoint-store.js +7 -0
  456. package/dist/plugins/tidb-cost-quota.d.ts +6 -0
  457. package/dist/plugins/tidb-cost-quota.js +1 -0
  458. package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
  459. package/dist/plugins/tidb-file-snapshot-store.js +6 -0
  460. package/dist/plugins/tidb-image-bake.d.ts +8 -0
  461. package/dist/plugins/tidb-image-bake.js +8 -0
  462. package/dist/plugins/tidb-image-index.d.ts +8 -0
  463. package/dist/plugins/tidb-image-index.js +8 -0
  464. package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
  465. package/dist/plugins/tidb-outcome-ledger.js +10 -0
  466. package/dist/plugins/tidb-pool.d.ts +56 -0
  467. package/dist/plugins/tidb-pool.js +181 -1
  468. package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
  469. package/dist/plugins/tidb-rate-limiter.js +5 -2
  470. package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
  471. package/dist/plugins/tidb-resume-anchor-store.js +5 -0
  472. package/dist/plugins/tidb-run-store.d.ts +7 -0
  473. package/dist/plugins/tidb-run-store.js +7 -0
  474. package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
  475. package/dist/plugins/tidb-session-policy-store.js +5 -0
  476. package/dist/plugins/tidb-session-storage.d.ts +43 -0
  477. package/dist/plugins/tidb-session-storage.js +62 -3
  478. package/dist/plugins/tidb-session-store.d.ts +142 -0
  479. package/dist/plugins/tidb-session-store.js +264 -16
  480. package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
  481. package/dist/plugins/tidb-tool-result-store.js +7 -0
  482. package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
  483. package/dist/plugins/tidb-workflow-journal-store.js +7 -0
  484. package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
  485. package/dist/plugins/tidb-workflow-run-store.js +8 -0
  486. package/dist/plugins/tool-result-store-sql.d.ts +58 -0
  487. package/dist/plugins/tool-result-store-sql.js +38 -2
  488. package/dist/plugins/web-search.d.ts +35 -0
  489. package/dist/plugins/web-search.js +45 -9
  490. package/dist/plugins/workflow-journal-limits.d.ts +10 -0
  491. package/dist/plugins/workflow-journal-limits.js +10 -0
  492. package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
  493. package/dist/plugins/workflow-journal-store-sql.js +58 -2
  494. package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
  495. package/dist/plugins/workflow-run-store-sql.js +84 -6
  496. package/dist/plugins/worktree-isolation.d.ts +45 -0
  497. package/dist/plugins/worktree-isolation.js +105 -6
  498. package/dist/plugins/write-behind-counter.d.ts +56 -1
  499. package/dist/plugins/write-behind-counter.js +53 -14
  500. package/dist/principal-jwt.d.ts +24 -0
  501. package/dist/principal-jwt.js +60 -5
  502. package/dist/project-memory.d.ts +22 -0
  503. package/dist/project-memory.js +144 -15
  504. package/dist/prompts-domain-validate.d.ts +28 -0
  505. package/dist/prompts-domain-validate.js +42 -1
  506. package/dist/question.d.ts +33 -0
  507. package/dist/question.js +69 -2
  508. package/dist/resource-suspend.d.ts +21 -0
  509. package/dist/resource-suspend.js +16 -0
  510. package/dist/router/route-orchestration.d.ts +78 -0
  511. package/dist/router/route-orchestration.js +77 -0
  512. package/dist/run-local.d.ts +32 -0
  513. package/dist/run-local.js +172 -8
  514. package/dist/runs.d.ts +189 -4
  515. package/dist/runs.js +465 -24
  516. package/dist/runtime-caps-resolver.d.ts +106 -0
  517. package/dist/runtime-caps-resolver.js +89 -4
  518. package/dist/runtime-governance.d.ts +84 -0
  519. package/dist/runtime-governance.js +127 -1
  520. package/dist/sandbox-pkg-source.d.ts +23 -0
  521. package/dist/sandbox-pkg-source.js +37 -0
  522. package/dist/sealed-key.d.ts +54 -0
  523. package/dist/sealed-key.js +68 -3
  524. package/dist/security.d.ts +108 -0
  525. package/dist/security.js +145 -6
  526. package/dist/sema-registry.d.ts +21 -0
  527. package/dist/sema-registry.js +21 -0
  528. package/dist/session-leaf-bus.d.ts +31 -0
  529. package/dist/session-leaf-bus.js +32 -0
  530. package/dist/session-sync-content.d.ts +46 -0
  531. package/dist/session-sync-content.js +47 -1
  532. package/dist/session-sync-kernel.d.ts +89 -0
  533. package/dist/session-sync-kernel.js +48 -3
  534. package/dist/session-sync.d.ts +125 -0
  535. package/dist/session-sync.js +181 -8
  536. package/dist/session-titler.d.ts +26 -0
  537. package/dist/session-titler.js +41 -7
  538. package/dist/session-watch.d.ts +53 -1
  539. package/dist/session-watch.js +73 -9
  540. package/dist/sighup-idle.d.ts +30 -0
  541. package/dist/sighup-idle.js +12 -1
  542. package/dist/spec-fields.d.ts +91 -3
  543. package/dist/spec-fields.js +116 -4
  544. package/dist/task-cwd.d.ts +50 -0
  545. package/dist/task-cwd.js +68 -1
  546. package/dist/task-mcp.d.ts +47 -0
  547. package/dist/task-mcp.js +29 -0
  548. package/dist/task-settings.d.ts +175 -0
  549. package/dist/task-settings.js +226 -11
  550. package/dist/task-workflow.d.ts +67 -0
  551. package/dist/task-workflow.js +75 -8
  552. package/dist/tool-approval.d.ts +91 -0
  553. package/dist/tool-approval.js +215 -0
  554. package/dist/trace/artifacts.d.ts +9 -0
  555. package/dist/trace/artifacts.js +30 -5
  556. package/dist/trace/core-keyset-guard.d.ts +18 -0
  557. package/dist/trace/ledger-sink.d.ts +43 -0
  558. package/dist/trace/ledger-sink.js +64 -5
  559. package/dist/trace/project.d.ts +133 -0
  560. package/dist/trace/project.js +189 -2
  561. package/dist/trace/redact.d.ts +19 -0
  562. package/dist/trace/redact.js +66 -9
  563. package/dist/usage-analytics.d.ts +26 -0
  564. package/dist/usage-analytics.js +26 -3
  565. package/package.json +1 -1
@@ -1,24 +1,51 @@
1
1
  import type { WorkflowRun, WorkflowRunStore, WorkflowRunStatus, WorkflowRunSummary } from "@sema-agent/core";
2
2
  import type { FleetEventBus } from "../fleet/fleet-bus.js";
3
+ /** A workflow completion notification's terminal payload — the bounded, redacted shape core's notifier seam
4
+ * carries, re-derivable from a durable {@link import("@sema-agent/core").WorkflowRun} on the recovery path. */
3
5
  export interface WorkflowCompletionPayload {
4
6
  runId: string;
5
7
  status: "completed" | "failed";
8
+ /** Redacted + length-bounded — never host-internal paths/tokens (parity with core's `boundedSummary`). */
6
9
  summary: string;
7
10
  sourceTaskId?: string;
8
11
  principal?: string;
12
+ /** core 1.208: the ORIGINATING session id, closed over by the Runner at RunWorkflow mount time —
13
+ * the lookup-free routing key for the completion inbox. Present on the LIVE notify path; ABSENT on the
14
+ * crash-recovery path (the durable `WorkflowRun` does not carry it — relayed to core to thread it there too,
15
+ * parity with `sourceTaskId`'s 1.187 story), where the delivery falls back to the `sourceTaskId` run-row lookup. */
9
16
  originatingSessionId?: string;
10
17
  }
18
+ /** The downstream delivery the journal guards (the deployment's real completion route — log+meter today, a full
19
+ * re-invoke into the originator's stream/inbox tomorrow). Idempotent on `runId` by contract; the journal still
20
+ * de-dups so it is invoked AT MOST once per run in steady state and at most one extra time across a crash. */
11
21
  export type WorkflowCompletionDelivery = (p: WorkflowCompletionPayload) => Promise<void> | void;
22
+ /** One journal entry: the durable to-do record for a single run's completion notify. `acked` flips true ONLY
23
+ * after delivery succeeds (deliver-then-ack — a crash mid-delivery re-delivers on recovery). */
12
24
  export interface WorkflowNotifyJournalEntry {
13
25
  runId: string;
26
+ /** The run's scope (= creating principal) — needed to re-fetch / owner-attribute on recovery. */
14
27
  scope: string;
28
+ /** Whether the completion has been DELIVERED to the downstream sink (and may be GC'd). */
15
29
  acked: boolean;
30
+ /** The originating task id, threaded to the delivery (parity with core's notifier input). */
16
31
  sourceTaskId?: string;
32
+ /** The originating principal, threaded to the delivery. */
17
33
  principal?: string;
34
+ /** When the run was journaled (epoch ms) — for retention + observability. */
18
35
  createdAt: number;
36
+ /** When the entry was acked (epoch ms) — set with `acked`. */
19
37
  ackedAt?: number;
20
38
  }
39
+ /**
40
+ * The pluggable durable seam for the notify journal. Intentionally tiny: record a started run, mark it acked,
41
+ * and enumerate the un-acked backlog the recovery sweep walks. `listPending` is the one method the
42
+ * `WorkflowRunStore` cannot provide (it has no cross-scope enumeration) and is the whole reason the journal is a
43
+ * separate store. A backend (the File default, or a follow-on TiDB/PG) implements this; the gate logic in
44
+ * {@link WorkflowNotifyGate} is backend-agnostic.
45
+ */
21
46
  export interface WorkflowNotifyJournalStore {
47
+ /** Record a STARTED run as pending-notify. Idempotent on `runId`: a second `record` for the same run is a
48
+ * no-op (it must NOT reset an already-`acked` entry back to pending — that would re-deliver forever). */
22
49
  record(entry: {
23
50
  runId: string;
24
51
  scope: string;
@@ -26,11 +53,27 @@ export interface WorkflowNotifyJournalStore {
26
53
  principal?: string;
27
54
  createdAt: number;
28
55
  }): Promise<void>;
56
+ /** Mark a run's completion DELIVERED. Idempotent: acking an already-acked or missing run is a no-op. */
29
57
  ack(runId: string, ackedAt: number): Promise<void>;
58
+ /** Every NOT-`acked` entry — the recovery backlog. Order is unspecified (the sweep handles each independently). */
30
59
  listPending(): Promise<WorkflowNotifyJournalEntry[]>;
60
+ /** Read one entry (`null` when absent) — lets the gate check `acked` before a live delivery (the dedup). */
31
61
  get(runId: string): Promise<WorkflowNotifyJournalEntry | null>;
32
62
  }
33
63
  export declare function recoverySummary(status: WorkflowRunStatus, error?: string): string;
64
+ /**
65
+ * The AT-LEAST-ONCE completion-notify gate. Wrap the deployment's real delivery once at boot, then:
66
+ * - {@link buildNotifier} hands core a {@link import("@sema-agent/core").WorkflowCompletionNotifier} whose `notify`
67
+ * runs the LIVE deliver-then-ack path (the in-process at-most-once notify, now journaled into at-least-once).
68
+ * - {@link onWorkflowStart} journals a run the moment it starts (so a crash BEFORE its terminal notify still
69
+ * leaves a pending entry the recovery sweep finds). Call it from wherever the runId becomes known.
70
+ * - {@link recover} runs ONCE at boot: re-derives every pending run's terminal state from the
71
+ * {@link WorkflowRunStore} and re-delivers + acks the ones that are terminal.
72
+ *
73
+ * The gate is the SINGLE writer of `acked`, and dedups every delivery against the journal, so the wrapped
74
+ * delivery sink is invoked at most once per run in steady state (and at most one extra time across a crash —
75
+ * the at-least-once / idempotent contract).
76
+ */
34
77
  export declare class WorkflowNotifyGate {
35
78
  private readonly journal;
36
79
  private readonly runStore;
@@ -38,21 +81,60 @@ export declare class WorkflowNotifyGate {
38
81
  private readonly opts;
39
82
  constructor(journal: WorkflowNotifyJournalStore, runStore: WorkflowRunStore, deliver: WorkflowCompletionDelivery, opts?: {
40
83
  now?: () => number;
84
+ /** Surfaced on a failure (so a transient downstream/journal error is observable, NOT swallowed silently —
85
+ * it stays pending + retries on the next recovery sweep). Never throws back into core's notify. `record` =
86
+ * the start-time journal write failed; `deliver` = the downstream delivery threw; `recover` = a per-entry
87
+ * recovery-sweep error. */
41
88
  onError?: (stage: "record" | "deliver" | "recover", runId: string, err: unknown) => void;
42
89
  });
43
90
  private now;
91
+ /**
92
+ * Journal a STARTED run as pending-notify. Call this with the synchronous `runId` from `startWorkflow` /
93
+ * `run_workflow` — BEFORE the workflow can reach terminal — so a crash mid-run still leaves a recoverable
94
+ * to-do. Best-effort + idempotent: a journal throw is reported, never propagated (it must not break the
95
+ * workflow start; worst case the recovery sweep won't know about this run — degraded, not corrupting).
96
+ */
44
97
  onWorkflowStart(input: {
45
98
  runId: string;
46
99
  scope: string;
47
100
  sourceTaskId?: string;
48
101
  principal?: string;
49
102
  }): Promise<void>;
103
+ /**
104
+ * The core-facing notifier. core calls this exactly once per run on terminal (its own at-most-once, runId-dedup
105
+ * `fire`). We turn it into at-least-once: ensure the run is journaled (the start hook may have been skipped),
106
+ * then deliver-then-ack. Idempotent: if the run is ALREADY acked (a recovery sweep beat us, or a duplicate
107
+ * core fire), skip — at most one delivery.
108
+ */
50
109
  buildNotifier(): {
51
110
  notify: (input: WorkflowCompletionPayload & {
52
111
  scope?: string;
53
112
  }) => Promise<void>;
54
113
  };
114
+ /**
115
+ * Deliver a run's completion exactly once (idempotent on the journal). Ensures the entry exists (record is a
116
+ * no-op if it already does), SKIPS if already acked, otherwise delivers THEN acks (a crash between deliver and
117
+ * ack re-delivers on recovery — at-least-once). A delivery throw is reported and re-thrown to the LIVE caller
118
+ * only as a swallowed report (core's `fire` already `.catch`es), leaving the entry pending for the next sweep.
119
+ */
55
120
  private deliverOnce;
121
+ /**
122
+ * RECOVERY sweep — run at boot AND PERIODICALLY (wired into the service reaper), BEFORE/while serving traffic.
123
+ * For every pending (not-acked) journal entry, re-fetch the run from the durable {@link WorkflowRunStore}:
124
+ * - TERMINAL (completed/failed): its in-process notify was lost to a crash (or it finished while we were
125
+ * down) → re-deliver + ack (idempotent on the receiver).
126
+ * - `running` but STALE (run.startedAt older than `orphanGraceMs`): a crash-orphaned run — core never resumes
127
+ * a prior `running` row (resume mints a NEW runId) and never reaps a `running` row, so NOTHING will ever
128
+ * flip it terminal. Finalize-as-ABANDONED: deliver a `failed` completion (so the originator learns the
129
+ * workflow died) + ack, instead of leaking the entry forever. This closes the exact crash topology SVC-1
130
+ * exists for (a replica SIGKILLed mid-run).
131
+ * - `running` and FRESH (within the grace window): genuinely in flight → leave pending (the owning process
132
+ * delivers its terminal notify, or the next sweep catches it once it goes terminal or stale).
133
+ * - MISSING (reaped / never persisted): ack-as-abandoned so the journal doesn't chase a ghost forever.
134
+ * `orphanGraceMs` MUST exceed the max expected workflow runtime (the run store has no cross-replica liveness
135
+ * signal, so age is the only orphan proxy). Returns a tally. A per-entry throw is isolated so one bad entry
136
+ * can't abort the sweep.
137
+ */
56
138
  recover(opts?: {
57
139
  orphanGraceMs?: number;
58
140
  }): Promise<{
@@ -62,13 +144,28 @@ export declare class WorkflowNotifyGate {
62
144
  abandoned: number;
63
145
  }>;
64
146
  }
147
+ /**
148
+ * Default zero-dependency, crash-safe {@link WorkflowNotifyJournalStore}. An append-only JSONL ledger replayed
149
+ * at boot (last-writer-wins per `runId`), the same durable posture as core's `FileWorkflowRunStore` — fsync'd
150
+ * appends, atomic single-line records. Single-instance / TOC-local: a cross-replica TiDB/PG port is a follow-on
151
+ * (the recovery sweep + gate are backend-agnostic).
152
+ *
153
+ * The ledger only ever grows by one line per `record`/`ack`; an acked entry's line is not deleted (the replay
154
+ * folds it), so retention is a future compaction concern — the backlog `listPending` walks is bounded by
155
+ * IN-FLIGHT + un-swept runs, not history.
156
+ */
65
157
  export declare class FileWorkflowNotifyJournalStore implements WorkflowNotifyJournalStore {
66
158
  private readonly fsyncEnabled;
67
159
  private readonly ledgerPath;
68
160
  private readonly entries;
69
161
  private fd;
70
162
  constructor(root: string, fsyncEnabled?: boolean);
163
+ /** Replay the ledger into the authoritative map (last-writer-wins by line order). Tolerates a torn final line
164
+ * (a crash mid-append) by dropping an unparsable trailing record — the same crash-safety FileWorkflowRunStore
165
+ * relies on (a partial append is simply not yet committed state). */
71
166
  private replay;
167
+ /** Commit one entry: append the JSON line (fsync) THEN flip the in-memory map (crash-safe ordering — the
168
+ * durable record lands before the in-memory state the caller observes). */
72
169
  private commit;
73
170
  record(input: {
74
171
  runId: string;
@@ -80,9 +177,15 @@ export declare class FileWorkflowNotifyJournalStore implements WorkflowNotifyJou
80
177
  ack(runId: string, ackedAt: number): Promise<void>;
81
178
  listPending(): Promise<WorkflowNotifyJournalEntry[]>;
82
179
  get(runId: string): Promise<WorkflowNotifyJournalEntry | null>;
180
+ /** Release the append handle (best-effort) — called on shutdown. */
83
181
  close(): void;
182
+ /** Test/inspection: total entries (acked + pending). */
84
183
  get size(): number;
85
184
  }
185
+ /** In-process {@link WorkflowNotifyJournalStore} — tests / single-instance ephemeral. Does NOT survive a
186
+ * restart (so it provides NO crash-recovery on its own); use {@link FileWorkflowNotifyJournalStore} or a
187
+ * durable backend for the real at-least-once guarantee. Useful to unit-test the gate's live + idempotency
188
+ * paths without touching disk, and to simulate a crash by handing a FRESH store to a new gate. */
86
189
  export declare class InMemoryWorkflowNotifyJournalStore implements WorkflowNotifyJournalStore {
87
190
  private readonly entries;
88
191
  record(input: {
@@ -97,11 +200,39 @@ export declare class InMemoryWorkflowNotifyJournalStore implements WorkflowNotif
97
200
  get(runId: string): Promise<WorkflowNotifyJournalEntry | null>;
98
201
  get size(): number;
99
202
  }
203
+ /**
204
+ * A {@link WorkflowRunStore} DECORATOR that journals a run the instant core persists it at START. core's
205
+ * `startWorkflow` `put`s the run row (`status: "running"`) synchronously before the body runs, carrying both the
206
+ * `runId` and the `scope` — the one synchronous start-time hook the service gets WITHOUT a new core seam (core
207
+ * exposes no `onWorkflowStart`). Wrapping the run store here observes that `put`, journals the started run as
208
+ * pending-notify, then delegates to the wrapped store. Every other method is a pure pass-through (the run store
209
+ * stays core's source of truth for `/workflows`). This is the [[core-service-boundary]]-clean wiring: reuse the
210
+ * core store seam, observe writes through it, never fork a parallel run model.
211
+ *
212
+ * Journaling on `put` (not on notify) is what makes recovery cover a crash BEFORE terminal: the entry exists the
213
+ * moment the run starts, so the boot sweep finds it even if the process died mid-run.
214
+ */
100
215
  export declare class JournalingWorkflowRunStore implements WorkflowRunStore {
101
216
  private readonly inner;
217
+ /** [1262] optional since the fleet decoupling: undefined ⇒ no start-time journal (ephemeral memory
218
+ * backend has nothing to recover), the FLEET half still publishes — the panel is replica-local UI
219
+ * state and must not be gated on the durable-notify machinery (the regression that emptied clay's
220
+ * workflow panel on memory-backend deployments). */
102
221
  private readonly gate?;
222
+ /** MF-Fleet (data contract): publish the workflow's fleet row on every put/update (the same write-observation
223
+ * point as the notify journal). Optional — undefined ⇒ no fleet publish. */
103
224
  private readonly fleetBus?;
104
- constructor(inner: WorkflowRunStore, gate?: Pick<WorkflowNotifyGate, "onWorkflowStart"> | undefined, fleetBus?: FleetEventBus | undefined);
225
+ constructor(inner: WorkflowRunStore,
226
+ /** [1262] optional since the fleet decoupling: undefined ⇒ no start-time journal (ephemeral memory
227
+ * backend has nothing to recover), the FLEET half still publishes — the panel is replica-local UI
228
+ * state and must not be gated on the durable-notify machinery (the regression that emptied clay's
229
+ * workflow panel on memory-backend deployments). */
230
+ gate?: Pick<WorkflowNotifyGate, "onWorkflowStart"> | undefined,
231
+ /** MF-Fleet (data contract): publish the workflow's fleet row on every put/update (the same write-observation
232
+ * point as the notify journal). Optional — undefined ⇒ no fleet publish. */
233
+ fleetBus?: FleetEventBus | undefined);
234
+ /** Derive + publish the MF-Fleet workflow row from a WorkflowRun (doneCount/totalCount from agents, tokens from
235
+ * stats); a terminal workflow LEAVES the fleet (publish terminal then remove), a running one stays/updates. */
105
236
  private publishFleet;
106
237
  put(id: string, run: WorkflowRun): Promise<void>;
107
238
  update(id: string, scope: string, run: WorkflowRun, expect?: {
@@ -1,7 +1,52 @@
1
+ /**
2
+ * SVC-1 (core contract) — the AT-LEAST-ONCE workflow completion-notify TRUST GATE.
3
+ *
4
+ * ## Why this exists
5
+ * core's `run_workflow` tool already does the BACKGROUND-RUN half of SVC-1: `startWorkflow` returns a `runId`
6
+ * synchronously (the caller never blocks), the workflow runs to terminal in the background, and on terminal the
7
+ * tool fires a single in-process completion notify through the {@link import("@sema-agent/core").WorkflowCompletionNotifier}
8
+ * seam (see core `run-workflow-tool.js`). That notify is **at-MOST-once**: it lives only in the process that
9
+ * started the run. If the replica CRASHES between the workflow reaching terminal and the receiver acking the
10
+ * notification — or if it crashes before the run even finishes — the notification is LOST. Nothing re-derives it.
11
+ *
12
+ * SVC-1 makes the completion notify **at-LEAST-once**, the half that is service's (design boundary
13
+ * [[core-service-boundary]] — the durable wiring + the deployment notify route is TOB, not core):
14
+ * 1. **terminal → notify** (steady state): every started run is journaled as `pending`; when its in-process
15
+ * notify fires, we record the terminal status durably, DELIVER to the wrapped notifier, and mark the journal
16
+ * entry `acked`. Delivery before ack ⇒ a crash mid-delivery re-delivers on recovery (never a silent drop).
17
+ * 2. **crash-recovery → re-derive + notify** (startup): on boot we read the journal for every NOT-`acked` entry
18
+ * and RE-FETCH the run from the durable {@link import("@sema-agent/core").WorkflowRunStore}. A run that is now
19
+ * TERMINAL (its in-process notify was lost to the crash, or it finished while we were down) is RE-DELIVERED
20
+ * and acked. A run still `running` is left pending — the live process owns its terminal notify, and the next
21
+ * recovery sweep (or that process's own delivery) will catch it. A run MISSING from the store (reaped /
22
+ * never persisted) is acked-as-abandoned so the journal does not grow unbounded chasing a ghost.
23
+ * 3. **idempotent**: the journal de-dups by `runId` (a delivered+acked run is never re-delivered), so the
24
+ * wrapped notifier — and the downstream receiver — may safely be invoked twice for the same run across a
25
+ * crash boundary (the SVC-1 contract: the receiver is idempotent on `runId`). We dedup on OUR side too, so a
26
+ * double recovery sweep, or a recovery racing the live notify, delivers at most one extra time, not N.
27
+ *
28
+ * ## Durability model
29
+ * The journal is itself a {@link WorkflowNotifyJournalStore} — a tiny append-only `(runId → entry)` durable map,
30
+ * deliberately SEPARATE from the `WorkflowRunStore`: the run store is core-owned (its schema/CAS is core's), and
31
+ * critically it has **no cross-scope enumeration** (`listByScope` needs a scope; there is no "list all runs" /
32
+ * "list all scopes"), so it cannot by itself answer "which runs might still owe a notify?" after a restart. The
33
+ * journal records `(runId, scope)` for exactly that: a bounded, service-owned to-do list of notifications, scoped
34
+ * to the deployment, that the recovery sweep walks. It is the SINGLE source of truth for "has this run's
35
+ * completion been delivered?".
36
+ *
37
+ * The default {@link FileWorkflowNotifyJournalStore} is zero-dependency + crash-safe (atomic-append ledger, same
38
+ * posture as core's `FileWorkflowRunStore`) so the no-DB / TOC-local path is durable out of the box. A durable
39
+ * cross-replica backend (TiDB/PG) is a thin port of the same interface (a follow-on; the recovery sweep + the
40
+ * gate logic here are backend-agnostic).
41
+ */
1
42
  import { mkdirSync, readFileSync, existsSync, openSync, writeSync, fsyncSync, closeSync } from "node:fs";
2
43
  import { join } from "node:path";
3
44
  import { deriveAgentDisplayStatus } from "@sema-agent/core";
4
45
  import { redactSecrets } from "../trace/redact.js";
46
+ /** Build a bounded + redacted completion summary from a durable run's terminal state (the recovery path — the
47
+ * live path uses core's own `boundedSummary`). We never have the raw result here (the run store keeps the run,
48
+ * not the originator's payload), so we synthesize a conservative one: status + the run's already-bounded error.
49
+ * Mirrors core `failureSummary`/`redactSummary` posture — strip URLs/tokens/paths defensively. */
5
50
  const SUMMARY_MAX = 500;
6
51
  export function recoverySummary(status, error) {
7
52
  if (status === "completed")
@@ -12,9 +57,24 @@ export function recoverySummary(status, error) {
12
57
  .replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi, "[redacted-token]")
13
58
  .replace(/\b(?:api[_-]?key|secret|token|password|authorization)\b\s*[:=]\s*"?[^\s"',}]+/gi, "[redacted-secret]")
14
59
  .replace(/(?:\/[A-Za-z0-9_.-]+){2,}/g, "[redacted-path]")
60
+ // Windows/UNC paths too (SVC-1 review): `C:\dir\file` + `\\host\share\…` would otherwise surface VERBATIM — a
61
+ // host-path/identity leak the forward-slash rule above misses. `\\{1,2}` covers the UNC double-leading-backslash.
15
62
  .replace(/(?:[A-Za-z]:)?(?:\\{1,2}[A-Za-z0-9_.$-]+){2,}/g, "[redacted-path]");
16
63
  return redacted.length > SUMMARY_MAX ? `${redacted.slice(0, SUMMARY_MAX)}…[+${redacted.length - SUMMARY_MAX} chars]` : redacted;
17
64
  }
65
+ /**
66
+ * The AT-LEAST-ONCE completion-notify gate. Wrap the deployment's real delivery once at boot, then:
67
+ * - {@link buildNotifier} hands core a {@link import("@sema-agent/core").WorkflowCompletionNotifier} whose `notify`
68
+ * runs the LIVE deliver-then-ack path (the in-process at-most-once notify, now journaled into at-least-once).
69
+ * - {@link onWorkflowStart} journals a run the moment it starts (so a crash BEFORE its terminal notify still
70
+ * leaves a pending entry the recovery sweep finds). Call it from wherever the runId becomes known.
71
+ * - {@link recover} runs ONCE at boot: re-derives every pending run's terminal state from the
72
+ * {@link WorkflowRunStore} and re-delivers + acks the ones that are terminal.
73
+ *
74
+ * The gate is the SINGLE writer of `acked`, and dedups every delivery against the journal, so the wrapped
75
+ * delivery sink is invoked at most once per run in steady state (and at most one extra time across a crash —
76
+ * the at-least-once / idempotent contract).
77
+ */
18
78
  export class WorkflowNotifyGate {
19
79
  journal;
20
80
  runStore;
@@ -29,6 +89,12 @@ export class WorkflowNotifyGate {
29
89
  now() {
30
90
  return this.opts.now ? this.opts.now() : Date.now();
31
91
  }
92
+ /**
93
+ * Journal a STARTED run as pending-notify. Call this with the synchronous `runId` from `startWorkflow` /
94
+ * `run_workflow` — BEFORE the workflow can reach terminal — so a crash mid-run still leaves a recoverable
95
+ * to-do. Best-effort + idempotent: a journal throw is reported, never propagated (it must not break the
96
+ * workflow start; worst case the recovery sweep won't know about this run — degraded, not corrupting).
97
+ */
32
98
  async onWorkflowStart(input) {
33
99
  try {
34
100
  await this.journal.record({
@@ -40,9 +106,15 @@ export class WorkflowNotifyGate {
40
106
  });
41
107
  }
42
108
  catch (err) {
43
- this.opts.onError?.("record", input.runId, err);
109
+ this.opts.onError?.("record", input.runId, err); // start-time JOURNAL write failed (not a delivery)
44
110
  }
45
111
  }
112
+ /**
113
+ * The core-facing notifier. core calls this exactly once per run on terminal (its own at-most-once, runId-dedup
114
+ * `fire`). We turn it into at-least-once: ensure the run is journaled (the start hook may have been skipped),
115
+ * then deliver-then-ack. Idempotent: if the run is ALREADY acked (a recovery sweep beat us, or a duplicate
116
+ * core fire), skip — at most one delivery.
117
+ */
46
118
  buildNotifier() {
47
119
  return {
48
120
  notify: async (input) => {
@@ -52,16 +124,24 @@ export class WorkflowNotifyGate {
52
124
  summary: input.summary,
53
125
  ...(input.sourceTaskId ? { sourceTaskId: input.sourceTaskId } : {}),
54
126
  ...(input.principal ? { principal: input.principal } : {}),
55
- ...(input.originatingSessionId ? { originatingSessionId: input.originatingSessionId } : {}),
127
+ ...(input.originatingSessionId ? { originatingSessionId: input.originatingSessionId } : {}), // core 1.208: lookup-free session routing
56
128
  }, input.scope ?? input.principal ?? "default");
57
129
  },
58
130
  };
59
131
  }
132
+ /**
133
+ * Deliver a run's completion exactly once (idempotent on the journal). Ensures the entry exists (record is a
134
+ * no-op if it already does), SKIPS if already acked, otherwise delivers THEN acks (a crash between deliver and
135
+ * ack re-delivers on recovery — at-least-once). A delivery throw is reported and re-thrown to the LIVE caller
136
+ * only as a swallowed report (core's `fire` already `.catch`es), leaving the entry pending for the next sweep.
137
+ */
60
138
  async deliverOnce(p, scope) {
61
139
  const existing = await this.journal.get(p.runId);
62
140
  if (existing?.acked)
63
- return;
141
+ return; // already delivered — idempotent skip
64
142
  if (!existing) {
143
+ // The start hook didn't journal it (e.g. a run started before this gate existed, or the hook was skipped).
144
+ // Record it now so the deliver-then-ack ordering still holds and a crash mid-delivery is recoverable.
65
145
  await this.journal.record({
66
146
  runId: p.runId,
67
147
  scope,
@@ -74,13 +154,31 @@ export class WorkflowNotifyGate {
74
154
  await this.deliver(p);
75
155
  }
76
156
  catch (err) {
157
+ // Stays PENDING (not acked) → the next recovery sweep re-delivers. Report, never throw back into core.
77
158
  this.opts.onError?.("deliver", p.runId, err);
78
159
  return;
79
160
  }
80
161
  await this.journal.ack(p.runId, this.now());
81
162
  }
163
+ /**
164
+ * RECOVERY sweep — run at boot AND PERIODICALLY (wired into the service reaper), BEFORE/while serving traffic.
165
+ * For every pending (not-acked) journal entry, re-fetch the run from the durable {@link WorkflowRunStore}:
166
+ * - TERMINAL (completed/failed): its in-process notify was lost to a crash (or it finished while we were
167
+ * down) → re-deliver + ack (idempotent on the receiver).
168
+ * - `running` but STALE (run.startedAt older than `orphanGraceMs`): a crash-orphaned run — core never resumes
169
+ * a prior `running` row (resume mints a NEW runId) and never reaps a `running` row, so NOTHING will ever
170
+ * flip it terminal. Finalize-as-ABANDONED: deliver a `failed` completion (so the originator learns the
171
+ * workflow died) + ack, instead of leaking the entry forever. This closes the exact crash topology SVC-1
172
+ * exists for (a replica SIGKILLed mid-run).
173
+ * - `running` and FRESH (within the grace window): genuinely in flight → leave pending (the owning process
174
+ * delivers its terminal notify, or the next sweep catches it once it goes terminal or stale).
175
+ * - MISSING (reaped / never persisted): ack-as-abandoned so the journal doesn't chase a ghost forever.
176
+ * `orphanGraceMs` MUST exceed the max expected workflow runtime (the run store has no cross-replica liveness
177
+ * signal, so age is the only orphan proxy). Returns a tally. A per-entry throw is isolated so one bad entry
178
+ * can't abort the sweep.
179
+ */
82
180
  async recover(opts = {}) {
83
- const orphanGraceMs = opts.orphanGraceMs ?? 24 * 60 * 60 * 1000;
181
+ const orphanGraceMs = opts.orphanGraceMs ?? 24 * 60 * 60 * 1000; // 24h default — well beyond any normal workflow
84
182
  const pending = await this.journal.listPending();
85
183
  let redelivered = 0;
86
184
  let stillRunning = 0;
@@ -89,19 +187,31 @@ export class WorkflowNotifyGate {
89
187
  try {
90
188
  const run = await this.runStore.get(entry.runId);
91
189
  if (!run) {
190
+ // No durable run — reaped or never persisted. Don't keep it pending forever.
92
191
  await this.journal.ack(entry.runId, this.now());
93
192
  abandoned++;
94
193
  continue;
95
194
  }
195
+ // principal fallback: the start-hook (JournalingWorkflowRunStore.put) records only runId+scope — scope IS
196
+ // the creating principal, so it's the sound owner attribution when entry.principal is absent (M6: a
197
+ // recovered notify must still carry an owner).
96
198
  const principal = entry.principal ?? entry.scope;
199
+ // #3 G (core 1.187): sourceTaskId used to be "genuinely unrecoverable" here (the durable WorkflowRun didn't
200
+ // carry it). core now threads it onto WorkflowRun.sourceTaskId (startWorkflow stores it / RunWorkflow passes the
201
+ // host taskId), so fall back to run's copy when the journal entry lost it — the recovered notify can finally
202
+ // attribute the originating host task.
97
203
  const sourceTaskId = entry.sourceTaskId ?? run.sourceTaskId;
204
+ // core 1.210: the durable WorkflowRun now records `originatingSessionId` (same story as
205
+ // sourceTaskId's 1.187) — thread it onto the RECOVERED payload so crash-recovery routes lookup-free,
206
+ // symmetric with the live notify (resolveCompletionRoute reads it first).
98
207
  const originatingSessionId = run.originatingSessionId;
99
208
  if (run.status === "running") {
100
209
  const startedAt = run.startedAt || entry.createdAt;
101
210
  if (this.now() - startedAt <= orphanGraceMs) {
102
211
  stillRunning++;
103
- continue;
212
+ continue; // fresh → genuinely in flight; the owner (or a later sweep) delivers terminal
104
213
  }
214
+ // Stale `running` ⇒ crash-orphan (nothing will ever flip it terminal). Finalize as abandoned/failed.
105
215
  await this.deliverOnce({
106
216
  runId: entry.runId,
107
217
  status: "failed",
@@ -114,6 +224,7 @@ export class WorkflowNotifyGate {
114
224
  abandoned++;
115
225
  continue;
116
226
  }
227
+ // Terminal but not acked ⇒ the crash dropped its notify. Re-derive the bounded summary + re-deliver.
117
228
  await this.deliverOnce({
118
229
  runId: entry.runId,
119
230
  status: run.status,
@@ -122,6 +233,7 @@ export class WorkflowNotifyGate {
122
233
  ...(principal ? { principal } : {}),
123
234
  ...(originatingSessionId ? { originatingSessionId } : {}),
124
235
  }, entry.scope);
236
+ // deliverOnce only acks on a clean delivery; count a redelivery whether or not it stuck (it logs on fail).
125
237
  const after = await this.journal.get(entry.runId);
126
238
  if (after?.acked)
127
239
  redelivered++;
@@ -133,6 +245,16 @@ export class WorkflowNotifyGate {
133
245
  return { scanned: pending.length, redelivered, stillRunning, abandoned };
134
246
  }
135
247
  }
248
+ /**
249
+ * Default zero-dependency, crash-safe {@link WorkflowNotifyJournalStore}. An append-only JSONL ledger replayed
250
+ * at boot (last-writer-wins per `runId`), the same durable posture as core's `FileWorkflowRunStore` — fsync'd
251
+ * appends, atomic single-line records. Single-instance / TOC-local: a cross-replica TiDB/PG port is a follow-on
252
+ * (the recovery sweep + gate are backend-agnostic).
253
+ *
254
+ * The ledger only ever grows by one line per `record`/`ack`; an acked entry's line is not deleted (the replay
255
+ * folds it), so retention is a future compaction concern — the backlog `listPending` walks is bounded by
256
+ * IN-FLIGHT + un-swept runs, not history.
257
+ */
136
258
  export class FileWorkflowNotifyJournalStore {
137
259
  fsyncEnabled;
138
260
  ledgerPath;
@@ -141,10 +263,15 @@ export class FileWorkflowNotifyJournalStore {
141
263
  constructor(root, fsyncEnabled = true) {
142
264
  this.fsyncEnabled = fsyncEnabled;
143
265
  const dir = join(root, "workflow-notify");
266
+ // 0o700 dir + 0o600 ledger: the journal persists tenant identity (scope/principal/sourceTaskId) — it must not
267
+ // be group/world-readable (parity with the durable-secret posture; a default-umask file would leak identity).
144
268
  mkdirSync(dir, { recursive: true, mode: 0o700 });
145
269
  this.ledgerPath = join(dir, "journal.jsonl");
146
270
  this.replay();
147
271
  }
272
+ /** Replay the ledger into the authoritative map (last-writer-wins by line order). Tolerates a torn final line
273
+ * (a crash mid-append) by dropping an unparsable trailing record — the same crash-safety FileWorkflowRunStore
274
+ * relies on (a partial append is simply not yet committed state). */
148
275
  replay() {
149
276
  if (!existsSync(this.ledgerPath))
150
277
  return;
@@ -157,15 +284,17 @@ export class FileWorkflowNotifyJournalStore {
157
284
  ev = JSON.parse(line);
158
285
  }
159
286
  catch {
160
- continue;
287
+ continue; // torn/partial line — skip (uncommitted)
161
288
  }
162
289
  if (ev && typeof ev.runId === "string")
163
290
  this.entries.set(ev.runId, ev);
164
291
  }
165
292
  }
293
+ /** Commit one entry: append the JSON line (fsync) THEN flip the in-memory map (crash-safe ordering — the
294
+ * durable record lands before the in-memory state the caller observes). */
166
295
  commit(entry) {
167
296
  if (this.fd === undefined)
168
- this.fd = openSync(this.ledgerPath, "a", 0o600);
297
+ this.fd = openSync(this.ledgerPath, "a", 0o600); // owner-only (identity data)
169
298
  writeSync(this.fd, `${JSON.stringify(entry)}\n`);
170
299
  if (this.fsyncEnabled)
171
300
  fsyncSync(this.fd);
@@ -173,6 +302,7 @@ export class FileWorkflowNotifyJournalStore {
173
302
  }
174
303
  async record(input) {
175
304
  const existing = this.entries.get(input.runId);
305
+ // Idempotent: never reset an existing entry (esp. an acked one → it would re-deliver forever).
176
306
  if (existing)
177
307
  return;
178
308
  this.commit({
@@ -187,7 +317,7 @@ export class FileWorkflowNotifyJournalStore {
187
317
  async ack(runId, ackedAt) {
188
318
  const existing = this.entries.get(runId);
189
319
  if (!existing || existing.acked)
190
- return;
320
+ return; // idempotent
191
321
  this.commit({ ...existing, acked: true, ackedAt });
192
322
  }
193
323
  async listPending() {
@@ -196,25 +326,32 @@ export class FileWorkflowNotifyJournalStore {
196
326
  async get(runId) {
197
327
  return this.entries.get(runId) ?? null;
198
328
  }
329
+ /** Release the append handle (best-effort) — called on shutdown. */
199
330
  close() {
200
331
  if (this.fd !== undefined) {
201
332
  try {
202
333
  closeSync(this.fd);
203
334
  }
204
335
  catch {
336
+ /* best-effort */
205
337
  }
206
338
  this.fd = undefined;
207
339
  }
208
340
  }
341
+ /** Test/inspection: total entries (acked + pending). */
209
342
  get size() {
210
343
  return this.entries.size;
211
344
  }
212
345
  }
346
+ /** In-process {@link WorkflowNotifyJournalStore} — tests / single-instance ephemeral. Does NOT survive a
347
+ * restart (so it provides NO crash-recovery on its own); use {@link FileWorkflowNotifyJournalStore} or a
348
+ * durable backend for the real at-least-once guarantee. Useful to unit-test the gate's live + idempotency
349
+ * paths without touching disk, and to simulate a crash by handing a FRESH store to a new gate. */
213
350
  export class InMemoryWorkflowNotifyJournalStore {
214
351
  entries = new Map();
215
352
  async record(input) {
216
353
  if (this.entries.has(input.runId))
217
- return;
354
+ return; // idempotent
218
355
  this.entries.set(input.runId, {
219
356
  runId: input.runId,
220
357
  scope: input.scope,
@@ -240,28 +377,58 @@ export class InMemoryWorkflowNotifyJournalStore {
240
377
  return this.entries.size;
241
378
  }
242
379
  }
380
+ /**
381
+ * A {@link WorkflowRunStore} DECORATOR that journals a run the instant core persists it at START. core's
382
+ * `startWorkflow` `put`s the run row (`status: "running"`) synchronously before the body runs, carrying both the
383
+ * `runId` and the `scope` — the one synchronous start-time hook the service gets WITHOUT a new core seam (core
384
+ * exposes no `onWorkflowStart`). Wrapping the run store here observes that `put`, journals the started run as
385
+ * pending-notify, then delegates to the wrapped store. Every other method is a pure pass-through (the run store
386
+ * stays core's source of truth for `/workflows`). This is the [[core-service-boundary]]-clean wiring: reuse the
387
+ * core store seam, observe writes through it, never fork a parallel run model.
388
+ *
389
+ * Journaling on `put` (not on notify) is what makes recovery cover a crash BEFORE terminal: the entry exists the
390
+ * moment the run starts, so the boot sweep finds it even if the process died mid-run.
391
+ */
243
392
  export class JournalingWorkflowRunStore {
244
393
  inner;
245
394
  gate;
246
395
  fleetBus;
247
- constructor(inner, gate, fleetBus) {
396
+ constructor(inner,
397
+ /** [1262] optional since the fleet decoupling: undefined ⇒ no start-time journal (ephemeral memory
398
+ * backend has nothing to recover), the FLEET half still publishes — the panel is replica-local UI
399
+ * state and must not be gated on the durable-notify machinery (the regression that emptied clay's
400
+ * workflow panel on memory-backend deployments). */
401
+ gate,
402
+ /** MF-Fleet (data contract): publish the workflow's fleet row on every put/update (the same write-observation
403
+ * point as the notify journal). Optional — undefined ⇒ no fleet publish. */
404
+ fleetBus) {
248
405
  this.inner = inner;
249
406
  this.gate = gate;
250
407
  this.fleetBus = fleetBus;
251
408
  }
409
+ /** Derive + publish the MF-Fleet workflow row from a WorkflowRun (doneCount/totalCount from agents, tokens from
410
+ * stats); a terminal workflow LEAVES the fleet (publish terminal then remove), a running one stays/updates. */
252
411
  publishFleet(id, run) {
253
412
  if (!this.fleetBus)
254
413
  return;
255
414
  const agents = run.agents ?? [];
256
415
  const done = agents.filter((a) => a.status === "completed" || a.status === "failed").length;
257
416
  const failed = agents.filter((a) => a.status === "failed").length;
417
+ // cli [1726] 二①:CC 规模告警的分母是 **started**(已启动),而 `totalCount`(= agents.length)是**计划总数**
418
+ // (含排队中)。判别口径走 core 导出的 `deriveAgentDisplayStatus` —— 一个 agent 已在 `run.agents` 里但
419
+ // `startedAt` 未置就是排队中。**不自己写 `startedAt !== undefined`**:那是 core 的显示契约,两端各写一遍
420
+ // 必然漂移(本仓刚在 coarse 门镜像上吃过同款),用它的函数则 core 一改、两端同时跟随。
258
421
  const started = agents.filter((a) => deriveAgentDisplayStatus(a, run.status) !== "queued").length;
259
422
  const terminal = run.status === "completed" || run.status === "failed";
260
423
  this.fleetBus.publishWorkflow({
261
424
  id,
425
+ // [WF2-A parity] redact the workflow label surfaces for parity with the run + subagent-child names (fleet-bus.ts):
426
+ // a tool-launched (LLM-authored) workflow's meta.name/description is task-controlled and could carry a secret shape.
262
427
  name: redactSecrets(run.name ?? "Dynamic workflow"),
263
428
  ...(run.description ? { description: redactSecrets(run.description) } : {}),
264
429
  scope: run.scope,
430
+ // codex-6 F2:sessionId 必须随行——streamFleet 对无 sessionId 的行按「同 principal 全会话可见」
431
+ // 兜底,漏发=A 会话的 workflow 名/进度/token 泄进 B 会话的 ?session= 过滤流。
265
432
  ...(run.originatingSessionId ? { sessionId: run.originatingSessionId } : {}),
266
433
  status: run.status,
267
434
  doneCount: done,
@@ -269,23 +436,30 @@ export class JournalingWorkflowRunStore {
269
436
  failedCount: failed,
270
437
  startedCount: started,
271
438
  tokens: (run.stats?.tokens ?? 0) + (run.stats?.nested?.tokens ?? 0),
439
+ // [1294]:跑动中也带时长(1.232 只在 endedAt 后带——clay 验收轮实锚面板恒显 0s)。终态用
440
+ // endedAt 定格,活跑用 now-startedAt(每次 put/update 观察点刷新,壳侧读帧即当前时长)。
272
441
  elapsedMs: (run.endedAt ?? Date.now()) - run.startedAt,
273
442
  });
274
443
  if (terminal)
275
- this.fleetBus.removeWorkflow(id);
444
+ this.fleetBus.removeWorkflow(id); // terminal workflow leaves the active fleet (the shell saw the final frame)
276
445
  }
277
446
  async put(id, run) {
447
+ // Journal FIRST (best-effort, swallowed inside onWorkflowStart) so a started run is always recoverable, THEN
448
+ // persist. Order matters: if persist throws, the journal entry still lets recovery re-check the (absent) run
449
+ // and ack-as-abandoned — no leak, no lost notify owed.
278
450
  await this.gate?.onWorkflowStart({
279
451
  runId: id,
280
452
  scope: run.scope,
453
+ // core threads sourceTaskId/principal to the NOTIFIER, not onto the run row, so they're unavailable here;
454
+ // the notifier path (deliverOnce) fills them in when it records/delivers. Recovery still has runId+scope.
281
455
  });
282
456
  await this.inner.put(id, run);
283
- this.publishFleet(id, run);
457
+ this.publishFleet(id, run); // MF-Fleet: the run appeared (running) / its row state changed
284
458
  }
285
459
  async update(id, scope, run, expect) {
286
460
  const ok = await this.inner.update(id, scope, run, expect);
287
461
  if (ok)
288
- this.publishFleet(id, run);
462
+ this.publishFleet(id, run); // MF-Fleet: only on a successful CAS (the persisted state is what the fleet shows)
289
463
  return ok;
290
464
  }
291
465
  get(id) {