@relayflows/sdk 2.0.8 → 2.0.10

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 (474) hide show
  1. package/dist/adapters/base.d.ts +46 -0
  2. package/dist/adapters/base.d.ts.map +1 -0
  3. package/dist/adapters/base.js +15 -0
  4. package/dist/adapters/base.js.map +1 -0
  5. package/dist/adapters/claude.d.ts +5 -0
  6. package/dist/adapters/claude.d.ts.map +1 -0
  7. package/dist/adapters/claude.js +44 -0
  8. package/dist/adapters/claude.js.map +1 -0
  9. package/dist/adapters/codex.d.ts +5 -0
  10. package/dist/adapters/codex.d.ts.map +1 -0
  11. package/dist/adapters/codex.js +45 -0
  12. package/dist/adapters/codex.js.map +1 -0
  13. package/dist/adapters/index.d.ts +14 -0
  14. package/dist/adapters/index.d.ts.map +1 -0
  15. package/dist/adapters/index.js +29 -0
  16. package/dist/adapters/index.js.map +1 -0
  17. package/dist/adapters/wrapper.d.ts +12 -0
  18. package/dist/adapters/wrapper.d.ts.map +1 -0
  19. package/dist/adapters/wrapper.js +31 -0
  20. package/dist/adapters/wrapper.js.map +1 -0
  21. package/dist/agent-relay-transport.d.ts +84 -0
  22. package/dist/agent-relay-transport.d.ts.map +1 -0
  23. package/dist/agent-relay-transport.js +134 -0
  24. package/dist/agent-relay-transport.js.map +1 -0
  25. package/dist/authored-budget.d.ts +13 -0
  26. package/dist/authored-budget.d.ts.map +1 -0
  27. package/dist/authored-budget.js +78 -0
  28. package/dist/authored-budget.js.map +1 -0
  29. package/dist/authored-flow-error.d.ts +1 -1
  30. package/dist/authored-flow-error.d.ts.map +1 -1
  31. package/dist/authored-flow-error.js.map +1 -1
  32. package/dist/authored-flow-executor.d.ts +13 -7
  33. package/dist/authored-flow-executor.d.ts.map +1 -1
  34. package/dist/authored-flow-executor.js +115 -194
  35. package/dist/authored-flow-executor.js.map +1 -1
  36. package/dist/authored-flow-loader.d.ts +10 -1
  37. package/dist/authored-flow-loader.d.ts.map +1 -1
  38. package/dist/authored-flow-loader.js +56 -3
  39. package/dist/authored-flow-loader.js.map +1 -1
  40. package/dist/authored-flow-operation.d.ts +9 -1
  41. package/dist/authored-flow-operation.d.ts.map +1 -1
  42. package/dist/authored-flow-operation.js +35 -4
  43. package/dist/authored-flow-operation.js.map +1 -1
  44. package/dist/authored-helper-effect.d.ts +12 -0
  45. package/dist/authored-helper-effect.d.ts.map +1 -0
  46. package/dist/authored-helper-effect.js +144 -0
  47. package/dist/authored-helper-effect.js.map +1 -0
  48. package/dist/authored-mcp.d.ts +17 -0
  49. package/dist/authored-mcp.d.ts.map +1 -0
  50. package/dist/authored-mcp.js +171 -0
  51. package/dist/authored-mcp.js.map +1 -0
  52. package/dist/authored-memory.d.ts +7 -0
  53. package/dist/authored-memory.d.ts.map +1 -0
  54. package/dist/authored-memory.js +60 -0
  55. package/dist/authored-memory.js.map +1 -0
  56. package/dist/authored-plugin-effect.d.ts +16 -0
  57. package/dist/authored-plugin-effect.d.ts.map +1 -0
  58. package/dist/authored-plugin-effect.js +163 -0
  59. package/dist/authored-plugin-effect.js.map +1 -0
  60. package/dist/authored-step-output.d.ts +23 -0
  61. package/dist/authored-step-output.d.ts.map +1 -0
  62. package/dist/authored-step-output.js +67 -0
  63. package/dist/authored-step-output.js.map +1 -0
  64. package/dist/authored-worker-step.d.ts +15 -0
  65. package/dist/authored-worker-step.d.ts.map +1 -0
  66. package/dist/authored-worker-step.js +136 -0
  67. package/dist/authored-worker-step.js.map +1 -0
  68. package/dist/budget-preflight.d.ts +5 -0
  69. package/dist/budget-preflight.d.ts.map +1 -0
  70. package/dist/budget-preflight.js +33 -0
  71. package/dist/budget-preflight.js.map +1 -0
  72. package/dist/budget.d.ts +14 -0
  73. package/dist/budget.d.ts.map +1 -0
  74. package/dist/budget.js +52 -0
  75. package/dist/budget.js.map +1 -0
  76. package/dist/bundle-transport.d.ts +18 -0
  77. package/dist/bundle-transport.d.ts.map +1 -0
  78. package/dist/bundle-transport.js +111 -0
  79. package/dist/bundle-transport.js.map +1 -0
  80. package/dist/bundle-typescript.d.ts +8 -0
  81. package/dist/bundle-typescript.d.ts.map +1 -0
  82. package/dist/bundle-typescript.js +108 -0
  83. package/dist/bundle-typescript.js.map +1 -0
  84. package/dist/bundle.d.ts +25 -0
  85. package/dist/bundle.d.ts.map +1 -0
  86. package/dist/bundle.js +199 -0
  87. package/dist/bundle.js.map +1 -0
  88. package/dist/child-stop.d.ts +59 -0
  89. package/dist/child-stop.d.ts.map +1 -0
  90. package/dist/child-stop.js +94 -0
  91. package/dist/child-stop.js.map +1 -0
  92. package/dist/cli/add.d.ts +6 -0
  93. package/dist/cli/add.d.ts.map +1 -0
  94. package/dist/cli/add.js +47 -0
  95. package/dist/cli/add.js.map +1 -0
  96. package/dist/cli/build.d.ts +13 -0
  97. package/dist/cli/build.d.ts.map +1 -0
  98. package/dist/cli/build.js +224 -0
  99. package/dist/cli/build.js.map +1 -0
  100. package/dist/cli/bundle-preflight.d.ts +5 -0
  101. package/dist/cli/bundle-preflight.d.ts.map +1 -0
  102. package/dist/cli/bundle-preflight.js +28 -0
  103. package/dist/cli/bundle-preflight.js.map +1 -0
  104. package/dist/cli/check-helper-body.d.ts +4 -0
  105. package/dist/cli/check-helper-body.d.ts.map +1 -0
  106. package/dist/cli/check-helper-body.js +15 -0
  107. package/dist/cli/check-helper-body.js.map +1 -0
  108. package/dist/cli/check-triggers.d.ts +14 -0
  109. package/dist/cli/check-triggers.d.ts.map +1 -0
  110. package/dist/cli/check-triggers.js +37 -0
  111. package/dist/cli/check-triggers.js.map +1 -0
  112. package/dist/cli/check-typescript.d.ts +20 -0
  113. package/dist/cli/check-typescript.d.ts.map +1 -0
  114. package/dist/cli/check-typescript.js +54 -0
  115. package/dist/cli/check-typescript.js.map +1 -0
  116. package/dist/cli/check.d.ts +36 -3
  117. package/dist/cli/check.d.ts.map +1 -1
  118. package/dist/cli/check.js +122 -11
  119. package/dist/cli/check.js.map +1 -1
  120. package/dist/cli/cloud-run.d.ts +8 -0
  121. package/dist/cli/cloud-run.d.ts.map +1 -0
  122. package/dist/cli/cloud-run.js +50 -0
  123. package/dist/cli/cloud-run.js.map +1 -0
  124. package/dist/cli/deploy.d.ts +9 -0
  125. package/dist/cli/deploy.d.ts.map +1 -0
  126. package/dist/cli/deploy.js +58 -0
  127. package/dist/cli/deploy.js.map +1 -0
  128. package/dist/cli/deterministic-failure.d.ts +5 -0
  129. package/dist/cli/deterministic-failure.d.ts.map +1 -0
  130. package/dist/cli/deterministic-failure.js +66 -0
  131. package/dist/cli/deterministic-failure.js.map +1 -0
  132. package/dist/cli/direct-run.d.ts.map +1 -1
  133. package/dist/cli/direct-run.js +83 -7
  134. package/dist/cli/direct-run.js.map +1 -1
  135. package/dist/cli/hn-monitor.d.ts.map +1 -1
  136. package/dist/cli/hn-monitor.js +2 -1
  137. package/dist/cli/hn-monitor.js.map +1 -1
  138. package/dist/cli/replay.d.ts +12 -0
  139. package/dist/cli/replay.d.ts.map +1 -0
  140. package/dist/cli/replay.js +82 -0
  141. package/dist/cli/replay.js.map +1 -0
  142. package/dist/cli/reuse.d.ts +8 -0
  143. package/dist/cli/reuse.d.ts.map +1 -0
  144. package/dist/cli/reuse.js +25 -0
  145. package/dist/cli/reuse.js.map +1 -0
  146. package/dist/cli/run-digest.d.ts +4 -0
  147. package/dist/cli/run-digest.d.ts.map +1 -0
  148. package/dist/cli/run-digest.js +24 -0
  149. package/dist/cli/run-digest.js.map +1 -0
  150. package/dist/cli/run.d.ts +16 -5
  151. package/dist/cli/run.d.ts.map +1 -1
  152. package/dist/cli/run.js +99 -17
  153. package/dist/cli/run.js.map +1 -1
  154. package/dist/cli/serve-webhook.d.ts +40 -0
  155. package/dist/cli/serve-webhook.d.ts.map +1 -0
  156. package/dist/cli/serve-webhook.js +233 -0
  157. package/dist/cli/serve-webhook.js.map +1 -0
  158. package/dist/cli/tick-runner.d.ts.map +1 -1
  159. package/dist/cli/tick-runner.js +2 -1
  160. package/dist/cli/tick-runner.js.map +1 -1
  161. package/dist/cli-adapter.d.ts +8 -14
  162. package/dist/cli-adapter.d.ts.map +1 -1
  163. package/dist/cli-adapter.js +19 -64
  164. package/dist/cli-adapter.js.map +1 -1
  165. package/dist/cli-watch.d.ts +13 -0
  166. package/dist/cli-watch.d.ts.map +1 -0
  167. package/dist/cli-watch.js +185 -0
  168. package/dist/cli-watch.js.map +1 -0
  169. package/dist/cli.d.ts +4 -0
  170. package/dist/cli.d.ts.map +1 -1
  171. package/dist/cli.js +387 -14
  172. package/dist/cli.js.map +1 -1
  173. package/dist/cloud-http.d.ts +22 -0
  174. package/dist/cloud-http.d.ts.map +1 -0
  175. package/dist/cloud-http.js +84 -0
  176. package/dist/cloud-http.js.map +1 -0
  177. package/dist/cloud-run.d.ts +38 -0
  178. package/dist/cloud-run.d.ts.map +1 -0
  179. package/dist/cloud-run.js +112 -0
  180. package/dist/cloud-run.js.map +1 -0
  181. package/dist/compile.d.ts +21 -3
  182. package/dist/compile.d.ts.map +1 -1
  183. package/dist/compile.js +97 -23
  184. package/dist/compile.js.map +1 -1
  185. package/dist/create-flow.d.ts +17 -0
  186. package/dist/create-flow.d.ts.map +1 -0
  187. package/dist/create-flow.js +72 -0
  188. package/dist/create-flow.js.map +1 -0
  189. package/dist/daemon-connection.d.ts +14 -0
  190. package/dist/daemon-connection.d.ts.map +1 -1
  191. package/dist/daemon-connection.js +33 -1
  192. package/dist/daemon-connection.js.map +1 -1
  193. package/dist/demo-hn-monitor.js +2 -1
  194. package/dist/demo-hn-monitor.js.map +1 -1
  195. package/dist/effect-channel.d.ts +30 -0
  196. package/dist/effect-channel.d.ts.map +1 -0
  197. package/dist/effect-channel.js +71 -0
  198. package/dist/effect-channel.js.map +1 -0
  199. package/dist/failure-kinds.d.ts +14 -3
  200. package/dist/failure-kinds.d.ts.map +1 -1
  201. package/dist/failure-kinds.js +27 -0
  202. package/dist/failure-kinds.js.map +1 -1
  203. package/dist/gate-contract.d.ts.map +1 -1
  204. package/dist/gate-contract.js +9 -0
  205. package/dist/gate-contract.js.map +1 -1
  206. package/dist/helper-preflight.d.ts +18 -0
  207. package/dist/helper-preflight.d.ts.map +1 -0
  208. package/dist/helper-preflight.js +32 -0
  209. package/dist/helper-preflight.js.map +1 -0
  210. package/dist/helper-storage.d.ts +5 -0
  211. package/dist/helper-storage.d.ts.map +1 -0
  212. package/dist/helper-storage.js +31 -0
  213. package/dist/helper-storage.js.map +1 -0
  214. package/dist/helper-writeback.d.ts +12 -0
  215. package/dist/helper-writeback.d.ts.map +1 -0
  216. package/dist/helper-writeback.js +95 -0
  217. package/dist/helper-writeback.js.map +1 -0
  218. package/dist/index.d.ts +10 -2
  219. package/dist/index.d.ts.map +1 -1
  220. package/dist/index.js +7 -1
  221. package/dist/index.js.map +1 -1
  222. package/dist/input-binding.d.ts +4 -0
  223. package/dist/input-binding.d.ts.map +1 -0
  224. package/dist/input-binding.js +78 -0
  225. package/dist/input-binding.js.map +1 -0
  226. package/dist/journal-client.d.ts +12 -4
  227. package/dist/journal-client.d.ts.map +1 -1
  228. package/dist/journal-client.js +17 -6
  229. package/dist/journal-client.js.map +1 -1
  230. package/dist/journal-offset.d.ts +3 -0
  231. package/dist/journal-offset.d.ts.map +1 -0
  232. package/dist/journal-offset.js +69 -0
  233. package/dist/journal-offset.js.map +1 -0
  234. package/dist/journal-reader.d.ts +30 -0
  235. package/dist/journal-reader.d.ts.map +1 -0
  236. package/dist/journal-reader.js +156 -0
  237. package/dist/journal-reader.js.map +1 -0
  238. package/dist/json-schema.d.ts +2 -0
  239. package/dist/json-schema.d.ts.map +1 -1
  240. package/dist/json-schema.js +38 -22
  241. package/dist/json-schema.js.map +1 -1
  242. package/dist/llm-worker.d.ts +16 -0
  243. package/dist/llm-worker.d.ts.map +1 -0
  244. package/dist/llm-worker.js +79 -0
  245. package/dist/llm-worker.js.map +1 -0
  246. package/dist/local-agent.d.ts +8 -0
  247. package/dist/local-agent.d.ts.map +1 -0
  248. package/dist/local-agent.js +25 -0
  249. package/dist/local-agent.js.map +1 -0
  250. package/dist/mcp-client.d.ts +15 -0
  251. package/dist/mcp-client.d.ts.map +1 -0
  252. package/dist/mcp-client.js +104 -0
  253. package/dist/mcp-client.js.map +1 -0
  254. package/dist/mcp-config.d.ts +4 -0
  255. package/dist/mcp-config.d.ts.map +1 -0
  256. package/dist/mcp-config.js +61 -0
  257. package/dist/mcp-config.js.map +1 -0
  258. package/dist/mcp-stdio.d.ts +24 -0
  259. package/dist/mcp-stdio.d.ts.map +1 -0
  260. package/dist/mcp-stdio.js +89 -0
  261. package/dist/mcp-stdio.js.map +1 -0
  262. package/dist/model-pricing.d.ts +22 -0
  263. package/dist/model-pricing.d.ts.map +1 -0
  264. package/dist/model-pricing.js +30 -0
  265. package/dist/model-pricing.js.map +1 -0
  266. package/dist/mount-registry.d.ts +9 -0
  267. package/dist/mount-registry.d.ts.map +1 -0
  268. package/dist/mount-registry.js +47 -0
  269. package/dist/mount-registry.js.map +1 -0
  270. package/dist/named-gate-lowering.d.ts +9 -0
  271. package/dist/named-gate-lowering.d.ts.map +1 -0
  272. package/dist/named-gate-lowering.js +152 -0
  273. package/dist/named-gate-lowering.js.map +1 -0
  274. package/dist/named-gates.d.ts +10 -0
  275. package/dist/named-gates.d.ts.map +1 -0
  276. package/dist/named-gates.js +69 -0
  277. package/dist/named-gates.js.map +1 -0
  278. package/dist/observer-link.d.ts +129 -0
  279. package/dist/observer-link.d.ts.map +1 -0
  280. package/dist/observer-link.js +274 -0
  281. package/dist/observer-link.js.map +1 -0
  282. package/dist/plugin-loader.d.ts +13 -0
  283. package/dist/plugin-loader.d.ts.map +1 -0
  284. package/dist/plugin-loader.js +110 -0
  285. package/dist/plugin-loader.js.map +1 -0
  286. package/dist/plugin-manifest.d.ts +27 -0
  287. package/dist/plugin-manifest.d.ts.map +1 -0
  288. package/dist/plugin-manifest.js +89 -0
  289. package/dist/plugin-manifest.js.map +1 -0
  290. package/dist/preflight.d.ts +26 -2
  291. package/dist/preflight.d.ts.map +1 -1
  292. package/dist/preflight.js +175 -1
  293. package/dist/preflight.js.map +1 -1
  294. package/dist/progress.d.ts +14 -0
  295. package/dist/progress.d.ts.map +1 -0
  296. package/dist/progress.js +39 -0
  297. package/dist/progress.js.map +1 -0
  298. package/dist/protocol.d.ts +11 -0
  299. package/dist/protocol.d.ts.map +1 -1
  300. package/dist/pty-sidechannel.d.ts +14 -0
  301. package/dist/pty-sidechannel.d.ts.map +1 -0
  302. package/dist/pty-sidechannel.js +103 -0
  303. package/dist/pty-sidechannel.js.map +1 -0
  304. package/dist/scope-compiler.d.ts +52 -0
  305. package/dist/scope-compiler.d.ts.map +1 -0
  306. package/dist/scope-compiler.js +62 -0
  307. package/dist/scope-compiler.js.map +1 -0
  308. package/dist/slack-preflight.d.ts +6 -0
  309. package/dist/slack-preflight.d.ts.map +1 -0
  310. package/dist/slack-preflight.js +28 -0
  311. package/dist/slack-preflight.js.map +1 -0
  312. package/dist/slack-writeback.d.ts +40 -0
  313. package/dist/slack-writeback.d.ts.map +1 -0
  314. package/dist/slack-writeback.js +60 -0
  315. package/dist/slack-writeback.js.map +1 -0
  316. package/dist/spec.d.ts +134 -4
  317. package/dist/spec.d.ts.map +1 -1
  318. package/dist/spec.js.map +1 -1
  319. package/dist/step-dependencies.d.ts.map +1 -1
  320. package/dist/step-dependencies.js +2 -1
  321. package/dist/step-dependencies.js.map +1 -1
  322. package/dist/step-fields.d.ts +4 -4
  323. package/dist/step-fields.d.ts.map +1 -1
  324. package/dist/step-fields.js +5 -2
  325. package/dist/step-fields.js.map +1 -1
  326. package/dist/trigger-executor.d.ts +7 -0
  327. package/dist/trigger-executor.d.ts.map +1 -0
  328. package/dist/trigger-executor.js +35 -0
  329. package/dist/trigger-executor.js.map +1 -0
  330. package/dist/validate.d.ts.map +1 -1
  331. package/dist/validate.js +53 -6
  332. package/dist/validate.js.map +1 -1
  333. package/dist/webhook-rate-limit.d.ts +29 -0
  334. package/dist/webhook-rate-limit.d.ts.map +1 -0
  335. package/dist/webhook-rate-limit.js +38 -0
  336. package/dist/webhook-rate-limit.js.map +1 -0
  337. package/dist/webhook-signature.d.ts +22 -0
  338. package/dist/webhook-signature.d.ts.map +1 -0
  339. package/dist/webhook-signature.js +53 -0
  340. package/dist/webhook-signature.js.map +1 -0
  341. package/dist/worker-cli.d.ts +13 -1
  342. package/dist/worker-cli.d.ts.map +1 -1
  343. package/dist/worker-cli.js +133 -12
  344. package/dist/worker-cli.js.map +1 -1
  345. package/dist/worker-input.d.ts +4 -0
  346. package/dist/worker-input.d.ts.map +1 -0
  347. package/dist/worker-input.js +14 -0
  348. package/dist/worker-input.js.map +1 -0
  349. package/dist/worker-lease.d.ts +5 -0
  350. package/dist/worker-lease.d.ts.map +1 -0
  351. package/dist/worker-lease.js +80 -0
  352. package/dist/worker-lease.js.map +1 -0
  353. package/dist/worker-spend.d.ts +19 -0
  354. package/dist/worker-spend.d.ts.map +1 -0
  355. package/dist/worker-spend.js +22 -0
  356. package/dist/worker-spend.js.map +1 -0
  357. package/dist/worker-usage.d.ts +7 -0
  358. package/dist/worker-usage.d.ts.map +1 -0
  359. package/dist/worker-usage.js +54 -0
  360. package/dist/worker-usage.js.map +1 -0
  361. package/dist/worker.d.ts +2 -0
  362. package/dist/worker.d.ts.map +1 -1
  363. package/dist/worker.js +22 -8
  364. package/dist/worker.js.map +1 -1
  365. package/dist/wrapper-session.d.ts +1 -1
  366. package/dist/wrapper-session.d.ts.map +1 -1
  367. package/dist/wrapper-session.js +56 -19
  368. package/dist/wrapper-session.js.map +1 -1
  369. package/dist/yaml-helper-effect.d.ts +8 -0
  370. package/dist/yaml-helper-effect.d.ts.map +1 -0
  371. package/dist/yaml-helper-effect.js +79 -0
  372. package/dist/yaml-helper-effect.js.map +1 -0
  373. package/dist/yaml-helpers.d.ts +18 -0
  374. package/dist/yaml-helpers.d.ts.map +1 -0
  375. package/dist/yaml-helpers.js +116 -0
  376. package/dist/yaml-helpers.js.map +1 -0
  377. package/package.json +19 -2
  378. package/src/adapters/base.ts +53 -0
  379. package/src/adapters/claude.ts +55 -0
  380. package/src/adapters/codex.ts +56 -0
  381. package/src/adapters/index.ts +36 -0
  382. package/src/adapters/wrapper.ts +42 -0
  383. package/src/agent-relay-transport.ts +187 -0
  384. package/src/authored-budget.ts +69 -0
  385. package/src/authored-flow-error.ts +10 -0
  386. package/src/authored-flow-executor.ts +170 -293
  387. package/src/authored-flow-loader.ts +60 -3
  388. package/src/authored-flow-operation.ts +38 -5
  389. package/src/authored-helper-effect.ts +143 -0
  390. package/src/authored-mcp.ts +166 -0
  391. package/src/authored-memory.ts +55 -0
  392. package/src/authored-plugin-effect.ts +152 -0
  393. package/src/authored-step-output.ts +107 -0
  394. package/src/authored-worker-step.ts +181 -0
  395. package/src/budget-preflight.ts +31 -0
  396. package/src/budget.ts +49 -0
  397. package/src/bundle-transport.ts +79 -0
  398. package/src/bundle-typescript.ts +98 -0
  399. package/src/bundle.ts +182 -0
  400. package/src/child-stop.ts +138 -0
  401. package/src/cli/add.ts +45 -0
  402. package/src/cli/build.ts +214 -0
  403. package/src/cli/bundle-preflight.ts +28 -0
  404. package/src/cli/check-helper-body.ts +14 -0
  405. package/src/cli/check-triggers.ts +41 -0
  406. package/src/cli/check-typescript.ts +63 -0
  407. package/src/cli/check.ts +132 -14
  408. package/src/cli/cloud-run.ts +47 -0
  409. package/src/cli/deploy.ts +52 -0
  410. package/src/cli/deterministic-failure.ts +69 -0
  411. package/src/cli/direct-run.ts +79 -7
  412. package/src/cli/hn-monitor.ts +2 -1
  413. package/src/cli/replay.ts +81 -0
  414. package/src/cli/reuse.ts +23 -0
  415. package/src/cli/run-digest.ts +24 -0
  416. package/src/cli/run.ts +104 -21
  417. package/src/cli/serve-webhook.ts +246 -0
  418. package/src/cli/tick-runner.ts +2 -1
  419. package/src/cli-adapter.ts +31 -74
  420. package/src/cli-watch.ts +174 -0
  421. package/src/cli.ts +396 -17
  422. package/src/cloud-http.ts +100 -0
  423. package/src/cloud-run.ts +137 -0
  424. package/src/compile.ts +102 -23
  425. package/src/create-flow.ts +82 -0
  426. package/src/daemon-connection.ts +32 -1
  427. package/src/demo-hn-monitor.ts +2 -1
  428. package/src/effect-channel.ts +97 -0
  429. package/src/failure-kinds.ts +38 -0
  430. package/src/gate-contract.ts +7 -0
  431. package/src/helper-preflight.ts +34 -0
  432. package/src/helper-storage.ts +23 -0
  433. package/src/helper-writeback.ts +83 -0
  434. package/src/index.ts +26 -0
  435. package/src/input-binding.ts +76 -0
  436. package/src/journal-client.ts +20 -7
  437. package/src/journal-offset.ts +60 -0
  438. package/src/journal-reader.ts +165 -0
  439. package/src/json-schema.ts +34 -18
  440. package/src/llm-worker.ts +82 -0
  441. package/src/local-agent.ts +30 -0
  442. package/src/mcp-client.ts +97 -0
  443. package/src/mcp-config.ts +42 -0
  444. package/src/mcp-stdio.ts +84 -0
  445. package/src/model-pricing.ts +32 -0
  446. package/src/mount-registry.ts +44 -0
  447. package/src/named-gate-lowering.ts +147 -0
  448. package/src/named-gates.ts +76 -0
  449. package/src/observer-link.ts +368 -0
  450. package/src/plugin-loader.ts +88 -0
  451. package/src/plugin-manifest.ts +76 -0
  452. package/src/preflight.ts +178 -4
  453. package/src/progress.ts +51 -0
  454. package/src/protocol.ts +12 -0
  455. package/src/pty-sidechannel.ts +92 -0
  456. package/src/scope-compiler.ts +105 -0
  457. package/src/slack-preflight.ts +25 -0
  458. package/src/slack-writeback.ts +63 -0
  459. package/src/spec.ts +112 -4
  460. package/src/step-dependencies.ts +3 -1
  461. package/src/step-fields.ts +5 -2
  462. package/src/trigger-executor.ts +34 -0
  463. package/src/validate.ts +47 -6
  464. package/src/webhook-rate-limit.ts +69 -0
  465. package/src/webhook-signature.ts +74 -0
  466. package/src/worker-cli.ts +156 -11
  467. package/src/worker-input.ts +15 -0
  468. package/src/worker-lease.ts +85 -0
  469. package/src/worker-spend.ts +23 -0
  470. package/src/worker-usage.ts +48 -0
  471. package/src/worker.ts +27 -9
  472. package/src/wrapper-session.ts +50 -15
  473. package/src/yaml-helper-effect.ts +78 -0
  474. package/src/yaml-helpers.ts +131 -0
@@ -0,0 +1,52 @@
1
+ import { join } from 'node:path';
2
+ import type { CliIo } from '../cli.js';
3
+ import { BundleFailure, bucketDirectory, copyBundle, exists, parseDigestReference,
4
+ verifyDigest, writableBucket } from '../bundle-transport.js';
5
+ import { checkRunnableBundle } from './bundle-preflight.js';
6
+
7
+ export interface DeployArgs { command: 'deploy'; value: string; to: string }
8
+ export function parseDeployArgs(args: readonly string[]): DeployArgs | undefined {
9
+ let value: string | undefined;
10
+ let to: string | undefined;
11
+ for (let i = 0; i < args.length; i++) {
12
+ const arg = args[i]!;
13
+ if (arg === '--to') {
14
+ if (to !== undefined || !args[i + 1] || args[i + 1]!.startsWith('-')) return undefined;
15
+ to = args[++i];
16
+ } else if (arg.startsWith('-') || value !== undefined) return undefined;
17
+ else value = arg;
18
+ }
19
+ return value && to && parseDigestReference(value) ? { command: 'deploy', value, to } : undefined;
20
+ }
21
+ export async function runDeploy(args: DeployArgs, io: CliIo): Promise<0 | 1 | 2> {
22
+ let started = false;
23
+ try {
24
+ const ref = parseDigestReference(args.value);
25
+ if (!ref) throw new BundleFailure('bundle_missing_locally', 'Expected <flow>@sha256:<64 lowercase hex characters>.');
26
+ const source = join(process.cwd(), 'dist', 'flows', args.value);
27
+ if (!await exists(source)) throw new BundleFailure('bundle_missing_locally', `Build ${args.value} locally first.`);
28
+ await verifyDigest(source, ref.digest);
29
+ const checked = await checkRunnableBundle(source, ref.name);
30
+ if (!checked.report.ok) {
31
+ for (const diagnostic of checked.report.diagnostics) io.stderr(`${diagnostic.severity.toUpperCase()} [${diagnostic.kind}] ${diagnostic.message}`);
32
+ return 2;
33
+ }
34
+ const target = bucketDirectory(args.to, ref);
35
+ if (await exists(target)) {
36
+ await verifyDigest(target, ref.digest);
37
+ io.stderr(`deploy_noop: ${args.value}`);
38
+ io.stdout(`SKIPPED (already-present) ${args.value} ${args.to}`);
39
+ return 0;
40
+ }
41
+ await writableBucket(target);
42
+ started = true;
43
+ const copied = await copyBundle(source, target, ref.digest);
44
+ if (!copied) io.stderr(`deploy_noop: ${args.value}`);
45
+ io.stdout(`${copied ? 'DEPLOYED' : 'SKIPPED (already-present)'} ${args.value} ${args.to}`);
46
+ return 0;
47
+ } catch (error) {
48
+ const kind = started ? 'deploy_partial' : error instanceof BundleFailure ? error.kind : 'bucket_unreachable';
49
+ io.stderr(`${started ? 'FAILED' : 'REFUSED'} [${kind}] ${error instanceof Error ? error.message : String(error)}`);
50
+ return started ? 1 : 2;
51
+ }
52
+ }
@@ -0,0 +1,69 @@
1
+ import type { StepFailedDetails } from '../failure-kinds.js';
2
+ import type { JournalClient } from '../journal-client.js';
3
+
4
+ const STDERR_TAIL_BYTES = 1_024;
5
+
6
+ /** Read completion evidence through the existing protocol, including later pages. */
7
+ export async function deterministicFailureDetails(
8
+ client: JournalClient,
9
+ runId: string,
10
+ ): Promise<StepFailedDetails | undefined> {
11
+ const snapshot = await client.runGet(runId);
12
+ if (!Object.values(snapshot.steps).some(step => step.type === 'deterministic')) return undefined;
13
+ let fromSeq = 1;
14
+ const failures = new Map<string, StepFailedDetails>();
15
+ while (true) {
16
+ const { entries } = await client.journalRead(runId, fromSeq, 100);
17
+ if (entries.length === 0) break;
18
+ for (const raw of entries) {
19
+ const entry = record(raw);
20
+ const seq = entry?.['seq'];
21
+ if (typeof seq !== 'number' || !Number.isSafeInteger(seq) || seq < fromSeq) {
22
+ throw new Error('invalid journal sequence in command failure inspection');
23
+ }
24
+ fromSeq = seq + 1;
25
+ const stepId = entry?.['step_id'];
26
+ if (entry?.['entry_type'] !== 'step.completed' || typeof stepId !== 'string'
27
+ || snapshot.steps[stepId]?.type !== 'deterministic') continue;
28
+ // A later completion supersedes an earlier failed attempt.
29
+ failures.delete(stepId);
30
+ const payload = record(entry['payload']);
31
+ // Post-#292 the kernel preserves the captured `{exit_code, stdout_tail,
32
+ // stderr_tail}` in `output` on failed completions; prefer it. Fall back
33
+ // to `trajectory_tail` for journal records emitted before that fix.
34
+ const output = record(payload?.['output']) ?? record(payload?.['trajectory_tail']);
35
+ const exitCode = output?.['exit_code'];
36
+ if (payload?.['disposition'] !== 'step_done' || payload['completionReason'] === 'success'
37
+ || typeof exitCode !== 'number' || !Number.isSafeInteger(exitCode) || exitCode === 0) continue;
38
+ failures.set(stepId, {
39
+ stepId,
40
+ exitCode,
41
+ stderrTail: stderrTail(output?.['stderr_tail']),
42
+ hint: `flows replay ${shellQuote(runId)} --at ${shellQuote(stepId)}`,
43
+ });
44
+ }
45
+ }
46
+ return [...failures.values()].at(-1);
47
+ }
48
+
49
+ function record(value: unknown): Record<string, unknown> | undefined {
50
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
51
+ ? value as Record<string, unknown> : undefined;
52
+ }
53
+
54
+ function stderrTail(value: unknown): string {
55
+ if (typeof value !== 'string') return '';
56
+ const bytes = Buffer.from(value, 'utf8');
57
+ let start = Math.max(0, bytes.length - STDERR_TAIL_BYTES);
58
+ // Drop a partial leading code point, avoiding replacement-byte expansion.
59
+ while (start < bytes.length && (bytes[start]! & 0xc0) === 0x80) start += 1;
60
+ // Preserve tabs/newlines; replace binary controls (including ESC and CR),
61
+ // C1 controls and Unicode formatting controls without growing the excerpt.
62
+ return bytes.subarray(start).toString('utf8')
63
+ .replace(/[\p{Cc}\p{Cf}]/gu, character => character === '\n' || character === '\t' ? character : '?');
64
+ }
65
+
66
+ function shellQuote(value: string): string {
67
+ return /^[A-Za-z0-9_-]+$/.test(value) && !value.startsWith('-')
68
+ ? value : `'${value.replace(/'/g, "'\\''")}'`;
69
+ }
@@ -1,11 +1,16 @@
1
+ import { McpStepError } from '../authored-mcp.js';
2
+ import { McpPreflightError } from './check-typescript.js';
3
+ import { attachLocalAgent } from '../local-agent.js';
4
+ import { LlmWorker } from '../llm-worker.js';
1
5
  import {
2
6
  AuthoredFlowExecutionError,
3
7
  executeAuthoredFlow,
4
8
  } from '../authored-flow-executor.js';
5
- import { AuthoredFlowLoadError, loadAuthoredFlow } from '../authored-flow-loader.js';
9
+ import { AuthoredFlowLoadError } from '../authored-flow-loader.js';
6
10
  import { DirectInputError, parseDirectInput } from '../direct-input.js';
7
11
  import { JournalClient } from '../journal-client.js';
8
12
  import { inputFailureReport } from './check.js';
13
+ import { checkAuthoredTriggers } from './check-triggers.js';
9
14
  import {
10
15
  connect,
11
16
  emptyReport,
@@ -37,17 +42,44 @@ export async function runDirectFlow(
37
42
  };
38
43
  }
39
44
 
45
+ // Declared triggers are knowable before any daemon or step is started.
46
+ // Importing the authored module is unavoidable here — trigger sources
47
+ // are only observable after `flow(...).on(webhook(...))` has run — but
48
+ // the authored body is not called, so a side-effect-in-body flow still
49
+ // has its body deferred until after daemon-attach below.
50
+ const checked = await checkAuthoredTriggers(path);
51
+ if (!checked.report.ok || checked.loaded === undefined) {
52
+ return { exitCode: 2, report: fromCheckReport('run', checked.report) };
53
+ }
40
54
  const socketPath = socketFor(dataDir);
41
55
  const base: RunReport = { ...emptyReport('run'), path };
42
56
  const client = new JournalClient(socketPath);
43
57
  const connected = await connect(client, 'run', dataDir, base, options);
44
58
  if (connected !== undefined) return connected;
45
59
 
60
+ let localAgent: Awaited<ReturnType<typeof attachLocalAgent>> | undefined;
61
+ let localLlm: LlmWorker | undefined;
62
+ let llmClient: JournalClient | undefined;
63
+ let llmFailure: unknown;
46
64
  try {
47
- const { handle, getDefinition } = await loadAuthoredFlow(path);
65
+ const { handle, getDefinition } = checked.loaded;
66
+ if (options.localAgent) {
67
+ localAgent = await attachLocalAgent(client, dataDir, options.onPtyReady);
68
+ // A session owns one worker registration. Keep the workspace-free LLM
69
+ // worker on its own connection so it cannot replace the agent worker.
70
+ llmClient = new JournalClient(socketPath);
71
+ await llmClient.connect();
72
+ await llmClient.hello('flows-local-llm');
73
+ localLlm = new LlmWorker(llmClient, `${localAgent.stream}-llm`);
74
+ localLlm.on('error', error => { llmFailure = error; client.close(); });
75
+ await localLlm.attach();
76
+ }
48
77
  const result = await executeAuthoredFlow(handle, client, input, {
49
78
  getDefinition,
79
+ dataDir,
50
80
  flowPath: path,
81
+ onProgress: options.onProgress,
82
+ localAgentStream: localAgent?.stream,
51
83
  ...(options.signal !== undefined ? { signal: options.signal } : {}),
52
84
  ...(options.onWait !== undefined ? { onWait: options.onWait } : {}),
53
85
  });
@@ -57,6 +89,19 @@ export async function runDirectFlow(
57
89
  `authored flow "${result.name}" completed without a journal step`,
58
90
  ));
59
91
  }
92
+ if (result.completionReason === 'needs_human') {
93
+ return {
94
+ exitCode: 3,
95
+ report: {
96
+ ...base, ok: false, runId: terminal.runId, socketPath, status: 'parked',
97
+ completedSteps: result.journalSteps.length,
98
+ diagnostics: [...base.diagnostics, {
99
+ severity: 'parked', kind: 'run_parked',
100
+ message: `Flow "${result.name}" needs_human; see the journal for accumulated blockers.`,
101
+ }],
102
+ },
103
+ };
104
+ }
60
105
  return {
61
106
  exitCode: 0,
62
107
  report: {
@@ -69,7 +114,21 @@ export async function runDirectFlow(
69
114
  completedSteps: result.journalSteps.length,
70
115
  },
71
116
  };
72
- } catch (error) {
117
+ } catch (caught) {
118
+ if (caught instanceof McpPreflightError) return {
119
+ exitCode: 2, report: fromCheckReport('run', caught.report),
120
+ };
121
+ if (caught instanceof McpStepError) return {
122
+ exitCode: 1,
123
+ report: { ...base, ok: false, runId: caught.runId, socketPath,
124
+ status: 'failed', completionReason: 'step_failed',
125
+ diagnostics: [...base.diagnostics, { severity: 'failure', kind: 'step_failed', message: caught.message }],
126
+ },
127
+ };
128
+ // Preserve authored classifications/run IDs; use the worker's cause only
129
+ // when its connection teardown left a generic transport error.
130
+ const error = caught instanceof AuthoredFlowExecutionError || caught instanceof AuthoredFlowLoadError
131
+ ? caught : llmFailure ?? localAgent?.failure ?? caught;
73
132
  // `agent_cli_unresolved` and `unsupported_workspace_permission` are
74
133
  // preflight-shaped refusals, not protocol failures — `flows check`
75
134
  // returns exit 2 for the equivalent declarative-spec failures, and this
@@ -82,21 +141,31 @@ export async function runDirectFlow(
82
141
  // the same limitation already documented elsewhere).
83
142
  if (error instanceof AuthoredFlowLoadError
84
143
  || (error instanceof AuthoredFlowExecutionError
85
- && (error.code === 'unsupported_header'
144
+ && (error.code === 'helper_slack.credential_missing'
145
+ || error.code === 'helper_slack.mount_required'
146
+ || error.code === 'budget_syntax_invalid'
147
+ || error.code === 'budget_missing_price'
148
+ || error.code === 'unsupported_header'
86
149
  || error.code === 'agent_cli_unresolved'
150
+ || error.code === 'llm_cli_unresolved'
87
151
  || error.code === 'unsupported_workspace_permission'))) {
88
152
  return {
89
153
  exitCode: 2,
90
154
  report: {
91
155
  ...fromCheckReport('run', inputFailureReport({
92
- kind: 'invalid_spec',
156
+ kind: error instanceof AuthoredFlowExecutionError && (
157
+ error.code === 'helper_slack.credential_missing'
158
+ || error.code === 'helper_slack.mount_required'
159
+ || error.code === 'budget_syntax_invalid'
160
+ || error.code === 'budget_missing_price'
161
+ ) ? error.code : 'invalid_spec',
93
162
  message: error.message,
94
163
  }, path)),
95
164
  socketPath,
96
165
  },
97
166
  };
98
167
  }
99
- if (error instanceof AuthoredFlowExecutionError && error.code === 'agent_parked') {
168
+ if (error instanceof AuthoredFlowExecutionError && (error.code === 'agent_parked' || error.code === 'llm_parked')) {
100
169
  return {
101
170
  exitCode: 3,
102
171
  report: {
@@ -116,6 +185,9 @@ export async function runDirectFlow(
116
185
  const runId = error instanceof AuthoredFlowExecutionError ? error.runId : undefined;
117
186
  return protocolFailure('run', base, socketPath, error, runId);
118
187
  } finally {
119
- client.close();
188
+ try {
189
+ await localLlm?.close();
190
+ await localAgent?.close();
191
+ } finally { llmClient?.close(); client.close(); }
120
192
  }
121
193
  }
@@ -16,6 +16,7 @@ import { readFile } from 'node:fs/promises';
16
16
  import { dirname, isAbsolute, resolve } from 'node:path';
17
17
  import { pollHackerNewsOnce, HnTransientFetchError, type Fetcher } from '../hn-poller.js';
18
18
  import { AgentWorker } from '../worker.js';
19
+ import { socketPathFor } from '../daemon-connection.js';
19
20
  import { JournalClient } from '../journal-client.js';
20
21
  import type { EventSubmitResult, HelloResult, Pins } from '../protocol.js';
21
22
  import type { CliIo } from '../cli.js';
@@ -181,7 +182,7 @@ async function defaultAttachWorker(
181
182
  */
182
183
  export async function runHnMonitor(args: HnMonitorArgs, io: CliIo): Promise<0 | 1> {
183
184
  const pollIntervalMs = args.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
184
- const socketPath = `${args.dataDir}/relayflowd.sock`;
185
+ const socketPath = socketPathFor(args.dataDir);
185
186
 
186
187
  let spec: unknown;
187
188
  try {
@@ -0,0 +1,81 @@
1
+ import type { CliIo } from '../cli.js';
2
+ import { canonicalize } from '../canonical.js';
3
+ import { JournalReadError, walkJournal } from '../journal-client.js';
4
+
5
+ export interface ReplayArgs {
6
+ command: 'replay';
7
+ value: string;
8
+ json: boolean;
9
+ dataDir: string;
10
+ at?: string;
11
+ allowHumanInfluenced?: boolean;
12
+ }
13
+
14
+ export function parseReplayArgs(args: readonly string[]): ReplayArgs | undefined {
15
+ let json = false;
16
+ let allowHumanInfluenced = false;
17
+ let dataDir: string | undefined;
18
+ let at: string | undefined;
19
+ const positionals: string[] = [];
20
+ for (let index = 0; index < args.length; index += 1) {
21
+ const argument = args[index]!;
22
+ if (argument === '--allow-human-influenced') {
23
+ if (allowHumanInfluenced) return undefined;
24
+ allowHumanInfluenced = true;
25
+ } else if (argument === '--json') {
26
+ if (json) return undefined;
27
+ json = true;
28
+ } else if (argument === '--data-dir' || argument === '--at') {
29
+ const value = args[++index];
30
+ if (value === undefined || value.length === 0 || value.startsWith('-')) return undefined;
31
+ if (argument === '--data-dir') {
32
+ if (dataDir !== undefined) return undefined;
33
+ dataDir = value;
34
+ } else {
35
+ if (at !== undefined) return undefined;
36
+ at = value;
37
+ }
38
+ } else if (argument.startsWith('-')) {
39
+ return undefined;
40
+ } else {
41
+ positionals.push(argument);
42
+ }
43
+ }
44
+ if (positionals.length !== 1) return undefined;
45
+ return { allowHumanInfluenced, command: 'replay', value: positionals[0]!, json, dataDir: dataDir ?? '.relayflowd', at };
46
+ }
47
+
48
+ export async function replayJournal(args: ReplayArgs, io: CliIo): Promise<0 | 1 | 2> {
49
+ let emitted = false;
50
+ try {
51
+ for await (const event of walkJournal(args.value, args.dataDir, { at: args.at })) {
52
+ const payload = event.payload !== null && typeof event.payload === 'object' && !Array.isArray(event.payload)
53
+ ? event.payload as Record<string, unknown> : {};
54
+ if (event.entry_type === 'step.completed' && payload['human_intervention'] === true && !args.allowHumanInfluenced) {
55
+ io.stderr(`REFUSED [human_influenced_run] step ${JSON.stringify(event.step_id)}; pass --allow-human-influenced to continue`);
56
+ return 2;
57
+ }
58
+ io.stdout(args.json ? canonicalize({
59
+ step_id: event.step_id,
60
+ kind: event.entry_type,
61
+ event,
62
+ verification: payload['verification'] ?? null,
63
+ spend: payload['budget'] ?? payload['budget_total'] ?? null,
64
+ })
65
+ : `${event.seq} ${event.at_ms} ${event.entry_type}`
66
+ + (event.step_id === null ? '' : ` step=${JSON.stringify(event.step_id)}`)
67
+ + (event.attempt === null ? '' : ` attempt=${event.attempt}`)
68
+ + ` ${canonicalize(event.payload)}`);
69
+ emitted = true;
70
+ }
71
+ return 0;
72
+ } catch (error) {
73
+ const diagnostic = {
74
+ severity: 'refusal',
75
+ kind: error instanceof JournalReadError ? error.code : 'journal_read_failed',
76
+ message: error instanceof Error ? error.message : String(error),
77
+ };
78
+ io.stderr(`${emitted ? 'FAILED' : 'REFUSED'} [${diagnostic.kind}] ${diagnostic.message}`);
79
+ return emitted ? 1 : 2;
80
+ }
81
+ }
@@ -0,0 +1,23 @@
1
+ import type { JournalClient } from '../journal-client.js';
2
+
3
+ /** Count durable facts, including failed executions, across paginated reads. */
4
+ export async function reuseSummary(client: JournalClient, runId: string, fromRunId: string): Promise<{
5
+ fromRunId: string; reusedSteps: number; executedSteps: number;
6
+ }> {
7
+ const reused = new Set<string>();
8
+ const executed = new Set<string>();
9
+ let fromSeq = 1;
10
+ while (true) {
11
+ const { entries } = await client.journalRead(runId, fromSeq, 1000);
12
+ if (entries.length === 0) break;
13
+ for (const raw of entries) {
14
+ const entry = raw as { seq: number; entry_type: string; step_id?: string; payload: { reused_from?: unknown } };
15
+ if (!Number.isSafeInteger(entry.seq) || entry.seq < fromSeq) throw new Error('invalid journal sequence in reuse summary');
16
+ fromSeq = entry.seq + 1;
17
+ if (entry.step_id === undefined) continue;
18
+ if (entry.entry_type === 'step.attempt.started') executed.add(entry.step_id);
19
+ if (entry.entry_type === 'step.completed' && entry.payload.reused_from !== undefined) reused.add(entry.step_id);
20
+ }
21
+ }
22
+ return { fromRunId, reusedSteps: reused.size, executedSteps: executed.size };
23
+ }
@@ -0,0 +1,24 @@
1
+ import { BundleFailure, fetchBundle, parseDigestReference } from '../bundle-transport.js';
2
+ import { CheckFailure, inputFailureReport, readProjectConfig, type CheckExecution } from './check.js';
3
+ import { checkRunnableBundle } from './bundle-preflight.js';
4
+ import type { RunExecution } from './run.js';
5
+
6
+ export async function prepareDigestRun(reference: string, bucket?: string): Promise<CheckExecution | RunExecution> {
7
+ try {
8
+ const ref = parseDigestReference(reference)!;
9
+ const selected = bucket ?? readProjectConfig(process.cwd()).deploy?.bucket;
10
+ if (!selected) throw new BundleFailure('bucket_unconfigured', 'Set --bucket <uri> or deploy.bucket in flows.json.');
11
+ const directory = await fetchBundle(ref, selected);
12
+ const checked = await checkRunnableBundle(directory, ref.name);
13
+ checked.report.path = reference;
14
+ return checked;
15
+ } catch (error) {
16
+ if (error instanceof CheckFailure) return { report: inputFailureReport(error, reference) };
17
+ const kind = error instanceof BundleFailure && (
18
+ error.kind === 'bucket_unconfigured' || error.kind === 'bucket_unreachable'
19
+ || error.kind === 'bundle_signature_invalid' || error.kind === 'bundle_unsupported'
20
+ ) ? error.kind : 'bundle_unsupported';
21
+ return { exitCode: 2, report: { ok: false, command: 'run', path: reference, resolutions: [],
22
+ diagnostics: [{ severity: 'refusal', kind, message: error instanceof Error ? error.message : String(error) }] } };
23
+ }
24
+ }
package/src/cli/run.ts CHANGED
@@ -1,10 +1,19 @@
1
+ import { parseDigestReference } from '../bundle-transport.js';
2
+ import { prepareDigestRun } from './run-digest.js';
3
+ import { reuseSummary } from './reuse.js';
4
+ import { resumeHelperEffect } from '../authored-helper-effect.js';
5
+ import { AuthoredFlowExecutionError } from '../authored-flow-error.js';
1
6
  import { join, resolve } from 'node:path';
7
+ import type { ProgressEvent } from '../progress.js';
2
8
  import { toKernelSpec } from '../compile.js';
9
+ import { socketPathFor } from '../daemon-connection.js';
3
10
  import { ensureDaemon, type EnsureDaemonOptions } from '../daemon-lifecycle.js';
11
+ import { isAuthoredFlowPath } from '../direct-input.js';
4
12
  import { daemonRefusal } from './daemon-refusal.js';
5
- import type { RunFailureKind, RunWarningKind } from '../failure-kinds.js';
13
+ import type { RunFailureKind, RunWarningKind, StepFailedDetails } from '../failure-kinds.js';
14
+ import { deterministicFailureDetails } from './deterministic-failure.js';
6
15
  import { JournalClient, JournalProtocolError } from '../journal-client.js';
7
- import type { PreflightDiagnostic } from '../preflight.js';
16
+ import { attachLocalAgent } from '../local-agent.js';
8
17
  import type {
9
18
  RunCompletionReason,
10
19
  RunOutcome,
@@ -13,7 +22,6 @@ import type {
13
22
  import type { StepType } from '../spec.js';
14
23
  import {
15
24
  checkFlow,
16
- type CheckInputDiagnostic,
17
25
  type CheckReport,
18
26
  } from './check.js';
19
27
 
@@ -25,7 +33,7 @@ export interface ParkedStep {
25
33
  type: Extract<StepType, 'llm' | 'agent'>;
26
34
  }
27
35
 
28
- export interface RunDiagnostic {
36
+ export interface RunDiagnostic extends StepFailedDetails {
29
37
  severity: 'refusal' | 'failure' | 'parked' | 'warning';
30
38
  kind: RunFailureKind | RunWarningKind | RunCompletionReason;
31
39
  message: string;
@@ -40,10 +48,11 @@ export interface RunReport {
40
48
  status?: RunStatus;
41
49
  completionReason?: RunCompletionReason;
42
50
  completedSteps?: number;
51
+ reuse?: { fromRunId: string; reusedSteps: number; executedSteps: number };
43
52
  parkedStep?: ParkedStep;
44
53
  projectConfigPath?: string;
45
54
  resolutions: CheckReport['resolutions'];
46
- diagnostics: Array<PreflightDiagnostic | CheckInputDiagnostic | RunDiagnostic>;
55
+ diagnostics: Array<CheckReport['diagnostics'][number] | RunDiagnostic>;
47
56
  }
48
57
 
49
58
  export interface RunExecution {
@@ -59,6 +68,12 @@ export interface RunProgress {
59
68
  }
60
69
 
61
70
  export interface RunLifecycleOptions {
71
+ bucket?: string;
72
+ allowHumanInfluenced?: boolean;
73
+ onPtyReady?: (path: string) => void;
74
+ reuseFromRunId?: string;
75
+ onProgress?: (event: ProgressEvent) => void;
76
+ localAgent?: boolean;
62
77
  signal?: AbortSignal;
63
78
  onWait?: (progress: RunProgress) => void;
64
79
  /**
@@ -74,7 +89,9 @@ export async function runFlow(
74
89
  dataDir: string,
75
90
  options: RunLifecycleOptions = {},
76
91
  ): Promise<RunExecution> {
77
- const checked = checkFlow(path);
92
+ const prepared = parseDigestReference(path) ? await prepareDigestRun(path, options.bucket) : undefined;
93
+ if (prepared && 'exitCode' in prepared) return prepared;
94
+ const checked = prepared ?? checkFlow(path);
78
95
  if (!checked.report.ok || checked.flow === undefined) {
79
96
  return { exitCode: 2, report: fromCheckReport('run', checked.report) };
80
97
  }
@@ -95,14 +112,31 @@ async function executeCheckedFlow(
95
112
  const connected = await connect(client, 'run', dataDir, base, options);
96
113
  if (connected !== undefined) return connected;
97
114
 
115
+ let localAgent: Awaited<ReturnType<typeof attachLocalAgent>> | undefined;
98
116
  try {
99
117
  const spec = toKernelSpec(checked.flow!);
100
- const outcome = await client.runStart(spec);
101
- return await classifyOutcome(client, 'run', outcome, base, socketPath, options);
118
+ // Use the checked CLI/model and declared surfaces unchanged. The worker
119
+ // advertises its existing pins; the daemon still owns surface matching.
120
+ if (options.localAgent) localAgent = await attachLocalAgent(client, dataDir, options.onPtyReady);
121
+ const outcome = await client.runStart(spec, options.reuseFromRunId);
122
+ const execution = await classifyOutcome(client, 'run', outcome, base, socketPath, options);
123
+ if (options.reuseFromRunId !== undefined) {
124
+ execution.report.reuse = await reuseSummary(client, outcome.run_id, options.reuseFromRunId);
125
+ }
126
+ return execution;
102
127
  } catch (error) {
103
- return protocolFailure('run', base, socketPath, error);
128
+ if (error instanceof JournalProtocolError && (
129
+ error.code === 'reuse_spec_mismatch' || error.code === 'reuse_run_not_found'
130
+ || error.code === 'reuse_journal_read_failed'
131
+ )) {
132
+ const failed = error.code === 'reuse_journal_read_failed';
133
+ return { exitCode: failed ? 1 : 2, report: { ...base, socketPath,
134
+ diagnostics: [...base.diagnostics, { severity: failed ? 'failure' : 'refusal',
135
+ kind: error.code, message: error.message }] } };
136
+ }
137
+ return protocolFailure('run', base, socketPath, localAgent?.failure ?? error);
104
138
  } finally {
105
- client.close();
139
+ try { await localAgent?.close(); } finally { client.close(); }
106
140
  }
107
141
  }
108
142
 
@@ -118,9 +152,26 @@ export async function resumeFlow(
118
152
  if (connected !== undefined) return connected;
119
153
 
120
154
  try {
121
- const outcome = await client.runResume(runId);
155
+ // resumeHelperEffect subsumes the old resumeSlackEffect: it handles the
156
+ // slack effect resume plus every other provider from N's codegen. The
157
+ // second call the earlier rebase left is a stale reference from before
158
+ // the helper fanout renamed the API.
159
+ let outcome = await client.runResume(runId, options.allowHumanInfluenced);
160
+ if (await resumeHelperEffect(client, runId, dataDir)) {
161
+ outcome = await client.runResume(runId, options.allowHumanInfluenced);
162
+ }
122
163
  return await classifyOutcome(client, 'resume', outcome, base, socketPath, options);
123
164
  } catch (error) {
165
+ if (error instanceof JournalProtocolError && error.code === 'human_influenced_run') {
166
+ return { exitCode: 2, report: { ...base, runId, socketPath,
167
+ diagnostics: [{ severity: 'refusal', kind: 'human_influenced_run', message: error.message.replace(/^human_influenced_run: /, '') }] } };
168
+ }
169
+ if (error instanceof AuthoredFlowExecutionError
170
+ && (error.code === 'helper_slack.credential_missing' || error.code === 'helper_slack.mount_required'
171
+ || error.code === 'helper_provider.mount_required' || error.code === 'helper_provider.unsupported')) {
172
+ return { exitCode: 2, report: { ...base, runId, socketPath,
173
+ diagnostics: [{ severity: 'refusal', kind: error.code, message: error.message }] } };
174
+ }
124
175
  if (!(error instanceof JournalProtocolError) || error.code !== 'run_not_found') {
125
176
  return protocolFailure('resume', base, socketPath, error, runId);
126
177
  }
@@ -243,11 +294,11 @@ export async function classifyOutcome(
243
294
  }
244
295
  if (inspection?.runningStep !== undefined) {
245
296
  await waitForRunningStep(client, current.run_id, inspection.runningStep, options);
246
- current = await client.runResume(current.run_id);
297
+ current = await client.runResume(current.run_id, command === 'run' || options.allowHumanInfluenced);
247
298
  continue;
248
299
  }
249
300
  if (inspection?.status === 'completed' || inspection?.status === 'failed') {
250
- current = await client.runResume(current.run_id);
301
+ current = await client.runResume(current.run_id, command === 'run' || options.allowHumanInfluenced);
251
302
  continue;
252
303
  }
253
304
  // The run is still RUNNING but no step is identifiable at this instant.
@@ -275,7 +326,7 @@ export async function classifyOutcome(
275
326
  // is already progressing -- it returns the current state rather than
276
327
  // re-dispatching. This loop leans on that up to MAX_UNCLASSIFIED_POLLS
277
328
  // times while the daemon is mid-transition.
278
- current = await client.runResume(current.run_id);
329
+ current = await client.runResume(current.run_id, command === 'run' || options.allowHumanInfluenced);
279
330
  continue;
280
331
  }
281
332
  // Fail closed rather than loop forever: if it never resolves, the original
@@ -295,15 +346,30 @@ export async function classifyOutcome(
295
346
 
296
347
  if (report.ok) return { exitCode: 0, report };
297
348
  if (current.status === 'failed' && current.completion_reason !== null) {
349
+ const diagnostic: RunDiagnostic = {
350
+ severity: 'failure',
351
+ kind: current.completion_reason,
352
+ message: `Run "${current.run_id}" failed with completionReason: ${current.completion_reason}.`,
353
+ };
354
+ if (current.completion_reason === 'step_failed') {
355
+ try {
356
+ const details = await deterministicFailureDetails(client, current.run_id);
357
+ if (details !== undefined) {
358
+ Object.assign(diagnostic, details);
359
+ diagnostic.message += ` Step ${JSON.stringify(details.stepId)} exit=${details.exitCode}.`
360
+ + (details.stderrTail ? `\nStderr (last 1,024 bytes):\n${details.stderrTail}` : '')
361
+ + `\nInspect: ${details.hint}`;
362
+ }
363
+ } catch (error) {
364
+ // Inspection must not erase the already known run failure.
365
+ diagnostic.message += ` Could not inspect command failure: ${errorMessage(error)}`;
366
+ }
367
+ }
298
368
  return {
299
369
  exitCode: 1,
300
370
  report: {
301
371
  ...report,
302
- diagnostics: [...report.diagnostics, {
303
- severity: 'failure',
304
- kind: current.completion_reason,
305
- message: `Run "${current.run_id}" failed with completionReason: ${current.completion_reason}.`,
306
- }],
372
+ diagnostics: [...report.diagnostics, diagnostic],
307
373
  },
308
374
  };
309
375
  }
@@ -318,7 +384,20 @@ export async function classifyOutcome(
318
384
  kind: 'run_parked',
319
385
  message: needsHuman
320
386
  ? `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): waiting for human recovery after the worker attempt failed.`
321
- : `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): no worker is attached for step type "${parkedStep.type}".`,
387
+ : `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): no worker is attached for step type "${parkedStep.type}".`
388
+ // Only suggest the `--local-agent` remedy for YAML flows.
389
+ // Authored TS flows require `--input`; the bare command below
390
+ // would be refused (Cursor Bugbot flagged as LOW on flows#293).
391
+ // For TS we omit the hint rather than fabricate a syntactically
392
+ // valid but semantically wrong command — the direct-run refusal
393
+ // for TS already names its own missing --input.
394
+ + (command === 'run'
395
+ && parkedStep.type === 'agent'
396
+ && !options.localAgent
397
+ && base.path !== undefined
398
+ && !isAuthoredFlowPath(base.path)
399
+ ? ` To start a new run with a local agent worker: flows run --local-agent '${base.path.replace(/'/g, "'\\''")}'. Declared workspace or stream surfaces require a worker that holds their pins.`
400
+ : ''),
322
401
  }],
323
402
  },
324
403
  };
@@ -461,8 +540,12 @@ function fromBase(command: RunCommand, base: CheckReport | RunReport): RunReport
461
540
  return 'command' in base ? base : fromCheckReport(command, base);
462
541
  }
463
542
 
543
+ // Delegates to the daemon-connection derivation so run.ts, direct-run.ts, and
544
+ // the daemon-lifecycle attach path all speak the same socket path. Kept as a
545
+ // re-export here so existing callers do not have to reach into
546
+ // daemon-connection.ts. See socketPathFor for the SUN_LEN reasoning (#262).
464
547
  export function socketFor(dataDir: string): string {
465
- return join(resolve(dataDir), 'relayflowd.sock');
548
+ return socketPathFor(dataDir);
466
549
  }
467
550
 
468
551
  function errorMessage(error: unknown): string {