@xdelivered/emberflow 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +153 -0
  3. package/bin/commands.test.ts +185 -0
  4. package/bin/commands.ts +306 -0
  5. package/bin/emberflow.mjs +38 -0
  6. package/bin/init.test.ts +165 -0
  7. package/bin/init.ts +297 -0
  8. package/bin/runtime.mjs +105 -0
  9. package/bin/runtime.test.ts +167 -0
  10. package/bin/skillTargets.test.ts +108 -0
  11. package/bin/skillTargets.ts +36 -0
  12. package/bin/skillTemplates.test.ts +37 -0
  13. package/bin/tsconfig.json +23 -0
  14. package/dist/bin/commands.d.ts +24 -0
  15. package/dist/bin/commands.js +252 -0
  16. package/dist/bin/init.d.ts +17 -0
  17. package/dist/bin/init.js +241 -0
  18. package/dist/bin/runtime.d.mts +39 -0
  19. package/dist/bin/runtime.mjs +96 -0
  20. package/dist/bin/skillTargets.d.ts +13 -0
  21. package/dist/bin/skillTargets.js +22 -0
  22. package/dist/server/agents/claudeAdapter.d.ts +8 -0
  23. package/dist/server/agents/claudeAdapter.js +190 -0
  24. package/dist/server/agents/claudeParse.d.ts +2 -0
  25. package/dist/server/agents/claudeParse.js +162 -0
  26. package/dist/server/agents/codexAdapter.d.ts +13 -0
  27. package/dist/server/agents/codexAdapter.js +174 -0
  28. package/dist/server/agents/codexParse.d.ts +2 -0
  29. package/dist/server/agents/codexParse.js +74 -0
  30. package/dist/server/agents/detect.d.ts +23 -0
  31. package/dist/server/agents/detect.js +35 -0
  32. package/dist/server/agents/gitScope.d.ts +24 -0
  33. package/dist/server/agents/gitScope.js +95 -0
  34. package/dist/server/agents/modelRejectionHint.d.ts +8 -0
  35. package/dist/server/agents/modelRejectionHint.js +12 -0
  36. package/dist/server/agents/prompt.d.ts +79 -0
  37. package/dist/server/agents/prompt.js +364 -0
  38. package/dist/server/agents/runManager.d.ts +90 -0
  39. package/dist/server/agents/runManager.js +259 -0
  40. package/dist/server/agents/types.d.ts +15 -0
  41. package/dist/server/agents/types.js +1 -0
  42. package/dist/server/apiStore.d.ts +60 -0
  43. package/dist/server/apiStore.js +249 -0
  44. package/dist/server/auth/enforce.d.ts +1 -0
  45. package/dist/server/auth/enforce.js +6 -0
  46. package/dist/server/auth/types.d.ts +1 -0
  47. package/dist/server/auth/types.js +1 -0
  48. package/dist/server/auth/verifiers.d.ts +1 -0
  49. package/dist/server/auth/verifiers.js +4 -0
  50. package/dist/server/authAttach.d.ts +19 -0
  51. package/dist/server/authAttach.js +79 -0
  52. package/dist/server/cli.d.ts +7 -0
  53. package/dist/server/cli.js +804 -0
  54. package/dist/server/client.d.ts +130 -0
  55. package/dist/server/client.js +247 -0
  56. package/dist/server/environments.d.ts +103 -0
  57. package/dist/server/environments.js +486 -0
  58. package/dist/server/flowStore.d.ts +37 -0
  59. package/dist/server/flowStore.js +117 -0
  60. package/dist/server/httpOperations.d.ts +32 -0
  61. package/dist/server/httpOperations.js +62 -0
  62. package/dist/server/index.d.ts +1 -0
  63. package/dist/server/index.js +1022 -0
  64. package/dist/server/infrastructure.d.ts +51 -0
  65. package/dist/server/infrastructure.js +116 -0
  66. package/dist/server/login.d.ts +21 -0
  67. package/dist/server/login.js +44 -0
  68. package/dist/server/mcp.d.ts +1 -0
  69. package/dist/server/mcp.js +182 -0
  70. package/dist/server/migrateFlows.d.ts +8 -0
  71. package/dist/server/migrateFlows.js +25 -0
  72. package/dist/server/mockHandler.d.ts +15 -0
  73. package/dist/server/mockHandler.js +35 -0
  74. package/dist/server/nodesPayload.d.ts +14 -0
  75. package/dist/server/nodesPayload.js +14 -0
  76. package/dist/server/normalizeFlow.d.ts +21 -0
  77. package/dist/server/normalizeFlow.js +48 -0
  78. package/dist/server/openBrowser.d.ts +8 -0
  79. package/dist/server/openBrowser.js +16 -0
  80. package/dist/server/operationResult.d.ts +12 -0
  81. package/dist/server/operationResult.js +26 -0
  82. package/dist/server/pathGuard.d.ts +1 -0
  83. package/dist/server/pathGuard.js +16 -0
  84. package/dist/server/pathSafety.d.ts +20 -0
  85. package/dist/server/pathSafety.js +35 -0
  86. package/dist/server/projectConfig.d.ts +47 -0
  87. package/dist/server/projectConfig.js +61 -0
  88. package/dist/server/projectMode.d.ts +26 -0
  89. package/dist/server/projectMode.js +44 -0
  90. package/dist/server/redact.d.ts +6 -0
  91. package/dist/server/redact.js +37 -0
  92. package/dist/server/runRegistry.d.ts +84 -0
  93. package/dist/server/runRegistry.js +200 -0
  94. package/dist/server/runtime/RuntimeAdapter.d.ts +22 -0
  95. package/dist/server/runtime/RuntimeAdapter.js +1 -0
  96. package/dist/server/runtime/expressAdapter.d.ts +19 -0
  97. package/dist/server/runtime/expressAdapter.js +56 -0
  98. package/dist/server/scenarioTest.d.ts +14 -0
  99. package/dist/server/scenarioTest.js +66 -0
  100. package/dist/server/subflowRunner.d.ts +32 -0
  101. package/dist/server/subflowRunner.js +72 -0
  102. package/dist/server/testRunner.d.ts +70 -0
  103. package/dist/server/testRunner.js +151 -0
  104. package/dist/src/config.d.ts +3 -0
  105. package/dist/src/config.js +2 -0
  106. package/dist/src/engine/authVerify.d.ts +33 -0
  107. package/dist/src/engine/authVerify.js +63 -0
  108. package/dist/src/engine/diagnostics.d.ts +62 -0
  109. package/dist/src/engine/diagnostics.js +148 -0
  110. package/dist/src/engine/executor.d.ts +151 -0
  111. package/dist/src/engine/executor.js +684 -0
  112. package/dist/src/engine/httpError.d.ts +7 -0
  113. package/dist/src/engine/httpError.js +14 -0
  114. package/dist/src/engine/index.d.ts +11 -0
  115. package/dist/src/engine/index.js +11 -0
  116. package/dist/src/engine/output.d.ts +11 -0
  117. package/dist/src/engine/output.js +20 -0
  118. package/dist/src/engine/publish.d.ts +30 -0
  119. package/dist/src/engine/publish.js +95 -0
  120. package/dist/src/engine/registry.d.ts +34 -0
  121. package/dist/src/engine/registry.js +67 -0
  122. package/dist/src/engine/scenarios.d.ts +12 -0
  123. package/dist/src/engine/scenarios.js +19 -0
  124. package/dist/src/engine/schemaCheck.d.ts +4 -0
  125. package/dist/src/engine/schemaCheck.js +34 -0
  126. package/dist/src/engine/trace.d.ts +12 -0
  127. package/dist/src/engine/trace.js +12 -0
  128. package/dist/src/engine/types.d.ts +308 -0
  129. package/dist/src/engine/types.js +1 -0
  130. package/dist/src/engine/validation.d.ts +26 -0
  131. package/dist/src/engine/validation.js +318 -0
  132. package/dist/src/flows/anomaly-flows.d.ts +23 -0
  133. package/dist/src/flows/anomaly-flows.js +151 -0
  134. package/dist/src/flows/city-sweep-flow.d.ts +10 -0
  135. package/dist/src/flows/city-sweep-flow.js +127 -0
  136. package/dist/src/flows/login-flow.d.ts +13 -0
  137. package/dist/src/flows/login-flow.js +145 -0
  138. package/dist/src/flows/pradar-flows.d.ts +5 -0
  139. package/dist/src/flows/pradar-flows.js +375 -0
  140. package/dist/src/flows/weather-flow.d.ts +12 -0
  141. package/dist/src/flows/weather-flow.js +150 -0
  142. package/dist/src/lib/pathParams.d.ts +3 -0
  143. package/dist/src/lib/pathParams.js +6 -0
  144. package/dist/src/nodes/anomaly.d.ts +2 -0
  145. package/dist/src/nodes/anomaly.js +556 -0
  146. package/dist/src/nodes/flow-control.d.ts +7 -0
  147. package/dist/src/nodes/flow-control.js +270 -0
  148. package/dist/src/nodes/index.d.ts +3 -0
  149. package/dist/src/nodes/index.js +20 -0
  150. package/dist/src/nodes/login.d.ts +7 -0
  151. package/dist/src/nodes/login.js +158 -0
  152. package/dist/src/nodes/loops.d.ts +11 -0
  153. package/dist/src/nodes/loops.js +60 -0
  154. package/dist/src/nodes/pradar/index.d.ts +7 -0
  155. package/dist/src/nodes/pradar/index.js +9 -0
  156. package/dist/src/nodes/pradar/logic.d.ts +189 -0
  157. package/dist/src/nodes/pradar/logic.js +370 -0
  158. package/dist/src/nodes/pradar/nodes.d.ts +42 -0
  159. package/dist/src/nodes/pradar/nodes.js +801 -0
  160. package/dist/src/nodes/requireAuth.d.ts +20 -0
  161. package/dist/src/nodes/requireAuth.js +48 -0
  162. package/dist/src/nodes/response.d.ts +8 -0
  163. package/dist/src/nodes/response.js +33 -0
  164. package/dist/src/nodes/weather.d.ts +33 -0
  165. package/dist/src/nodes/weather.js +260 -0
  166. package/package.json +92 -0
  167. package/server/agentRoute.test.ts +157 -0
  168. package/server/agents/__fixtures__/fake-claude-writer.mjs +23 -0
  169. package/server/agents/__fixtures__/fake-claude.mjs +55 -0
  170. package/server/agents/__fixtures__/fake-codex-writer.mjs +27 -0
  171. package/server/agents/__fixtures__/fake-codex.mjs +52 -0
  172. package/server/agents/__fixtures__/fake-version-empty.mjs +3 -0
  173. package/server/agents/__fixtures__/fake-version-fail.mjs +4 -0
  174. package/server/agents/__fixtures__/fake-version-garbage.mjs +4 -0
  175. package/server/agents/__fixtures__/fake-version-good.mjs +4 -0
  176. package/server/agents/__fixtures__/fake-version-hang.mjs +3 -0
  177. package/server/agents/claudeAdapter.test.ts +127 -0
  178. package/server/agents/claudeAdapter.ts +212 -0
  179. package/server/agents/claudeParse.ts +193 -0
  180. package/server/agents/codexAdapter.test.ts +125 -0
  181. package/server/agents/codexAdapter.ts +198 -0
  182. package/server/agents/codexParse.test.ts +58 -0
  183. package/server/agents/codexParse.ts +126 -0
  184. package/server/agents/detect.test.ts +65 -0
  185. package/server/agents/detect.ts +43 -0
  186. package/server/agents/gitScope.test.ts +129 -0
  187. package/server/agents/gitScope.ts +110 -0
  188. package/server/agents/modelRejectionHint.test.ts +30 -0
  189. package/server/agents/modelRejectionHint.ts +14 -0
  190. package/server/agents/prompt.test.ts +613 -0
  191. package/server/agents/prompt.ts +527 -0
  192. package/server/agents/runManager.test.ts +251 -0
  193. package/server/agents/runManager.ts +286 -0
  194. package/server/agents/types.ts +17 -0
  195. package/server/apiMount.test.ts +591 -0
  196. package/server/apiStore.test.ts +324 -0
  197. package/server/apiStore.ts +241 -0
  198. package/server/auth/enforce.test.ts +61 -0
  199. package/server/auth/enforce.ts +6 -0
  200. package/server/auth/types.ts +5 -0
  201. package/server/auth/verifiers.test.ts +37 -0
  202. package/server/auth/verifiers.ts +9 -0
  203. package/server/authAttach.test.ts +175 -0
  204. package/server/authAttach.ts +99 -0
  205. package/server/cli.ts +847 -0
  206. package/server/cliAuth.test.ts +229 -0
  207. package/server/cliCreate.test.ts +131 -0
  208. package/server/cliDoctor.test.ts +326 -0
  209. package/server/cliTest.test.ts +735 -0
  210. package/server/client.ts +314 -0
  211. package/server/demoProject.test.ts +29 -0
  212. package/server/diagnosticsRoute.test.ts +169 -0
  213. package/server/environments.test.ts +620 -0
  214. package/server/environments.ts +603 -0
  215. package/server/environmentsRoute.test.ts +385 -0
  216. package/server/errorWorkflow.test.ts +205 -0
  217. package/server/flowStore.test.ts +84 -0
  218. package/server/flowStore.ts +125 -0
  219. package/server/httpOperations.test.ts +377 -0
  220. package/server/httpOperations.ts +96 -0
  221. package/server/index.ts +1111 -0
  222. package/server/infrastructure.test.ts +154 -0
  223. package/server/infrastructure.ts +161 -0
  224. package/server/infrastructureRoute.test.ts +105 -0
  225. package/server/login.test.ts +153 -0
  226. package/server/login.ts +67 -0
  227. package/server/mcp.ts +278 -0
  228. package/server/migrateFlows.test.ts +55 -0
  229. package/server/migrateFlows.ts +23 -0
  230. package/server/mockHandler.test.ts +138 -0
  231. package/server/mockHandler.ts +52 -0
  232. package/server/mockRun.test.ts +367 -0
  233. package/server/mockServe.test.ts +467 -0
  234. package/server/nodesPayload.test.ts +29 -0
  235. package/server/nodesPayload.ts +26 -0
  236. package/server/normalizeFlow.test.ts +80 -0
  237. package/server/normalizeFlow.ts +59 -0
  238. package/server/openBrowser.test.ts +20 -0
  239. package/server/openBrowser.ts +22 -0
  240. package/server/operationResult.test.ts +67 -0
  241. package/server/operationResult.ts +27 -0
  242. package/server/pathGuard.test.ts +19 -0
  243. package/server/pathGuard.ts +12 -0
  244. package/server/pathSafety.test.ts +38 -0
  245. package/server/pathSafety.ts +33 -0
  246. package/server/projectConfig.test.ts +67 -0
  247. package/server/projectConfig.ts +101 -0
  248. package/server/projectMode.test.ts +106 -0
  249. package/server/projectMode.ts +59 -0
  250. package/server/redact.test.ts +88 -0
  251. package/server/redact.ts +35 -0
  252. package/server/redactEgress.test.ts +281 -0
  253. package/server/runRegistry.ts +270 -0
  254. package/server/runsAuth.test.ts +119 -0
  255. package/server/runtime/RuntimeAdapter.ts +24 -0
  256. package/server/runtime/expressAdapter.test.ts +38 -0
  257. package/server/runtime/expressAdapter.ts +70 -0
  258. package/server/scenarioTest.test.ts +148 -0
  259. package/server/scenarioTest.ts +88 -0
  260. package/server/setupStatus.test.ts +127 -0
  261. package/server/subflowRunner.ts +104 -0
  262. package/server/testRunner.ts +216 -0
  263. package/server/tsconfig.json +20 -0
  264. package/server/workflowTestRoute.test.ts +297 -0
  265. package/src/App.tsx +233 -0
  266. package/src/components/AgentConsole.tsx +461 -0
  267. package/src/components/BranchRulesEditor.tsx +156 -0
  268. package/src/components/CreateModal.tsx +275 -0
  269. package/src/components/Dock.tsx +487 -0
  270. package/src/components/EnvironmentDialog.tsx +569 -0
  271. package/src/components/EnvironmentPicker.tsx +357 -0
  272. package/src/components/EnvironmentsDialog.tsx +144 -0
  273. package/src/components/ExecutionPager.tsx +67 -0
  274. package/src/components/InfraPanel.test.tsx +103 -0
  275. package/src/components/InfraPanel.tsx +171 -0
  276. package/src/components/Inspector.tsx +1182 -0
  277. package/src/components/Json.tsx +50 -0
  278. package/src/components/JsonModal.tsx +52 -0
  279. package/src/components/LogMessage.tsx +61 -0
  280. package/src/components/NodeRunModal.tsx +213 -0
  281. package/src/components/RunLogPanel.tsx +397 -0
  282. package/src/components/RunbookView.tsx +1085 -0
  283. package/src/components/Scenarios.tsx +476 -0
  284. package/src/components/SettingsDialog.tsx +229 -0
  285. package/src/components/Sidebar.tsx +436 -0
  286. package/src/components/StatusBar.tsx +302 -0
  287. package/src/components/Toolbar.tsx +663 -0
  288. package/src/components/WelcomeDialog.test.tsx +107 -0
  289. package/src/components/WelcomeDialog.tsx +412 -0
  290. package/src/components/agentMarkdown.test.tsx +91 -0
  291. package/src/components/agentMarkdown.tsx +158 -0
  292. package/src/components/ui/badge.tsx +31 -0
  293. package/src/components/ui/button.tsx +46 -0
  294. package/src/components/ui/combobox.tsx +114 -0
  295. package/src/components/ui/command.tsx +82 -0
  296. package/src/components/ui/dialog.tsx +73 -0
  297. package/src/components/ui/input.tsx +20 -0
  298. package/src/components/ui/popover.tsx +32 -0
  299. package/src/components/ui/resizable.tsx +44 -0
  300. package/src/components/ui/tabs.tsx +36 -0
  301. package/src/config.ts +4 -0
  302. package/src/engine/authVerify.ts +81 -0
  303. package/src/engine/diagnostics.test.ts +437 -0
  304. package/src/engine/diagnostics.ts +211 -0
  305. package/src/engine/executor.test.ts +1339 -0
  306. package/src/engine/executor.ts +840 -0
  307. package/src/engine/httpError.test.ts +12 -0
  308. package/src/engine/httpError.ts +16 -0
  309. package/src/engine/index.ts +11 -0
  310. package/src/engine/output.ts +21 -0
  311. package/src/engine/publish.test.ts +176 -0
  312. package/src/engine/publish.ts +127 -0
  313. package/src/engine/registry.test.ts +64 -0
  314. package/src/engine/registry.ts +80 -0
  315. package/src/engine/scenarios.test.ts +55 -0
  316. package/src/engine/scenarios.ts +29 -0
  317. package/src/engine/schemaCheck.test.ts +21 -0
  318. package/src/engine/schemaCheck.ts +35 -0
  319. package/src/engine/trace.test.ts +19 -0
  320. package/src/engine/trace.ts +23 -0
  321. package/src/engine/types.test.ts +22 -0
  322. package/src/engine/types.ts +316 -0
  323. package/src/engine/validation.test.ts +314 -0
  324. package/src/engine/validation.ts +354 -0
  325. package/src/flows/anomaly-flows.test.ts +81 -0
  326. package/src/flows/anomaly-flows.ts +202 -0
  327. package/src/flows/city-sweep-flow.ts +131 -0
  328. package/src/flows/flows.test.ts +30 -0
  329. package/src/flows/login-flow.ts +150 -0
  330. package/src/flows/pradar-flows.test.ts +204 -0
  331. package/src/flows/pradar-flows.ts +419 -0
  332. package/src/flows/weather-flow.ts +154 -0
  333. package/src/globals.css +147 -0
  334. package/src/lib/pathParams.test.ts +24 -0
  335. package/src/lib/pathParams.ts +6 -0
  336. package/src/lib/registerLens.test.ts +79 -0
  337. package/src/lib/registerLens.ts +59 -0
  338. package/src/lib/runbookModel.test.ts +61 -0
  339. package/src/lib/runbookModel.ts +290 -0
  340. package/src/lib/runbookProjection.test.ts +417 -0
  341. package/src/lib/runbookProjection.ts +254 -0
  342. package/src/lib/useTailAnchor.ts +53 -0
  343. package/src/lib/utils.ts +7 -0
  344. package/src/main.tsx +13 -0
  345. package/src/nodes/anomaly.test.ts +98 -0
  346. package/src/nodes/anomaly.ts +637 -0
  347. package/src/nodes/effects-scan.test.ts +44 -0
  348. package/src/nodes/flow-control.test.ts +280 -0
  349. package/src/nodes/flow-control.ts +305 -0
  350. package/src/nodes/index.ts +22 -0
  351. package/src/nodes/login.test.ts +81 -0
  352. package/src/nodes/login.ts +186 -0
  353. package/src/nodes/loops.ts +69 -0
  354. package/src/nodes/pradar/index.ts +11 -0
  355. package/src/nodes/pradar/logic.test.ts +288 -0
  356. package/src/nodes/pradar/logic.ts +582 -0
  357. package/src/nodes/pradar/nodes.test.ts +146 -0
  358. package/src/nodes/pradar/nodes.ts +955 -0
  359. package/src/nodes/requireAuth.test.ts +75 -0
  360. package/src/nodes/requireAuth.ts +55 -0
  361. package/src/nodes/response.test.ts +33 -0
  362. package/src/nodes/response.ts +39 -0
  363. package/src/nodes/traceDetail.test.ts +39 -0
  364. package/src/nodes/weather.test.ts +65 -0
  365. package/src/nodes/weather.ts +306 -0
  366. package/src/store/agentClient.test.ts +103 -0
  367. package/src/store/agentClient.ts +131 -0
  368. package/src/store/apiTree.test.ts +17 -0
  369. package/src/store/apiTree.ts +73 -0
  370. package/src/store/builderStore.test.ts +1234 -0
  371. package/src/store/builderStore.ts +1879 -0
  372. package/src/store/infraClient.ts +63 -0
  373. package/src/store/nodeMeta.test.ts +24 -0
  374. package/src/store/nodeMeta.ts +21 -0
  375. package/src/store/persistence.test.ts +15 -0
  376. package/src/store/persistence.ts +54 -0
  377. package/src/store/serverRunner.ts +381 -0
  378. package/src/store/setupClient.ts +57 -0
  379. package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  380. package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  381. package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
  382. package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
  383. package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  384. package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  385. package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
  386. package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
  387. package/studio-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  388. package/studio-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  389. package/studio-dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  390. package/studio-dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  391. package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  392. package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  393. package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
  394. package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
  395. package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  396. package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  397. package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
  398. package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
  399. package/studio-dist/assets/index-DNJwW-hM.css +1 -0
  400. package/studio-dist/assets/index-O26dKRjW.js +65 -0
  401. package/studio-dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  402. package/studio-dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  403. package/studio-dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  404. package/studio-dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  405. package/studio-dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  406. package/studio-dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  407. package/studio-dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  408. package/studio-dist/favicon.svg +1 -0
  409. package/studio-dist/icons.svg +24 -0
  410. package/studio-dist/index.html +14 -0
  411. package/templates/skills/emberflow-basics/SKILL.md +316 -0
  412. package/templates/skills/emberflow-model-process/SKILL.md +209 -0
  413. package/templates/skills/emberflow-new-workflow/SKILL.md +211 -0
  414. package/templates/skills/emberflow-review-workflow/SKILL.md +148 -0
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Client for the infrastructure manifest (GET /infrastructure), reached through
3
+ * the Vite proxy at /api → 127.0.0.1:8092, same-origin as setupClient.ts.
4
+ * Powers the Dock's "Infra" tab.
5
+ *
6
+ * NOTE ON DUPLICATION: the browser bundle can't import from server/, so these
7
+ * types mirror server/infrastructure.ts's InfrastructureManifest. Keep them in
8
+ * sync by hand if the server shape changes.
9
+ */
10
+
11
+ const BASE = '/api';
12
+
13
+ /** Mirrors server/infrastructure.ts's INFRASTRUCTURE_KINDS. */
14
+ export type InfrastructureKind =
15
+ | 'database'
16
+ | 'http-api'
17
+ | 'queue'
18
+ | 'cache'
19
+ | 'email'
20
+ | 'llm'
21
+ | 'auth'
22
+ | 'framework'
23
+ | 'storage'
24
+ | 'other';
25
+
26
+ export interface InfrastructureEvidence {
27
+ file: string;
28
+ note?: string;
29
+ }
30
+
31
+ export interface InfrastructureItem {
32
+ id: string;
33
+ kind: InfrastructureKind;
34
+ name: string;
35
+ evidence: InfrastructureEvidence[];
36
+ suggestedSecretRefs: string[];
37
+ suggestedVars: string[];
38
+ notes?: string;
39
+ }
40
+
41
+ export interface InfrastructureManifest {
42
+ version: number;
43
+ scannedAt?: string;
44
+ greenfield: boolean;
45
+ summary?: string;
46
+ items: InfrastructureItem[];
47
+ }
48
+
49
+ /** The GET /infrastructure response: `{present:false}` or `{present:true, manifest}`. */
50
+ export type InfrastructureResponse =
51
+ | { present: false }
52
+ | { present: true; manifest: InfrastructureManifest };
53
+
54
+ /** GET /infrastructure — returns null when the runner is unreachable. */
55
+ export async function fetchInfrastructure(): Promise<InfrastructureResponse | null> {
56
+ try {
57
+ const response = await fetch(`${BASE}/infrastructure`);
58
+ if (!response.ok) return null;
59
+ return (await response.json()) as InfrastructureResponse;
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
@@ -0,0 +1,24 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { fetchNodeMeta } from './nodeMeta';
3
+
4
+ afterEach(() => vi.unstubAllGlobals());
5
+
6
+ describe('fetchNodeMeta', () => {
7
+ it('returns the runner node list', async () => {
8
+ vi.stubGlobal('fetch', vi.fn(async () => ({
9
+ ok: true,
10
+ json: async () => ({ nodes: [{ type: 'X', label: 'X', source: 'fn' }] }),
11
+ })));
12
+ expect(await fetchNodeMeta()).toEqual([{ type: 'X', label: 'X', source: 'fn' }]);
13
+ });
14
+
15
+ it('returns [] when the runner is unreachable', async () => {
16
+ vi.stubGlobal('fetch', vi.fn(async () => { throw new Error('down'); }));
17
+ expect(await fetchNodeMeta()).toEqual([]);
18
+ });
19
+
20
+ it('returns [] on a non-ok response', async () => {
21
+ vi.stubGlobal('fetch', vi.fn(async () => ({ ok: false })));
22
+ expect(await fetchNodeMeta()).toEqual([]);
23
+ });
24
+ });
@@ -0,0 +1,21 @@
1
+ import type { NodeDefinition } from '../engine';
2
+
3
+ /** A runner node definition plus its implementation source (for display). */
4
+ export type NodeMeta = NodeDefinition & { source?: string };
5
+
6
+ /**
7
+ * Fetch the runner's node metadata (GET /api/nodes, same-origin via the
8
+ * studio proxy). Returns [] on any failure — the studio still has its
9
+ * bundled built-in nodes; consumer nodes simply won't appear until the
10
+ * runner is reachable.
11
+ */
12
+ export async function fetchNodeMeta(): Promise<NodeMeta[]> {
13
+ try {
14
+ const res = await fetch('/api/nodes');
15
+ if (!res.ok) return [];
16
+ const body = (await res.json()) as { nodes?: NodeMeta[] };
17
+ return Array.isArray(body.nodes) ? body.nodes : [];
18
+ } catch {
19
+ return [];
20
+ }
21
+ }
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseFlow, serializeFlow } from './persistence';
3
+ import { createLoginFlow } from '../flows/login-flow';
4
+
5
+ describe('flow persistence', () => {
6
+ it('round-trips a flow through JSON', () => {
7
+ const flow = createLoginFlow();
8
+ expect(parseFlow(serializeFlow(flow))).toEqual(flow);
9
+ });
10
+
11
+ it('rejects garbage', () => {
12
+ expect(() => parseFlow('{"nope": true}')).toThrow('Invalid flow JSON');
13
+ expect(() => parseFlow('not json')).toThrow();
14
+ });
15
+ });
@@ -0,0 +1,54 @@
1
+ import type { WorkflowDefinition } from '../engine';
2
+
3
+ // Versioned: bump when the format changes incompatibly (stale saves are dropped).
4
+ const WORKSPACE_KEY = 'emberflow.workspace.v1';
5
+
6
+ export interface Workspace {
7
+ flows: WorkflowDefinition[];
8
+ activeId: string;
9
+ }
10
+
11
+ export function serializeFlow(flow: WorkflowDefinition): string {
12
+ return JSON.stringify(flow, null, 2);
13
+ }
14
+
15
+ export function parseFlow(json: string): WorkflowDefinition {
16
+ const parsed: unknown = JSON.parse(json);
17
+ if (
18
+ parsed === null ||
19
+ typeof parsed !== 'object' ||
20
+ typeof (parsed as WorkflowDefinition).id !== 'string' ||
21
+ !Array.isArray((parsed as WorkflowDefinition).nodes) ||
22
+ !Array.isArray((parsed as WorkflowDefinition).edges)
23
+ ) {
24
+ throw new Error('Invalid flow JSON');
25
+ }
26
+ return parsed as WorkflowDefinition;
27
+ }
28
+
29
+ export function saveWorkspace(workspace: Workspace): void {
30
+ if (typeof localStorage === 'undefined') return;
31
+ localStorage.setItem(WORKSPACE_KEY, JSON.stringify(workspace));
32
+ }
33
+
34
+ export function loadWorkspace(): Workspace | null {
35
+ if (typeof localStorage === 'undefined') return null;
36
+ const json = localStorage.getItem(WORKSPACE_KEY);
37
+ if (json === null) return null;
38
+ try {
39
+ const parsed: unknown = JSON.parse(json);
40
+ if (
41
+ parsed === null ||
42
+ typeof parsed !== 'object' ||
43
+ !Array.isArray((parsed as Workspace).flows) ||
44
+ typeof (parsed as Workspace).activeId !== 'string'
45
+ ) {
46
+ return null;
47
+ }
48
+ const flows = (parsed as Workspace).flows.map((f) => parseFlow(JSON.stringify(f)));
49
+ if (flows.length === 0) return null;
50
+ return { flows, activeId: (parsed as Workspace).activeId };
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
@@ -0,0 +1,381 @@
1
+ import type { HttpTrigger, LogLine, NodeExecutionSample, NodeRunState, WorkflowDefinition, WorkflowRun } from '../engine';
2
+
3
+ /**
4
+ * Client for the local runner (server/index.ts), reached through the Vite
5
+ * proxy at /api → 127.0.0.1:8092. Event names/payloads mirror ExecutorEvents.
6
+ */
7
+
8
+ const BASE = '/api';
9
+
10
+ /** Tags a finished run that was fired by an error-handler op (server/runRegistry.ts's
11
+ * fireErrorWorkflow) — carries the op id that triggered it. */
12
+ export interface ErrorHandlerTag {
13
+ firedBy: string;
14
+ }
15
+
16
+ export interface ServerRunHandlers {
17
+ onNodeState(nodeId: string, state: NodeRunState): void;
18
+ onLog(line: LogLine): void;
19
+ onFinished(run: WorkflowRun, errorHandler?: ErrorHandlerTag): void;
20
+ onError(message: string): void;
21
+ }
22
+
23
+ /** Result of a health check: `online` mirrors the old boolean-only contract;
24
+ * `mock` reflects the runner's `/healthz` `mock` field (true when it's
25
+ * serving EMBERFLOW_MOCK responses instead of live execution). Both are
26
+ * false when the runner can't be reached at all. */
27
+ export interface RunnerHealth {
28
+ online: boolean;
29
+ mock: boolean;
30
+ }
31
+
32
+ export async function runnerHealthy(): Promise<RunnerHealth> {
33
+ try {
34
+ const response = await fetch(`${BASE}/healthz`, { signal: AbortSignal.timeout(1500) });
35
+ if (!response.ok) return { online: false, mock: false };
36
+ const body = (await response.json().catch(() => ({}))) as { mock?: unknown };
37
+ return { online: true, mock: body.mock === true };
38
+ } catch {
39
+ return { online: false, mock: false };
40
+ }
41
+ }
42
+
43
+ /** One operation's on-disk path + http metadata, from the runner's ApiStore. */
44
+ export interface OperationMeta {
45
+ id: string;
46
+ name: string;
47
+ path: string;
48
+ http?: HttpTrigger;
49
+ }
50
+
51
+ /** The runner's workflow set: full flow definitions plus per-operation path/http metadata. */
52
+ export interface WorkflowsPayload {
53
+ flows: WorkflowDefinition[];
54
+ operations: OperationMeta[];
55
+ }
56
+
57
+ /** Fetch the runner's workflow set (flows + operation path/http metadata). Returns null on any failure. */
58
+ export async function fetchWorkflows(): Promise<WorkflowsPayload | null> {
59
+ try {
60
+ const response = await fetch(`${BASE}/workflows`, { signal: AbortSignal.timeout(2500) });
61
+ if (!response.ok) return null;
62
+ const body = (await response.json()) as { flows?: WorkflowDefinition[]; operations?: OperationMeta[] };
63
+ if (!Array.isArray(body.flows)) return null;
64
+ return { flows: body.flows, operations: Array.isArray(body.operations) ? body.operations : [] };
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ /** Fetch runner-recorded execution samples for a node. Returns [] on any failure. */
71
+ export async function fetchSamples(nodeId: string): Promise<NodeExecutionSample[]> {
72
+ try {
73
+ const response = await fetch(`${BASE}/samples?nodeId=${encodeURIComponent(nodeId)}`, {
74
+ signal: AbortSignal.timeout(2500),
75
+ });
76
+ if (!response.ok) return [];
77
+ const { samples } = (await response.json()) as { samples: NodeExecutionSample[] };
78
+ return Array.isArray(samples) ? samples : [];
79
+ } catch {
80
+ return [];
81
+ }
82
+ }
83
+
84
+ /** PUT a flow to the runner. Returns false on any failure. The id is
85
+ * URL-encoded so operations whose id contains a slash (the apis-tree path,
86
+ * e.g. "util/echo-body") match the `/workflows/:id` route instead of 404ing. */
87
+ export async function putWorkflow(flow: WorkflowDefinition): Promise<boolean> {
88
+ try {
89
+ const response = await fetch(`${BASE}/workflows/${encodeURIComponent(flow.id)}`, {
90
+ method: 'PUT',
91
+ headers: { 'content-type': 'application/json' },
92
+ body: JSON.stringify(flow),
93
+ });
94
+ return response.ok;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ /** Result of a create-operation attempt: `ok: false` always carries a message
101
+ * the caller can show (e.g. a 409 collision or a network failure) — a
102
+ * creation failure must never be silent. */
103
+ export interface CreateOperationResult {
104
+ ok: boolean;
105
+ error?: string;
106
+ }
107
+
108
+ /**
109
+ * Create a brand-new operation at an explicit `apis/` path. Unlike `putWorkflow`
110
+ * (which resolves an EXISTING op's path, defaulting unknown ids to `default/<id>`),
111
+ * a new op with a nested path-style id needs to land at that exact path — this
112
+ * calls the runner's `POST /operations { flow, path }`. Never overwrites: the
113
+ * runner 409s when an operation already exists at `path`, and that error
114
+ * message is surfaced here rather than swallowed.
115
+ */
116
+ export async function createOperationOnServer(
117
+ flow: WorkflowDefinition,
118
+ path: string,
119
+ ): Promise<CreateOperationResult> {
120
+ try {
121
+ const response = await fetch(`${BASE}/operations`, {
122
+ method: 'POST',
123
+ headers: { 'content-type': 'application/json' },
124
+ body: JSON.stringify({ flow, path }),
125
+ });
126
+ if (response.ok) return { ok: true };
127
+ const body = await response.json().catch(() => undefined) as { error?: string } | undefined;
128
+ return { ok: false, error: body?.error ?? `Request failed with status ${response.status}` };
129
+ } catch (err) {
130
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
131
+ }
132
+ }
133
+
134
+ /** Delete an operation by its flow id (removes its .json + .scenarios sidecar). */
135
+ export async function deleteWorkflowOnServer(id: string): Promise<{ ok: boolean; error?: string }> {
136
+ try {
137
+ const response = await fetch(`${BASE}/workflows/${encodeURIComponent(id)}`, { method: 'DELETE' });
138
+ if (response.status === 204 || response.ok) return { ok: true };
139
+ return { ok: false, error: `Delete failed with status ${response.status}` };
140
+ } catch (err) {
141
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
142
+ }
143
+ }
144
+
145
+ /** Mirrors server/environments.ts EnvAuth — names/refs only, values never cross the wire. */
146
+ export interface EnvAuth {
147
+ attach: { as: 'cookie' | 'header'; name: string; secretRef: string; prefix?: string };
148
+ login?: {
149
+ request: { method: string; url: string; headers?: Record<string, string>; bodyRef?: string };
150
+ capture:
151
+ | { from: 'set-cookie'; cookieName?: string }
152
+ | { from: 'json'; path: string }
153
+ | { from: 'header'; name: string };
154
+ };
155
+ }
156
+
157
+ /** Summary of a runner environment — key names only, values never cross the wire. */
158
+ export interface EnvironmentSummary {
159
+ name: string;
160
+ protected: boolean;
161
+ varKeys: string[];
162
+ secretKeys: string[];
163
+ /** Login-auth status (booleans only — secret values never cross the wire). Absent for envs with no auth config. */
164
+ auth?: { configured: boolean; authenticated: boolean; secretRef?: string; config?: EnvAuth };
165
+ }
166
+
167
+ export interface EnvironmentList {
168
+ defaultEnvironment: string;
169
+ environments: EnvironmentSummary[];
170
+ /** False when the runner synthesized its bare "local" fallback (no
171
+ * emberflow.environments.json) — the studio treats that as "no
172
+ * environments yet" rather than showing the synthetic entry. */
173
+ configured?: boolean;
174
+ }
175
+
176
+ /** Fetch the runner's environments. Returns null on any failure (runner offline). */
177
+ export async function listEnvironments(): Promise<EnvironmentList | null> {
178
+ try {
179
+ const response = await fetch(`${BASE}/environments`, { signal: AbortSignal.timeout(2500) });
180
+ if (!response.ok) return null;
181
+ const data = (await response.json()) as EnvironmentList;
182
+ return data && Array.isArray(data.environments) ? data : null;
183
+ } catch {
184
+ return null;
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Fire the environment's configured login request; the runner persists the
190
+ * captured credential into `emberflow.environments.json` under that env's
191
+ * secrets. Never returns the credential — callers should re-fetch
192
+ * environments afterward to observe the updated `auth.authenticated` flag.
193
+ */
194
+ /**
195
+ * Flip the runner's serving mode. 'mock' answers mounted endpoints from
196
+ * scenario expectations (no nodes, no auth); 'real' executes them. Takes
197
+ * effect immediately for every consumer of the mounted API.
198
+ */
199
+ export async function setServingMode(mode: 'real' | 'mock'): Promise<void> {
200
+ const response = await fetch(`${BASE}/serving`, {
201
+ method: 'POST',
202
+ headers: { 'Content-Type': 'application/json' },
203
+ body: JSON.stringify({ mode }),
204
+ });
205
+ if (!response.ok) {
206
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
207
+ throw new Error(body.error ?? `Failed to set serving mode (HTTP ${response.status})`);
208
+ }
209
+ }
210
+
211
+ export async function loginEnvironment(name: string): Promise<void> {
212
+ const response = await fetch(`${BASE}/environments/${encodeURIComponent(name)}/login`, { method: 'POST' });
213
+ if (!response.ok) {
214
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
215
+ throw new Error(body.error ?? `Login failed for environment "${name}" (HTTP ${response.status})`);
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Set a secret's value on an environment. The value is sent once, over this
221
+ * PUT, and never appears in any other route, log, or return value — the
222
+ * runner responds 204 with an empty body on success.
223
+ */
224
+ export async function setEnvironmentSecret(name: string, key: string, value: string): Promise<void> {
225
+ const response = await fetch(
226
+ `${BASE}/environments/${encodeURIComponent(name)}/secrets/${encodeURIComponent(key)}`,
227
+ { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ value }) },
228
+ );
229
+ if (!response.ok) {
230
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
231
+ throw new Error(body.error ?? `Failed to set secret "${key}" for environment "${name}" (HTTP ${response.status})`);
232
+ }
233
+ }
234
+
235
+ /** Delete a secret from an environment. The runner responds 204 with an empty body on success. */
236
+ export async function deleteEnvironmentSecret(name: string, key: string): Promise<void> {
237
+ const response = await fetch(
238
+ `${BASE}/environments/${encodeURIComponent(name)}/secrets/${encodeURIComponent(key)}`,
239
+ { method: 'DELETE' },
240
+ );
241
+ if (!response.ok) {
242
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
243
+ throw new Error(
244
+ body.error ?? `Failed to delete secret "${key}" for environment "${name}" (HTTP ${response.status})`,
245
+ );
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Set (or, with `null`, clear) an environment's login-auth config. The
251
+ * runner responds 204 with an empty body on success; secret values are
252
+ * referenced by name only (`secretRef`) and never included here.
253
+ */
254
+ export async function setEnvironmentAuth(name: string, auth: EnvAuth | null): Promise<void> {
255
+ const response = await fetch(`${BASE}/environments/${encodeURIComponent(name)}/auth`, {
256
+ method: 'PUT',
257
+ headers: { 'content-type': 'application/json' },
258
+ body: JSON.stringify(auth),
259
+ });
260
+ if (!response.ok) {
261
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
262
+ throw new Error(body.error ?? `Failed to set auth for environment "${name}" (HTTP ${response.status})`);
263
+ }
264
+ }
265
+
266
+ /** Mirrors server/testRunner.ts's SkipReason. */
267
+ export type ScenarioTestSkipReason = 'no expect' | 'empty expect';
268
+
269
+ /** Mirrors server/testRunner.ts's ScenarioResult — one scenario's outcome
270
+ * from POST /workflows/:id/test. */
271
+ export interface ScenarioTestResult {
272
+ opId: string;
273
+ scenario: string;
274
+ status: 'passed' | 'failed' | 'skipped';
275
+ /** Present only when status === 'failed' — evaluateExpectation's failure strings. */
276
+ failures?: string[];
277
+ /** Present only when status === 'skipped'. */
278
+ reason?: ScenarioTestSkipReason;
279
+ }
280
+
281
+ /** Mirrors server/testRunner.ts's TestReport. */
282
+ export interface ScenarioTestReport {
283
+ results: ScenarioTestResult[];
284
+ passed: number;
285
+ failed: number;
286
+ skipped: number;
287
+ }
288
+
289
+ /**
290
+ * Run an operation's scenario suite on the runner (server/testRunner.ts —
291
+ * the studio never duplicates expectation-evaluation logic). The id is
292
+ * URL-encoded so ids containing a slash (the apis-tree path) match the
293
+ * `/workflows/:id/test` route instead of 404ing.
294
+ */
295
+ export async function testWorkflow(id: string, environment?: string): Promise<ScenarioTestReport> {
296
+ const response = await fetch(`${BASE}/workflows/${encodeURIComponent(id)}/test`, {
297
+ method: 'POST',
298
+ headers: { 'content-type': 'application/json' },
299
+ body: JSON.stringify({ environment }),
300
+ });
301
+ if (!response.ok) {
302
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
303
+ throw new Error(body.error ?? `Test run failed for "${id}" (HTTP ${response.status})`);
304
+ }
305
+ return (await response.json()) as ScenarioTestReport;
306
+ }
307
+
308
+ /** Environment/safety options threaded into a server run. */
309
+ export interface ServerRunOptions {
310
+ /** Scenario name for the runner to resolve server-side (mock runs merge the
311
+ * scenario's mocks over the op-level map; harmless on real runs). */
312
+ scenarioName?: string;
313
+ environment?: string;
314
+ safeMode?: boolean;
315
+ /** Required to equal `environment` when disabling safe mode on a protected env. */
316
+ confirm?: string;
317
+ }
318
+
319
+ export async function startServerRun(
320
+ flow: WorkflowDefinition,
321
+ mode: 'run' | 'step',
322
+ pins?: Record<string, unknown>,
323
+ input?: Record<string, unknown>,
324
+ options?: ServerRunOptions,
325
+ ): Promise<string> {
326
+ const response = await fetch(`${BASE}/runs`, {
327
+ method: 'POST',
328
+ headers: { 'content-type': 'application/json' },
329
+ body: JSON.stringify({ flow, mode, pins, input, ...options }),
330
+ });
331
+ if (!response.ok) {
332
+ const body = (await response.json().catch(() => ({}))) as { error?: string };
333
+ throw new Error(body.error ?? `Runner rejected the run (HTTP ${response.status})`);
334
+ }
335
+ const { runId } = (await response.json()) as { runId: string };
336
+ return runId;
337
+ }
338
+
339
+ export async function stepServerRun(runId: string): Promise<boolean> {
340
+ const response = await fetch(`${BASE}/runs/${runId}/step`, { method: 'POST' });
341
+ if (!response.ok) throw new Error(`Step failed (HTTP ${response.status})`);
342
+ const { done } = (await response.json()) as { done: boolean };
343
+ return done;
344
+ }
345
+
346
+ export async function cancelServerRun(runId: string): Promise<void> {
347
+ await fetch(`${BASE}/runs/${runId}/cancel`, { method: 'POST' }).catch(() => undefined);
348
+ }
349
+
350
+ /** Subscribe to a run's SSE stream. Returns an unsubscribe function. */
351
+ export function subscribeServerRun(runId: string, handlers: ServerRunHandlers): () => void {
352
+ const source = new EventSource(`${BASE}/runs/${runId}/events`);
353
+
354
+ source.addEventListener('nodeState', (event) => {
355
+ const data = JSON.parse((event as MessageEvent).data) as {
356
+ nodeId: string;
357
+ state: NodeRunState;
358
+ };
359
+ handlers.onNodeState(data.nodeId, data.state);
360
+ });
361
+ source.addEventListener('log', (event) => {
362
+ const data = JSON.parse((event as MessageEvent).data) as { line: LogLine };
363
+ handlers.onLog(data.line);
364
+ });
365
+ source.addEventListener('finished', (event) => {
366
+ const data = JSON.parse((event as MessageEvent).data) as {
367
+ run: WorkflowRun;
368
+ errorHandler?: ErrorHandlerTag;
369
+ };
370
+ handlers.onFinished(data.run, data.errorHandler);
371
+ source.close();
372
+ });
373
+ source.onerror = () => {
374
+ // EventSource retries transient errors itself; only report when closed.
375
+ if (source.readyState === EventSource.CLOSED) {
376
+ handlers.onError('Lost connection to the runner event stream');
377
+ }
378
+ };
379
+
380
+ return () => source.close();
381
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Client for the first-run onboarding aggregate (GET /setup-status), reached
3
+ * through the Vite proxy at /api → 127.0.0.1:8092, same-origin as
4
+ * agentClient.ts/serverRunner.ts. Powers the Welcome checklist.
5
+ *
6
+ * NOTE ON DUPLICATION: the browser bundle can't import from server/, so
7
+ * SetupStatus mirrors the shape server/index.ts's /setup-status returns. Keep
8
+ * it in sync by hand if the server payload changes.
9
+ */
10
+
11
+ import type { DetectedAgent } from './agentClient';
12
+
13
+ const BASE = '/api';
14
+
15
+ export interface SetupStatus {
16
+ agents: DetectedAgent[];
17
+ environments: {
18
+ configured: boolean;
19
+ count: number;
20
+ protectedCount: number;
21
+ anyAuthConfigured: boolean;
22
+ };
23
+ skills: { claude: boolean; codex: boolean };
24
+ language: string;
25
+ ops: { count: number; onlyHello: boolean };
26
+ servingMode: 'real' | 'mock';
27
+ /** Phase 3 fills scannedAt/itemCount and flips `present`. */
28
+ infrastructure: { present: boolean; scannedAt?: string; itemCount?: number };
29
+ }
30
+
31
+ /**
32
+ * Progress across the Welcome checklist's rows, mirrored from
33
+ * WelcomeChecklist's per-row status logic. Powers the StatusBar setup chip;
34
+ * keep in step if rows are added or their completion rules change.
35
+ */
36
+ export function setupProgress(status: SetupStatus): { done: number; total: number } {
37
+ const rows = [
38
+ status.agents.length > 0,
39
+ status.environments.configured,
40
+ status.environments.configured && status.environments.anyAuthConfigured,
41
+ status.skills.claude || status.skills.codex,
42
+ status.infrastructure.present,
43
+ status.ops.count > 1,
44
+ ];
45
+ return { done: rows.filter(Boolean).length, total: rows.length };
46
+ }
47
+
48
+ /** GET /setup-status — returns null when the runner is unreachable. */
49
+ export async function fetchSetupStatus(): Promise<SetupStatus | null> {
50
+ try {
51
+ const response = await fetch(`${BASE}/setup-status`);
52
+ if (!response.ok) return null;
53
+ return (await response.json()) as SetupStatus;
54
+ } catch {
55
+ return null;
56
+ }
57
+ }