@relayflows/sdk 2.0.30 → 2.0.32

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 (347) hide show
  1. package/dist/agent-artifacts.d.ts.map +1 -1
  2. package/dist/agent-artifacts.js +2 -9
  3. package/dist/agent-artifacts.js.map +1 -1
  4. package/dist/agent-cwd.d.ts +69 -0
  5. package/dist/agent-cwd.d.ts.map +1 -0
  6. package/dist/agent-cwd.js +140 -0
  7. package/dist/agent-cwd.js.map +1 -0
  8. package/dist/artifact-scan-policy.d.ts +35 -0
  9. package/dist/artifact-scan-policy.d.ts.map +1 -0
  10. package/dist/artifact-scan-policy.js +49 -0
  11. package/dist/artifact-scan-policy.js.map +1 -0
  12. package/dist/authored-completion-record.d.ts +35 -0
  13. package/dist/authored-completion-record.d.ts.map +1 -0
  14. package/dist/authored-completion-record.js +92 -0
  15. package/dist/authored-completion-record.js.map +1 -0
  16. package/dist/authored-completion.d.ts +99 -0
  17. package/dist/authored-completion.d.ts.map +1 -0
  18. package/dist/authored-completion.js +184 -0
  19. package/dist/authored-completion.js.map +1 -0
  20. package/dist/authored-flow-error.d.ts +13 -1
  21. package/dist/authored-flow-error.d.ts.map +1 -1
  22. package/dist/authored-flow-error.js +12 -0
  23. package/dist/authored-flow-error.js.map +1 -1
  24. package/dist/authored-flow-executor.d.ts +7 -30
  25. package/dist/authored-flow-executor.d.ts.map +1 -1
  26. package/dist/authored-flow-executor.js +54 -47
  27. package/dist/authored-flow-executor.js.map +1 -1
  28. package/dist/authored-human.d.ts.map +1 -1
  29. package/dist/authored-human.js +1 -3
  30. package/dist/authored-human.js.map +1 -1
  31. package/dist/authored-node-entry.js +4 -1
  32. package/dist/authored-node-entry.js.map +1 -1
  33. package/dist/authored-node-runner.d.ts +9 -1
  34. package/dist/authored-node-runner.d.ts.map +1 -1
  35. package/dist/authored-node-runner.js +92 -17
  36. package/dist/authored-node-runner.js.map +1 -1
  37. package/dist/authored-preflight.d.ts +4 -0
  38. package/dist/authored-preflight.d.ts.map +1 -0
  39. package/dist/authored-preflight.js +50 -0
  40. package/dist/authored-preflight.js.map +1 -0
  41. package/dist/authored-root.d.ts +5 -0
  42. package/dist/authored-root.d.ts.map +1 -1
  43. package/dist/authored-root.js +20 -2
  44. package/dist/authored-root.js.map +1 -1
  45. package/dist/authored-step-output.d.ts +35 -10
  46. package/dist/authored-step-output.d.ts.map +1 -1
  47. package/dist/authored-step-output.js +108 -40
  48. package/dist/authored-step-output.js.map +1 -1
  49. package/dist/authored-verdict.d.ts +28 -0
  50. package/dist/authored-verdict.d.ts.map +1 -0
  51. package/dist/authored-verdict.js +79 -0
  52. package/dist/authored-verdict.js.map +1 -0
  53. package/dist/authored-worker-step.d.ts +5 -2
  54. package/dist/authored-worker-step.d.ts.map +1 -1
  55. package/dist/authored-worker-step.js +51 -13
  56. package/dist/authored-worker-step.js.map +1 -1
  57. package/dist/cli/check-worker-surface.d.ts +27 -0
  58. package/dist/cli/check-worker-surface.d.ts.map +1 -0
  59. package/dist/cli/check-worker-surface.js +63 -0
  60. package/dist/cli/check-worker-surface.js.map +1 -0
  61. package/dist/cli/check.d.ts +28 -3
  62. package/dist/cli/check.d.ts.map +1 -1
  63. package/dist/cli/check.js +27 -140
  64. package/dist/cli/check.js.map +1 -1
  65. package/dist/cli/cli-probe.d.ts +20 -0
  66. package/dist/cli/cli-probe.d.ts.map +1 -0
  67. package/dist/cli/cli-probe.js +166 -0
  68. package/dist/cli/cli-probe.js.map +1 -0
  69. package/dist/cli/cloud-format.d.ts +9 -0
  70. package/dist/cli/cloud-format.d.ts.map +1 -0
  71. package/dist/cli/cloud-format.js +77 -0
  72. package/dist/cli/cloud-format.js.map +1 -0
  73. package/dist/cli/cloud-live.d.ts +39 -0
  74. package/dist/cli/cloud-live.d.ts.map +1 -0
  75. package/dist/cli/cloud-live.js +325 -0
  76. package/dist/cli/cloud-live.js.map +1 -0
  77. package/dist/cli/cloud-mirror-session.d.ts +97 -0
  78. package/dist/cli/cloud-mirror-session.d.ts.map +1 -0
  79. package/dist/cli/cloud-mirror-session.js +264 -0
  80. package/dist/cli/cloud-mirror-session.js.map +1 -0
  81. package/dist/cli/cloud-read.d.ts +3 -7
  82. package/dist/cli/cloud-read.d.ts.map +1 -1
  83. package/dist/cli/cloud-read.js +14 -266
  84. package/dist/cli/cloud-read.js.map +1 -1
  85. package/dist/cli/cloud-refusal.d.ts +39 -0
  86. package/dist/cli/cloud-refusal.d.ts.map +1 -0
  87. package/dist/cli/cloud-refusal.js +95 -0
  88. package/dist/cli/cloud-refusal.js.map +1 -0
  89. package/dist/cli/cloud-status-view.d.ts +7 -0
  90. package/dist/cli/cloud-status-view.d.ts.map +1 -0
  91. package/dist/cli/cloud-status-view.js +214 -0
  92. package/dist/cli/cloud-status-view.js.map +1 -0
  93. package/dist/cli/direct-run.d.ts.map +1 -1
  94. package/dist/cli/direct-run.js +16 -2
  95. package/dist/cli/direct-run.js.map +1 -1
  96. package/dist/cli/hn-monitor.d.ts +0 -13
  97. package/dist/cli/hn-monitor.d.ts.map +1 -1
  98. package/dist/cli/hn-monitor.js +2 -1
  99. package/dist/cli/hn-monitor.js.map +1 -1
  100. package/dist/cli/local-agent-remedy.d.ts +80 -0
  101. package/dist/cli/local-agent-remedy.d.ts.map +1 -0
  102. package/dist/cli/local-agent-remedy.js +116 -0
  103. package/dist/cli/local-agent-remedy.js.map +1 -0
  104. package/dist/cli/observer-session.d.ts +41 -0
  105. package/dist/cli/observer-session.d.ts.map +1 -0
  106. package/dist/cli/observer-session.js +78 -0
  107. package/dist/cli/observer-session.js.map +1 -0
  108. package/dist/cli/run.d.ts +30 -2
  109. package/dist/cli/run.d.ts.map +1 -1
  110. package/dist/cli/run.js +186 -24
  111. package/dist/cli/run.js.map +1 -1
  112. package/dist/cli/status.d.ts +9 -0
  113. package/dist/cli/status.d.ts.map +1 -1
  114. package/dist/cli/status.js +31 -2
  115. package/dist/cli/status.js.map +1 -1
  116. package/dist/cli/step-evidence.d.ts +90 -0
  117. package/dist/cli/step-evidence.d.ts.map +1 -0
  118. package/dist/cli/step-evidence.js +259 -0
  119. package/dist/cli/step-evidence.js.map +1 -0
  120. package/dist/cli/step-failure.d.ts +14 -4
  121. package/dist/cli/step-failure.d.ts.map +1 -1
  122. package/dist/cli/step-failure.js +41 -76
  123. package/dist/cli/step-failure.js.map +1 -1
  124. package/dist/cli-commands.d.ts +12 -0
  125. package/dist/cli-commands.d.ts.map +1 -1
  126. package/dist/cli-commands.js +3 -0
  127. package/dist/cli-commands.js.map +1 -1
  128. package/dist/cli.d.ts +17 -0
  129. package/dist/cli.d.ts.map +1 -1
  130. package/dist/cli.js +134 -57
  131. package/dist/cli.js.map +1 -1
  132. package/dist/cloud-deploy.d.ts +1 -1
  133. package/dist/cloud-deploy.d.ts.map +1 -1
  134. package/dist/cloud-deploy.js +24 -8
  135. package/dist/cloud-deploy.js.map +1 -1
  136. package/dist/cloud-mirror-ledger.d.ts +40 -0
  137. package/dist/cloud-mirror-ledger.d.ts.map +1 -0
  138. package/dist/cloud-mirror-ledger.js +142 -0
  139. package/dist/cloud-mirror-ledger.js.map +1 -0
  140. package/dist/cloud-mirror-step.d.ts +168 -0
  141. package/dist/cloud-mirror-step.d.ts.map +1 -0
  142. package/dist/cloud-mirror-step.js +504 -0
  143. package/dist/cloud-mirror-step.js.map +1 -0
  144. package/dist/cloud-mirror-transport.d.ts +94 -0
  145. package/dist/cloud-mirror-transport.d.ts.map +1 -0
  146. package/dist/cloud-mirror-transport.js +163 -0
  147. package/dist/cloud-mirror-transport.js.map +1 -0
  148. package/dist/cloud-mirror.d.ts +132 -0
  149. package/dist/cloud-mirror.d.ts.map +1 -0
  150. package/dist/cloud-mirror.js +556 -0
  151. package/dist/cloud-mirror.js.map +1 -0
  152. package/dist/cloud-read.d.ts +15 -0
  153. package/dist/cloud-read.d.ts.map +1 -1
  154. package/dist/cloud-read.js +20 -1
  155. package/dist/cloud-read.js.map +1 -1
  156. package/dist/cloud-run-record.d.ts +27 -0
  157. package/dist/cloud-run-record.d.ts.map +1 -0
  158. package/dist/cloud-run-record.js +56 -0
  159. package/dist/cloud-run-record.js.map +1 -0
  160. package/dist/cloud-run.d.ts +2 -9
  161. package/dist/cloud-run.d.ts.map +1 -1
  162. package/dist/cloud-run.js +3 -20
  163. package/dist/cloud-run.js.map +1 -1
  164. package/dist/communication/local.d.ts.map +1 -1
  165. package/dist/communication/local.js +2 -1
  166. package/dist/communication/local.js.map +1 -1
  167. package/dist/communication/worker.d.ts +1 -1
  168. package/dist/communication/worker.d.ts.map +1 -1
  169. package/dist/communication/worker.js +13 -5
  170. package/dist/communication/worker.js.map +1 -1
  171. package/dist/compile.d.ts.map +1 -1
  172. package/dist/compile.js +28 -6
  173. package/dist/compile.js.map +1 -1
  174. package/dist/direct-input.d.ts.map +1 -1
  175. package/dist/direct-input.js +21 -1
  176. package/dist/direct-input.js.map +1 -1
  177. package/dist/failure-kinds.d.ts +96 -6
  178. package/dist/failure-kinds.d.ts.map +1 -1
  179. package/dist/failure-kinds.js +29 -2
  180. package/dist/failure-kinds.js.map +1 -1
  181. package/dist/flow-requirements.d.ts.map +1 -1
  182. package/dist/flow-requirements.js +24 -9
  183. package/dist/flow-requirements.js.map +1 -1
  184. package/dist/gate-contract.d.ts +7 -0
  185. package/dist/gate-contract.d.ts.map +1 -1
  186. package/dist/gate-contract.js +6 -1
  187. package/dist/gate-contract.js.map +1 -1
  188. package/dist/helper-preflight.d.ts.map +1 -1
  189. package/dist/helper-preflight.js +10 -3
  190. package/dist/helper-preflight.js.map +1 -1
  191. package/dist/helper-reference.d.ts +25 -0
  192. package/dist/helper-reference.d.ts.map +1 -0
  193. package/dist/helper-reference.js +129 -0
  194. package/dist/helper-reference.js.map +1 -0
  195. package/dist/hosted-extension-runtime.js +1 -1
  196. package/dist/index.d.ts +1 -1
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js.map +1 -1
  199. package/dist/journal-client.d.ts +3 -1
  200. package/dist/journal-client.d.ts.map +1 -1
  201. package/dist/journal-client.js +17 -2
  202. package/dist/journal-client.js.map +1 -1
  203. package/dist/journal-projection.d.ts +16 -0
  204. package/dist/journal-projection.d.ts.map +1 -0
  205. package/dist/journal-projection.js +108 -0
  206. package/dist/journal-projection.js.map +1 -0
  207. package/dist/llm-worker.js +1 -1
  208. package/dist/llm-worker.js.map +1 -1
  209. package/dist/local-agent.d.ts +1 -1
  210. package/dist/local-agent.d.ts.map +1 -1
  211. package/dist/local-agent.js +4 -3
  212. package/dist/local-agent.js.map +1 -1
  213. package/dist/named-gate-lowering.js +35 -5
  214. package/dist/named-gate-lowering.js.map +1 -1
  215. package/dist/named-gate-preflight.d.ts +27 -0
  216. package/dist/named-gate-preflight.d.ts.map +1 -0
  217. package/dist/named-gate-preflight.js +47 -0
  218. package/dist/named-gate-preflight.js.map +1 -0
  219. package/dist/named-gates.d.ts +1 -1
  220. package/dist/named-gates.d.ts.map +1 -1
  221. package/dist/named-gates.js +3 -0
  222. package/dist/named-gates.js.map +1 -1
  223. package/dist/observer-link.d.ts +7 -0
  224. package/dist/observer-link.d.ts.map +1 -1
  225. package/dist/observer-link.js +3 -1
  226. package/dist/observer-link.js.map +1 -1
  227. package/dist/package-version.d.ts +10 -0
  228. package/dist/package-version.d.ts.map +1 -0
  229. package/dist/package-version.js +22 -0
  230. package/dist/package-version.js.map +1 -0
  231. package/dist/preflight.d.ts +14 -0
  232. package/dist/preflight.d.ts.map +1 -1
  233. package/dist/preflight.js +25 -3
  234. package/dist/preflight.js.map +1 -1
  235. package/dist/protocol.d.ts +2 -0
  236. package/dist/protocol.d.ts.map +1 -1
  237. package/dist/redact.d.ts +42 -0
  238. package/dist/redact.d.ts.map +1 -1
  239. package/dist/redact.js +128 -0
  240. package/dist/redact.js.map +1 -1
  241. package/dist/relay-cli.d.ts.map +1 -1
  242. package/dist/relay-cli.js +1 -21
  243. package/dist/relay-cli.js.map +1 -1
  244. package/dist/run-projection.d.ts +83 -0
  245. package/dist/run-projection.d.ts.map +1 -0
  246. package/dist/run-projection.js +199 -0
  247. package/dist/run-projection.js.map +1 -0
  248. package/dist/shell-word.d.ts +19 -0
  249. package/dist/shell-word.d.ts.map +1 -0
  250. package/dist/shell-word.js +23 -0
  251. package/dist/shell-word.js.map +1 -0
  252. package/dist/spec.d.ts +52 -3
  253. package/dist/spec.d.ts.map +1 -1
  254. package/dist/spec.js.map +1 -1
  255. package/dist/step-fields.d.ts +1 -1
  256. package/dist/step-fields.js +1 -1
  257. package/dist/step-fields.js.map +1 -1
  258. package/dist/steps-green.d.ts +27 -0
  259. package/dist/steps-green.d.ts.map +1 -0
  260. package/dist/steps-green.js +164 -0
  261. package/dist/steps-green.js.map +1 -0
  262. package/dist/validate.d.ts.map +1 -1
  263. package/dist/validate.js +39 -8
  264. package/dist/validate.js.map +1 -1
  265. package/dist/worker-lease.d.ts +8 -1
  266. package/dist/worker-lease.d.ts.map +1 -1
  267. package/dist/worker-lease.js +34 -4
  268. package/dist/worker-lease.js.map +1 -1
  269. package/dist/worker.d.ts +8 -0
  270. package/dist/worker.d.ts.map +1 -1
  271. package/dist/worker.js +17 -9
  272. package/dist/worker.js.map +1 -1
  273. package/package.json +3 -7
  274. package/src/agent-artifacts.ts +2 -10
  275. package/src/agent-cwd.ts +139 -0
  276. package/src/artifact-scan-policy.ts +51 -0
  277. package/src/authored-completion-record.ts +119 -0
  278. package/src/authored-completion.ts +203 -0
  279. package/src/authored-flow-error.ts +13 -1
  280. package/src/authored-flow-executor.ts +91 -58
  281. package/src/authored-human.ts +1 -4
  282. package/src/authored-node-entry.ts +4 -1
  283. package/src/authored-node-runner.ts +96 -22
  284. package/src/authored-preflight.ts +46 -0
  285. package/src/authored-root.ts +20 -2
  286. package/src/authored-step-output.ts +139 -42
  287. package/src/authored-verdict.ts +87 -0
  288. package/src/authored-worker-step.ts +63 -14
  289. package/src/cli/check-worker-surface.ts +66 -0
  290. package/src/cli/check.ts +59 -166
  291. package/src/cli/cli-probe.ts +194 -0
  292. package/src/cli/cloud-format.ts +82 -0
  293. package/src/cli/cloud-live.ts +366 -0
  294. package/src/cli/cloud-mirror-session.ts +329 -0
  295. package/src/cli/cloud-read.ts +13 -282
  296. package/src/cli/cloud-refusal.ts +113 -0
  297. package/src/cli/cloud-status-view.ts +213 -0
  298. package/src/cli/direct-run.ts +19 -2
  299. package/src/cli/hn-monitor.ts +2 -1
  300. package/src/cli/local-agent-remedy.ts +160 -0
  301. package/src/cli/observer-session.ts +107 -0
  302. package/src/cli/run.ts +233 -28
  303. package/src/cli/status.ts +59 -3
  304. package/src/cli/step-evidence.ts +310 -0
  305. package/src/cli/step-failure.ts +57 -81
  306. package/src/cli-commands.ts +3 -0
  307. package/src/cli.ts +155 -60
  308. package/src/cloud-deploy.ts +26 -8
  309. package/src/cloud-mirror-ledger.ts +161 -0
  310. package/src/cloud-mirror-step.ts +618 -0
  311. package/src/cloud-mirror-transport.ts +261 -0
  312. package/src/cloud-mirror.ts +633 -0
  313. package/src/cloud-read.ts +25 -1
  314. package/src/cloud-run-record.ts +64 -0
  315. package/src/cloud-run.ts +5 -24
  316. package/src/communication/local.ts +2 -1
  317. package/src/communication/worker.ts +13 -5
  318. package/src/compile.ts +28 -6
  319. package/src/direct-input.ts +22 -1
  320. package/src/failure-kinds.ts +104 -2
  321. package/src/flow-requirements.ts +24 -9
  322. package/src/gate-contract.ts +13 -1
  323. package/src/helper-preflight.ts +10 -3
  324. package/src/helper-reference.ts +130 -0
  325. package/src/hosted-extension-runtime.ts +1 -1
  326. package/src/index.ts +2 -0
  327. package/src/journal-client.ts +19 -2
  328. package/src/journal-projection.ts +106 -0
  329. package/src/llm-worker.ts +1 -1
  330. package/src/local-agent.ts +4 -2
  331. package/src/named-gate-lowering.ts +35 -5
  332. package/src/named-gate-preflight.ts +47 -0
  333. package/src/named-gates.ts +3 -0
  334. package/src/observer-link.ts +10 -1
  335. package/src/package-version.ts +23 -0
  336. package/src/preflight.ts +38 -7
  337. package/src/protocol.ts +2 -0
  338. package/src/redact.ts +111 -0
  339. package/src/relay-cli.ts +1 -24
  340. package/src/run-projection.ts +247 -0
  341. package/src/shell-word.ts +24 -0
  342. package/src/spec.ts +54 -3
  343. package/src/step-fields.ts +1 -1
  344. package/src/steps-green.ts +168 -0
  345. package/src/validate.ts +35 -8
  346. package/src/worker-lease.ts +35 -5
  347. package/src/worker.ts +27 -11
@@ -0,0 +1,261 @@
1
+ // The Cloud calls a mirrored local run makes, and nothing else.
2
+ //
3
+ // A hosted run reports through five endpoints. A local run reports through the
4
+ // same five, with the same bodies, using a credential Cloud issued for that
5
+ // one run — so the control plane cannot tell a mirrored run from a sandboxed
6
+ // one, and no route needed a new case to admit it.
7
+ //
8
+ // POST /api/v1/workflows/local-run register; returns the credential
9
+ // POST /api/v1/workflows/runs/<id>/events lifecycle events
10
+ // POST /api/v1/workflows/runs/<id>/steps/snapshot the live view, while it runs
11
+ // POST /api/v1/workflows/runs/<id>/steps the final report
12
+ // PUT /api/v1/workflows/runs/<id>/storage/<k> runner log and step transcripts
13
+ // POST /api/v1/workflows/callback the terminal status
14
+ //
15
+ // ## Two credentials, never confused
16
+ //
17
+ // Registration authenticates as the *operator*: the `agent-relay cloud login`
18
+ // token or `FLOWS_CLOUD_TOKEN`, the same credential `flows run --cloud` uses.
19
+ // Everything after it authenticates as the *run*, with the run-bound token the
20
+ // registration returned. That token can write this run's steps and read this
21
+ // run, and can do nothing else in the workspace — so a mirror that is somehow
22
+ // coerced into pushing elsewhere has nothing to push with.
23
+ //
24
+ // ## Everything here is best-effort by construction
25
+ //
26
+ // Except `register`, which the caller needs an answer from, every function
27
+ // resolves to a boolean and throws nothing. A mirror is an observer: a run's
28
+ // correctness cannot depend on whether a report landed, and a Cloud outage
29
+ // must cost a local run nothing but its dashboard page. The caller decides
30
+ // what to retry; this module decides nothing.
31
+
32
+ import { cloudFetch, CloudFlowError, cloudConnection, cloudRunId, isCloudRecord, type CloudConnectionOptions } from './cloud-http.js';
33
+ import type { FinalStep, SnapshotStep } from './cloud-mirror-step.js';
34
+
35
+ /** What registration returns: the run, and the credential that may report on it. */
36
+ export interface MirrorRegistration {
37
+ runId: string;
38
+ /** The run-bound token every later call authenticates with. */
39
+ token: string;
40
+ /** Proves the terminal callback came from this run's executor. */
41
+ callbackToken: string;
42
+ /** The dashboard page for this run, as Cloud named it. */
43
+ runUrl: string;
44
+ /**
45
+ * The deployment that issued the credential, pinned.
46
+ *
47
+ * Load-bearing, not bookkeeping. `cloudConnection` resolves the base URL
48
+ * from the *login store* only while no explicit token is given — and every
49
+ * call after registration gives one. Without pinning it here, a CLI signed
50
+ * in to a staging deployment would register there and then send that
51
+ * deployment's run token to the production default.
52
+ */
53
+ apiUrl: string;
54
+ }
55
+
56
+ export interface MirrorRunSource {
57
+ /** The exact source bytes that ran: YAML/JSON text, or authored `.flow.ts`. */
58
+ workflow: string;
59
+ fileType: 'yaml' | 'ts';
60
+ /** Authored runs only: the input the flow was invoked with. */
61
+ inputs?: unknown;
62
+ /**
63
+ * The Cloud run of the attempt this one continues, for a `flows resume`.
64
+ *
65
+ * Cloud models a resume as a new attempt row — its own hosted resume mints a
66
+ * fresh run id too — so one parked-then-resumed flow is two rows either way.
67
+ * Naming the predecessor is what stops those two rows reading as two
68
+ * unrelated pieces of work: the run page links them, and a reader of the
69
+ * red "Needs review" row can see it was answered.
70
+ */
71
+ resumedFromRunId?: string;
72
+ }
73
+
74
+ /** One lifecycle event, in the vocabulary Cloud's session event stream uses. */
75
+ export interface MirrorEvent {
76
+ eventType: string;
77
+ stepName?: string;
78
+ payload?: Record<string, unknown>;
79
+ }
80
+
81
+ const REGISTER_PATH = '/api/v1/workflows/local-run';
82
+
83
+ /**
84
+ * Register the run and take its credential.
85
+ *
86
+ * The only call here that throws. Everything the mirror does afterwards
87
+ * depends on this receipt, so a caller has to be able to tell "Cloud refused"
88
+ * from "Cloud accepted" — and the CLI turns that difference into one line on
89
+ * stderr rather than a failed run.
90
+ */
91
+ export async function registerLocalRun(
92
+ source: MirrorRunSource,
93
+ options: CloudConnectionOptions = {},
94
+ ): Promise<MirrorRegistration> {
95
+ const result = await cloudFetch(REGISTER_PATH, options, {
96
+ method: 'POST',
97
+ detail: true,
98
+ body: JSON.stringify({
99
+ workflow: source.workflow,
100
+ fileType: source.fileType,
101
+ relayflowVersion: 'v2',
102
+ ...(source.inputs === undefined ? {} : { inputs: source.inputs }),
103
+ ...(source.resumedFromRunId === undefined ? {} : { resumedFromRunId: source.resumedFromRunId }),
104
+ }),
105
+ });
106
+ if (!isCloudRecord(result)) {
107
+ throw new CloudFlowError('invalid_response', 'Cloud did not return a registered local run.');
108
+ }
109
+ const runId = cloudRunId(result['runId']);
110
+ const token = result['accessToken'];
111
+ const callbackToken = result['callbackToken'];
112
+ if (typeof token !== 'string' || token.trim().length === 0
113
+ || typeof callbackToken !== 'string' || callbackToken.length === 0) {
114
+ throw new CloudFlowError('invalid_response', 'Cloud registered the run without a usable credential.');
115
+ }
116
+ const { baseUrl } = cloudConnection(options);
117
+ const runUrl = typeof result['runUrl'] === 'string' && /^https:\/\//u.test(result['runUrl'])
118
+ ? result['runUrl']
119
+ : `${baseUrl}/dashboard/workflow/${encodeURIComponent(runId)}/runner`;
120
+ return { runId, token, callbackToken, runUrl, apiUrl: baseUrl };
121
+ }
122
+
123
+ /** A mirror's authenticated view of one run. Built once, from the registration. */
124
+ export class MirrorClient {
125
+ /** Connection options with the run's credential and its deployment pinned. */
126
+ private readonly bound: CloudConnectionOptions;
127
+
128
+ constructor(
129
+ private readonly registration: MirrorRegistration,
130
+ options: CloudConnectionOptions = {},
131
+ ) {
132
+ this.bound = { ...options, token: registration.token, apiUrl: registration.apiUrl };
133
+ }
134
+
135
+ get runId(): string {
136
+ return this.registration.runId;
137
+ }
138
+
139
+ get runUrl(): string {
140
+ return this.registration.runUrl;
141
+ }
142
+
143
+ /**
144
+ * Every call but registration goes through here. The run token replaces the
145
+ * operator credential, the outcome collapses to a boolean, and nothing —
146
+ * not a refusal, not a timeout, not a thrown transport error — escapes.
147
+ */
148
+ private async post(
149
+ path: string,
150
+ body: string,
151
+ init: { signal?: AbortSignal; timeoutMs?: number } = {},
152
+ ): Promise<boolean> {
153
+ try {
154
+ await cloudFetch(path, {
155
+ ...this.bound,
156
+ ...(init.signal === undefined ? {} : { signal: init.signal }),
157
+ ...(init.timeoutMs === undefined ? {} : { requestTimeoutMs: init.timeoutMs }),
158
+ }, { method: 'POST', body });
159
+ return true;
160
+ } catch {
161
+ return false;
162
+ }
163
+ }
164
+
165
+ async publishEvent(event: MirrorEvent, signal?: AbortSignal): Promise<boolean> {
166
+ return this.post(
167
+ `/api/v1/workflows/runs/${this.registration.runId}/events`,
168
+ JSON.stringify({
169
+ eventType: event.eventType,
170
+ ...(event.stepName === undefined ? {} : { stepName: event.stepName }),
171
+ payload: event.payload ?? {},
172
+ }),
173
+ { ...(signal === undefined ? {} : { signal }) },
174
+ );
175
+ }
176
+
177
+ async publishSnapshot(
178
+ snapshot: { sequence: number; capturedAt: string; truncated?: true; omittedStepCount?: number; steps: SnapshotStep[] },
179
+ limits: { signal?: AbortSignal; timeoutMs?: number } = {},
180
+ ): Promise<boolean> {
181
+ return this.post(
182
+ `/api/v1/workflows/runs/${this.registration.runId}/steps/snapshot`,
183
+ JSON.stringify(snapshot),
184
+ limits,
185
+ );
186
+ }
187
+
188
+ async publishSteps(
189
+ steps: readonly FinalStep[],
190
+ omittedStepCount: number,
191
+ signal?: AbortSignal,
192
+ timeoutMs?: number,
193
+ ): Promise<boolean> {
194
+ return this.post(
195
+ `/api/v1/workflows/runs/${this.registration.runId}/steps`,
196
+ JSON.stringify({ steps, ...(omittedStepCount > 0 ? { omittedStepCount } : {}) }),
197
+ { ...(signal === undefined ? {} : { signal }), ...(timeoutMs === undefined ? {} : { timeoutMs }) },
198
+ );
199
+ }
200
+
201
+ /**
202
+ * Write one object under the run's storage prefix. The keys are the ones the
203
+ * `/logs` route already reads: `runner.log` for the run, and
204
+ * `<stepName>/agent.log` for a step's assembled transcript.
205
+ */
206
+ async putObject(
207
+ key: string,
208
+ bytes: Uint8Array,
209
+ signal?: AbortSignal,
210
+ timeoutMs?: number,
211
+ ): Promise<boolean> {
212
+ if (!/^[A-Za-z0-9][A-Za-z0-9._/-]{0,511}$/u.test(key) || key.includes('..')) return false;
213
+ try {
214
+ await cloudFetch(
215
+ `/api/v1/workflows/runs/${this.registration.runId}/storage/${key}`,
216
+ {
217
+ ...this.bound,
218
+ ...(signal === undefined ? {} : { signal }),
219
+ ...(timeoutMs === undefined ? {} : { requestTimeoutMs: timeoutMs }),
220
+ },
221
+ { method: 'PUT', body: bytes, contentType: 'text/plain' },
222
+ );
223
+ return true;
224
+ } catch {
225
+ return false;
226
+ }
227
+ }
228
+
229
+ /**
230
+ * The terminal status. Authenticated by the callback token rather than the
231
+ * run token, because that is the credential this route checks — and because
232
+ * the run token is revoked by the transition this very call performs.
233
+ */
234
+ async reportTerminal(
235
+ status: 'completed' | 'failed' | 'cancelled',
236
+ result: Record<string, unknown>,
237
+ error?: string,
238
+ signal?: AbortSignal,
239
+ timeoutMs?: number,
240
+ ): Promise<boolean> {
241
+ try {
242
+ await cloudFetch('/api/v1/workflows/callback', {
243
+ ...this.bound,
244
+ ...(signal === undefined ? {} : { signal }),
245
+ ...(timeoutMs === undefined ? {} : { requestTimeoutMs: timeoutMs }),
246
+ }, {
247
+ method: 'POST',
248
+ body: JSON.stringify({
249
+ runId: this.registration.runId,
250
+ callbackToken: this.registration.callbackToken,
251
+ status,
252
+ result,
253
+ ...(error === undefined ? {} : { error }),
254
+ }),
255
+ });
256
+ return true;
257
+ } catch {
258
+ return false;
259
+ }
260
+ }
261
+ }