@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,308 @@
1
+ export type FieldType = 'string' | 'number' | 'boolean' | 'enum' | 'datetime' | 'object' | 'array';
2
+ export interface FieldDefinition {
3
+ name: string;
4
+ type: FieldType;
5
+ required?: boolean;
6
+ enumValues?: string[];
7
+ description?: string;
8
+ }
9
+ export interface SchemaDefinition {
10
+ fields: FieldDefinition[];
11
+ }
12
+ export interface NodeDefinition {
13
+ type: string;
14
+ label: string;
15
+ description?: string;
16
+ /**
17
+ * Plain-language one-liner for non-developers, shown in the simple register
18
+ * (runbook idle text, simple Inspector description) instead of `description`,
19
+ * which may lead with mechanism (PORT NOTE, file paths, implementation
20
+ * detail). Falls back to the first sentence of `description` when absent.
21
+ */
22
+ simpleDescription?: string;
23
+ category?: string;
24
+ inputSchema?: SchemaDefinition;
25
+ outputSchema?: SchemaDefinition;
26
+ configSchema?: SchemaDefinition;
27
+ icon?: string;
28
+ tags?: string[];
29
+ /**
30
+ * Side-effect class. 'mutation' nodes write state someone else can observe
31
+ * (DB writes, emails, external POSTs that create/change resources) and are
32
+ * dry-run under safe mode. Absent = 'read' (default).
33
+ */
34
+ effects?: 'read' | 'mutation';
35
+ /**
36
+ * What kind of work this node does, for the runbook's technical register. Pure
37
+ * documentation — the engine ignores it. 'db' = queries Postgres, 'http' =
38
+ * calls an external service over HTTP, 'llm' = calls a language model,
39
+ * 'compute' = pure in-process logic. Absent when unknown (an absent badge is
40
+ * honest; a wrong one is not).
41
+ */
42
+ traceKind?: 'db' | 'http' | 'llm' | 'compute';
43
+ /**
44
+ * A short, STATIC technical descriptor of the concrete call this node makes,
45
+ * for the runbook's technical register (the trace badge hover card). Pure
46
+ * documentation — the engine ignores it. For 'db' the query shape (e.g.
47
+ * 'SELECT … FROM projects JOIN users … WHERE p.id = $1'); for 'http' the
48
+ * method + endpoint (e.g. 'POST https://oauth2.googleapis.com/token'); for
49
+ * 'llm' the provider + model (e.g. 'openrouter.ai · x-ai/grok-4.3:online').
50
+ * Describes the mechanism, NOT runtime values. Absent on 'compute' nodes and
51
+ * whenever the target is dynamic enough that no honest static shape exists.
52
+ */
53
+ traceDetail?: string;
54
+ }
55
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
56
+ /** Outcome of running a child workflow synchronously via a Subflow node. */
57
+ export interface SubflowResult {
58
+ status: 'succeeded' | 'failed';
59
+ output?: unknown;
60
+ error?: string;
61
+ }
62
+ export interface NodeExecutionContext {
63
+ input: Record<string, unknown>;
64
+ config: Record<string, unknown>;
65
+ /** Runner-supplied secrets; empty in browser execution. */
66
+ secrets: Record<string, string>;
67
+ /** Non-secret environment values (API base URLs, seed ids, flags). Empty in browser execution. */
68
+ vars: Record<string, string>;
69
+ /** The environment name this run targets (e.g. 'prod'); undefined in browser/in-tab runs. */
70
+ environment?: string;
71
+ /** When true, mutation nodes must dry-run their side effects instead of executing them. */
72
+ safeMode: boolean;
73
+ /** The payload this run was invoked with (emberflow.run(name, input)). */
74
+ runInput: Record<string, unknown>;
75
+ log: (level: LogLevel, message: string) => void;
76
+ /**
77
+ * Runs a child workflow to completion and returns its collected output.
78
+ * Provided by the host (browser store / server run registry); absent when the
79
+ * run has no way to look up other workflows, in which case a Subflow node
80
+ * fails with a clear message.
81
+ */
82
+ runSubflow?: (workflowId: string, input: Record<string, unknown>) => Promise<SubflowResult>;
83
+ }
84
+ export type NodeImplementation = (ctx: NodeExecutionContext) => Promise<unknown>;
85
+ export interface FieldMapping {
86
+ sourceNodeId: string;
87
+ /** Dot path into the source node's output. '$' means the entire output. */
88
+ sourceField: string;
89
+ transform?: string;
90
+ }
91
+ export interface WorkflowNode {
92
+ id: string;
93
+ type: string;
94
+ label: string;
95
+ position: {
96
+ x: number;
97
+ y: number;
98
+ };
99
+ config: Record<string, unknown>;
100
+ inputMap?: Record<string, FieldMapping>;
101
+ /**
102
+ * Fail-soft flag. When true, this node throwing marks it `failed` but does
103
+ * NOT abort the run: the cursor continues, so independent branches still run
104
+ * and the run can finish `succeeded`. The failed node produces no output, so
105
+ * its downstream consumers become unreachable (dead edges) and skip — exactly
106
+ * like a live "mirror" step whose failure must not break the deterministic
107
+ * path beside it. A non-optional node's failure still aborts the run.
108
+ *
109
+ * Applies to standard node execution. A ForEach region's own setup failure is
110
+ * NOT fail-soft (the flag is ignored there); mark ordinary/Subflow nodes.
111
+ */
112
+ optional?: boolean;
113
+ /**
114
+ * Retry the implementation call on throw. `maxTries` is the total number of
115
+ * attempts including the first (so `maxTries: 3` means up to 2 retries).
116
+ * `waitMs` (default 0) is a fixed delay between attempts. Only the
117
+ * `implementation({...})` call is retried — config/input resolution runs
118
+ * once, and only the final attempt's outcome is recorded (state, trace,
119
+ * fail-soft). A non-object value or `maxTries < 1` is treated as absent.
120
+ */
121
+ retry?: {
122
+ maxTries: number;
123
+ waitMs?: number;
124
+ };
125
+ /** Builder-owned extras (e.g. pinnedOutput). The engine never reads this. */
126
+ metadata?: Record<string, unknown>;
127
+ }
128
+ export interface WorkflowEdge {
129
+ id: string;
130
+ source: string;
131
+ target: string;
132
+ sourceHandle?: string;
133
+ targetHandle?: string;
134
+ label?: string;
135
+ }
136
+ export interface ScenarioDefinition {
137
+ id: string;
138
+ name: string;
139
+ description?: string;
140
+ /** Run payload, same shape as StartRunOptions.input. For an operation (a flow
141
+ * with `http`), this is the request shape `{ params?, query?, body?, headers? }`
142
+ * — an in-studio "Run" of a scenario passes this object as `input` through the
143
+ * same `RunRegistry.create` path a live HTTP request builds and passes, so the
144
+ * two are parity-equivalent (see server/httpOperations.test.ts). For a non-HTTP
145
+ * (internal) flow, `input` is used as-is — unchanged behavior. */
146
+ input: Record<string, unknown>;
147
+ /** Optional assertion the scenario's run must satisfy. Consumed by `emberflow
148
+ * test` (evaluateExpectation in server/scenarioTest.ts) and mock mode; a
149
+ * scenario without `expect` is a fixture only (not assertable). */
150
+ expect?: ScenarioExpectation;
151
+ /** nodeId -> canned output (verbatim, same shape the implementation would return).
152
+ * Consulted only when the run has `mockRun: true`; merges over the operation-level
153
+ * mocks map (scenario wins per nodeId). Plumbing (reading/merging these into a run)
154
+ * is a later increment — this is type-only for now. */
155
+ mocks?: Record<string, unknown>;
156
+ }
157
+ /** Assertion checked against a scenario's run + its flow's response mapping.
158
+ * `body` is a deep-subset match (see evaluateExpectation): every expected key
159
+ * must match recursively, arrays compare index-wise on the expected prefix,
160
+ * extra actual keys are fine, and `null` matches only `null`. */
161
+ export interface ScenarioExpectation {
162
+ /** Expected HTTP status of the extracted response (default response is 200). */
163
+ status?: number;
164
+ /** Expected response body, matched as a deep subset of the actual body. */
165
+ body?: unknown;
166
+ /** Node ids expected to have run to `succeeded`. */
167
+ executedNodes?: string[];
168
+ }
169
+ /** An inheritable auth policy: scheme + secret ref + optional named verifier.
170
+ * Set at the API/folder level via `_meta.json` (inherited by descendants) or
171
+ * overridden per-operation via `HttpTrigger.auth`. Lives here (not in
172
+ * server/auth/types.ts) because src/ must not import from server/; server/auth/types.ts
173
+ * re-exports this type. */
174
+ export interface AuthPolicy {
175
+ scheme: 'bearer' | 'apiKey';
176
+ /** Name of the secret (in the run environment's secrets) holding the expected token/key. */
177
+ secretRef: string;
178
+ /** Optional named custom verifier; when set, overrides the built-in scheme verifier. */
179
+ verify?: string;
180
+ /** Header to read for apiKey (default 'x-api-key'); bearer always reads Authorization. */
181
+ header?: string;
182
+ }
183
+ /** HTTP trigger metadata for an operation. Routing is a later increment; this
184
+ * increment only stores/round-trips it. */
185
+ export interface HttpTrigger {
186
+ method: string;
187
+ path: string;
188
+ inputSchema?: unknown;
189
+ /** Effective auth policy for this operation. 'none' makes it explicitly
190
+ * public (overriding any inherited _meta.json policy); 'inherit' (or
191
+ * absent) defers to the nearest ancestor _meta.json's policy, if any. */
192
+ auth?: AuthPolicy | 'none' | 'inherit';
193
+ }
194
+ export interface WorkflowDefinition {
195
+ id: string;
196
+ name: string;
197
+ version: number;
198
+ /** Optional sidebar folder path (single level, e.g. "Anomaly Detection"). */
199
+ folder?: string;
200
+ /** Present → this flow is (or will be) an HTTP endpoint. Absent → internal sub-flow. */
201
+ http?: HttpTrigger;
202
+ /**
203
+ * Preferred environment name. When set and the runner offers a matching
204
+ * environment, opening this flow auto-selects it — so a flow that targets
205
+ * prod infrastructure doesn't silently run against local.
206
+ */
207
+ environment?: string;
208
+ nodes: WorkflowNode[];
209
+ edges: WorkflowEdge[];
210
+ /** Named test inputs ("storybook" scenarios). Dev fixtures — stripped on publish. */
211
+ scenarios?: ScenarioDefinition[];
212
+ /** Op-level nodeId -> canned output (verbatim), consulted only when a run
213
+ * has `mockRun: true`. Merges under any per-scenario `mocks` (scenario
214
+ * wins per nodeId — see `ScenarioDefinition.mocks`). Lives in the
215
+ * `<op>.scenarios.json` sidecar alongside `scenarios`, exposed here by
216
+ * the store that loads it (e.g. `ApiStore`). Dev fixture — stripped on
217
+ * publish, same as `scenarios`. */
218
+ mocks?: Record<string, unknown>;
219
+ viewport?: {
220
+ x: number;
221
+ y: number;
222
+ zoom: number;
223
+ };
224
+ createdAt: string;
225
+ updatedAt: string;
226
+ }
227
+ export type NodeStatus = 'idle' | 'queued' | 'running' | 'succeeded' | 'failed' | 'skipped';
228
+ export type RunStatus = 'running' | 'succeeded' | 'failed' | 'cancelled';
229
+ /** One execution of a node within a loop region — one entry per iteration. */
230
+ export interface ExecutionRecord {
231
+ iteration: {
232
+ index: number;
233
+ total: number;
234
+ };
235
+ input?: unknown;
236
+ output?: unknown;
237
+ error?: string;
238
+ status: 'succeeded' | 'failed';
239
+ }
240
+ export interface NodeRunState {
241
+ status: NodeStatus;
242
+ input?: unknown;
243
+ output?: unknown;
244
+ error?: string;
245
+ startedAt?: string;
246
+ completedAt?: string;
247
+ /** True when this node's output came from a pin instead of execution. */
248
+ pinned?: boolean;
249
+ /** True when a mutation-declared node completed under safe mode (its writes were dry-run). */
250
+ mutationBlocked?: boolean;
251
+ /**
252
+ * Present on a ForEach node and its loop-body nodes while a loop region is
253
+ * iterating (and left at its last value once the loop completes), giving
254
+ * the 0-based position and total iteration count.
255
+ */
256
+ iteration?: {
257
+ index: number;
258
+ total: number;
259
+ };
260
+ /**
261
+ * Full per-iteration execution history, present on a ForEach node and its
262
+ * loop-body nodes, ordered by iteration. Absent on non-loop executions.
263
+ */
264
+ executions?: ExecutionRecord[];
265
+ /**
266
+ * Total number of implementation-call attempts (including the first),
267
+ * present only when the node has a `retry` and used more than one attempt
268
+ * to reach its final outcome (success or exhausted failure). Absent
269
+ * whenever a single attempt sufficed — including nodes without `retry` at
270
+ * all — so existing single-try consumers see no shape change.
271
+ */
272
+ attempts?: number;
273
+ /** True when this node's output is a canned mock value from a mock run, not the result of executing its implementation. */
274
+ mocked?: boolean;
275
+ }
276
+ export interface WorkflowRun {
277
+ id: string;
278
+ workflowId: string;
279
+ status: RunStatus;
280
+ startedAt: string;
281
+ completedAt?: string;
282
+ /** The environment this run pointed at (from StartRunOptions.environment). */
283
+ environment?: string;
284
+ /** Whether safe mode was active for this run. */
285
+ safeMode?: boolean;
286
+ nodeStates: Record<string, NodeRunState>;
287
+ }
288
+ export interface LogLine {
289
+ timestamp: string;
290
+ level: LogLevel;
291
+ runId: string;
292
+ nodeId?: string;
293
+ nodeLabel?: string;
294
+ message: string;
295
+ }
296
+ export interface NodeExecutionSample {
297
+ id: string;
298
+ workflowId: string;
299
+ runId: string;
300
+ nodeId: string;
301
+ nodeType: string;
302
+ nodeLabel: string;
303
+ input: unknown;
304
+ output?: unknown;
305
+ status: 'succeeded' | 'failed';
306
+ startedAt: string;
307
+ completedAt?: string;
308
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import type { WorkflowDefinition } from './types.js';
2
+ import type { NodeRegistry } from './registry.js';
3
+ export interface ValidationIssue {
4
+ severity: 'error' | 'warning';
5
+ nodeId?: string;
6
+ message: string;
7
+ }
8
+ export interface LoopRegion {
9
+ forEachId: string;
10
+ collectId: string;
11
+ /** Loop-body node ids: downstream(forEach) ∩ upstream(collect), excluding both. */
12
+ bodyIds: string[];
13
+ }
14
+ export declare function topoSort(flow: WorkflowDefinition): string[];
15
+ /** All nodes upstream of nodeId (direct parents and further ancestors). */
16
+ export declare function upstreamNodeIds(flow: WorkflowDefinition, nodeId: string): Set<string>;
17
+ /** All nodes downstream of nodeId (direct children and further descendants). */
18
+ export declare function downstreamNodeIds(flow: WorkflowDefinition, nodeId: string): Set<string>;
19
+ /**
20
+ * Computes ForEach/Collect loop regions for a flow. Only returns regions for
21
+ * valid pairings (1:1 ForEach↔Collect, no leaking edges, not nested) — an
22
+ * invalid flow fails validateFlow and startRun already throws before this
23
+ * would be consulted.
24
+ */
25
+ export declare function computeLoopRegions(flow: WorkflowDefinition): LoopRegion[];
26
+ export declare function validateFlow(flow: WorkflowDefinition, registry: NodeRegistry): ValidationIssue[];
@@ -0,0 +1,318 @@
1
+ export function topoSort(flow) {
2
+ const indegree = new Map();
3
+ const adjacency = new Map();
4
+ for (const n of flow.nodes) {
5
+ indegree.set(n.id, 0);
6
+ adjacency.set(n.id, []);
7
+ }
8
+ for (const e of flow.edges) {
9
+ if (!adjacency.has(e.source) || !indegree.has(e.target))
10
+ continue;
11
+ adjacency.get(e.source).push(e.target);
12
+ indegree.set(e.target, indegree.get(e.target) + 1);
13
+ }
14
+ const queue = flow.nodes.filter((n) => indegree.get(n.id) === 0).map((n) => n.id);
15
+ const order = [];
16
+ while (queue.length > 0) {
17
+ const id = queue.shift();
18
+ order.push(id);
19
+ for (const next of adjacency.get(id)) {
20
+ indegree.set(next, indegree.get(next) - 1);
21
+ if (indegree.get(next) === 0)
22
+ queue.push(next);
23
+ }
24
+ }
25
+ if (order.length !== flow.nodes.length)
26
+ throw new Error('Flow contains a cycle');
27
+ return order;
28
+ }
29
+ /** All nodes upstream of nodeId (direct parents and further ancestors). */
30
+ export function upstreamNodeIds(flow, nodeId) {
31
+ const incoming = new Map();
32
+ for (const e of flow.edges) {
33
+ if (!incoming.has(e.target))
34
+ incoming.set(e.target, []);
35
+ incoming.get(e.target).push(e.source);
36
+ }
37
+ const seen = new Set();
38
+ const queue = [...(incoming.get(nodeId) ?? [])];
39
+ while (queue.length > 0) {
40
+ const id = queue.shift();
41
+ if (seen.has(id))
42
+ continue;
43
+ seen.add(id);
44
+ queue.push(...(incoming.get(id) ?? []));
45
+ }
46
+ return seen;
47
+ }
48
+ /** All nodes downstream of nodeId (direct children and further descendants). */
49
+ export function downstreamNodeIds(flow, nodeId) {
50
+ const outgoing = new Map();
51
+ for (const e of flow.edges) {
52
+ if (!outgoing.has(e.source))
53
+ outgoing.set(e.source, []);
54
+ outgoing.get(e.source).push(e.target);
55
+ }
56
+ const seen = new Set();
57
+ const queue = [...(outgoing.get(nodeId) ?? [])];
58
+ while (queue.length > 0) {
59
+ const id = queue.shift();
60
+ if (seen.has(id))
61
+ continue;
62
+ seen.add(id);
63
+ queue.push(...(outgoing.get(id) ?? []));
64
+ }
65
+ return seen;
66
+ }
67
+ /**
68
+ * Matches ForEach nodes to a single downstream Collect (and vice versa) and
69
+ * computes each region's body + any edges that leak out of it. A ForEach/
70
+ * Collect that doesn't pair 1:1 is simply omitted here — validateFlow raises
71
+ * the specific "no Collect"/"multiple Collect"/etc. errors separately.
72
+ */
73
+ function findLoopPairings(flow) {
74
+ const forEachNodes = flow.nodes.filter((n) => n.type === 'ForEach');
75
+ const collectNodes = flow.nodes.filter((n) => n.type === 'Collect');
76
+ const pairings = [];
77
+ for (const forEachNode of forEachNodes) {
78
+ const downstream = downstreamNodeIds(flow, forEachNode.id);
79
+ const collectsDownstream = collectNodes.filter((c) => downstream.has(c.id));
80
+ if (collectsDownstream.length !== 1)
81
+ continue;
82
+ const collectNode = collectsDownstream[0];
83
+ const upstream = upstreamNodeIds(flow, collectNode.id);
84
+ const forEachesUpstream = forEachNodes.filter((f) => upstream.has(f.id));
85
+ if (forEachesUpstream.length !== 1 || forEachesUpstream[0].id !== forEachNode.id)
86
+ continue;
87
+ const bodyIds = [...downstream].filter((id) => upstream.has(id) && id !== forEachNode.id && id !== collectNode.id);
88
+ const bodySet = new Set(bodyIds);
89
+ const leaks = flow.edges.filter((e) => bodySet.has(e.source) && !bodySet.has(e.target) && e.target !== collectNode.id);
90
+ pairings.push({ forEachNode, collectNode, bodyIds, leaks });
91
+ }
92
+ return pairings;
93
+ }
94
+ /**
95
+ * ForEach node ids that sit downstream of another ForEach node — i.e. one
96
+ * region wraps the other. Deliberately independent of findLoopPairings: a
97
+ * genuinely nested pair almost always also fails the "exactly one Collect
98
+ * descendant" check for the outer ForEach (its downstream includes both the
99
+ * inner and outer Collect), which would otherwise prevent a pairing — and
100
+ * therefore prevent detecting the nesting — from ever being computed.
101
+ */
102
+ function nestedForEachIds(flow) {
103
+ const forEachNodes = flow.nodes.filter((n) => n.type === 'ForEach');
104
+ const nested = new Set();
105
+ for (const outer of forEachNodes) {
106
+ const downstream = downstreamNodeIds(flow, outer.id);
107
+ for (const inner of forEachNodes) {
108
+ if (outer === inner)
109
+ continue;
110
+ if (downstream.has(inner.id)) {
111
+ nested.add(outer.id);
112
+ nested.add(inner.id);
113
+ }
114
+ }
115
+ }
116
+ return nested;
117
+ }
118
+ /**
119
+ * Computes ForEach/Collect loop regions for a flow. Only returns regions for
120
+ * valid pairings (1:1 ForEach↔Collect, no leaking edges, not nested) — an
121
+ * invalid flow fails validateFlow and startRun already throws before this
122
+ * would be consulted.
123
+ */
124
+ export function computeLoopRegions(flow) {
125
+ const pairings = findLoopPairings(flow);
126
+ const nested = nestedForEachIds(flow);
127
+ return pairings
128
+ .filter((p) => p.leaks.length === 0 && !nested.has(p.forEachNode.id))
129
+ .map((p) => ({
130
+ forEachId: p.forEachNode.id,
131
+ collectId: p.collectNode.id,
132
+ bodyIds: p.bodyIds,
133
+ }));
134
+ }
135
+ export function validateFlow(flow, registry) {
136
+ const issues = [];
137
+ const nodeIds = new Set(flow.nodes.map((n) => n.id));
138
+ for (const node of flow.nodes) {
139
+ if (!registry.has(node.type)) {
140
+ issues.push({ severity: 'error', nodeId: node.id, message: `Unknown node type: ${node.type}` });
141
+ }
142
+ }
143
+ for (const edge of flow.edges) {
144
+ for (const end of [edge.source, edge.target]) {
145
+ if (!nodeIds.has(end)) {
146
+ issues.push({ severity: 'error', message: `Edge ${edge.id} references missing node: ${end}` });
147
+ }
148
+ }
149
+ }
150
+ try {
151
+ topoSort(flow);
152
+ }
153
+ catch {
154
+ issues.push({ severity: 'error', message: 'Flow contains a cycle' });
155
+ }
156
+ const ancestorsOf = (nodeId) => upstreamNodeIds(flow, nodeId);
157
+ for (const node of flow.nodes) {
158
+ for (const [field, mapping] of Object.entries(node.inputMap ?? {})) {
159
+ if (!nodeIds.has(mapping.sourceNodeId)) {
160
+ issues.push({
161
+ severity: 'error', nodeId: node.id,
162
+ message: `Input "${field}" maps to missing node: ${mapping.sourceNodeId}`,
163
+ });
164
+ }
165
+ else if (!ancestorsOf(node.id).has(mapping.sourceNodeId)) {
166
+ issues.push({
167
+ severity: 'warning', nodeId: node.id,
168
+ message: `Input "${field}" maps to ${mapping.sourceNodeId}, which is not upstream of this node`,
169
+ });
170
+ }
171
+ }
172
+ // A Subflow that names its own containing flow would recurse forever; the
173
+ // runtime guard catches cross-flow cycles, but a direct self-call is a
174
+ // static error.
175
+ if (node.type === 'Subflow' && node.config.workflowId === flow.id) {
176
+ issues.push({
177
+ severity: 'error', nodeId: node.id,
178
+ message: 'subflow cannot call its own flow',
179
+ });
180
+ }
181
+ if (!registry.has(node.type))
182
+ continue;
183
+ const definition = registry.get(node.type).definition;
184
+ const inputSchema = definition.inputSchema;
185
+ // Mutation nodes write observable state — warn so they can be reviewed
186
+ // before running against a protected environment; safe mode dry-runs them.
187
+ if (definition.effects === 'mutation') {
188
+ issues.push({
189
+ severity: 'warning',
190
+ nodeId: node.id,
191
+ message: `Mutation node "${node.label}" performs writes — dry-run under safe mode`,
192
+ });
193
+ }
194
+ // Mappings to fields the node never declared are silently ignored by
195
+ // implementations — surface them.
196
+ const declared = new Set((inputSchema?.fields ?? []).map((f) => f.name));
197
+ for (const field of Object.keys(node.inputMap ?? {})) {
198
+ if (!declared.has(field)) {
199
+ issues.push({
200
+ severity: 'warning', nodeId: node.id,
201
+ message: `Input "${field}" is mapped but not declared in ${node.type}'s input schema`,
202
+ });
203
+ }
204
+ }
205
+ for (const field of inputSchema?.fields ?? []) {
206
+ if (!field.required)
207
+ continue;
208
+ const mapped = node.inputMap?.[field.name] !== undefined;
209
+ const configured = node.config[field.name] !== undefined;
210
+ if (!mapped && !configured) {
211
+ issues.push({
212
+ severity: 'warning', nodeId: node.id,
213
+ message: `Required input "${field.name}" is not mapped or configured`,
214
+ });
215
+ }
216
+ }
217
+ }
218
+ if (flow.scenarios && flow.scenarios.length > 0) {
219
+ const inputNode = flow.nodes.find((n) => n.type === 'Input');
220
+ if (!inputNode) {
221
+ issues.push({
222
+ severity: 'warning',
223
+ message: 'Flow has scenarios but no Input node — scenario input is never consumed',
224
+ });
225
+ }
226
+ else {
227
+ const rawFields = inputNode.config?.fields;
228
+ const fields = Array.isArray(rawFields)
229
+ ? rawFields.filter((f) => f !== null && typeof f === 'object' && typeof f.name === 'string')
230
+ : [];
231
+ const rawDefaults = inputNode.config?.defaults;
232
+ const defaults = rawDefaults !== null && typeof rawDefaults === 'object' && !Array.isArray(rawDefaults)
233
+ ? rawDefaults
234
+ : {};
235
+ const declaredNames = new Set(fields.map((f) => f.name));
236
+ for (const scenario of flow.scenarios) {
237
+ for (const field of fields) {
238
+ if (!field.required)
239
+ continue;
240
+ if (Object.prototype.hasOwnProperty.call(defaults, field.name))
241
+ continue;
242
+ if (Object.prototype.hasOwnProperty.call(scenario.input, field.name))
243
+ continue;
244
+ issues.push({
245
+ severity: 'warning',
246
+ nodeId: inputNode.id,
247
+ message: `Scenario "${scenario.name}" omits required input field "${field.name}"`,
248
+ });
249
+ }
250
+ for (const key of Object.keys(scenario.input)) {
251
+ if (!declaredNames.has(key)) {
252
+ issues.push({
253
+ severity: 'warning',
254
+ nodeId: inputNode.id,
255
+ message: `Scenario "${scenario.name}" provides undeclared input field "${key}"`,
256
+ });
257
+ }
258
+ }
259
+ }
260
+ }
261
+ }
262
+ // ── ForEach/Collect loop regions ──────────────────────────────────
263
+ for (const n of flow.nodes) {
264
+ if (n.type !== 'ForEach')
265
+ continue;
266
+ const downstream = downstreamNodeIds(flow, n.id);
267
+ const collectsDownstream = flow.nodes.filter((c) => c.type === 'Collect' && downstream.has(c.id));
268
+ if (collectsDownstream.length === 0) {
269
+ issues.push({
270
+ severity: 'error', nodeId: n.id,
271
+ message: `ForEach "${n.id}" has no Collect node among its descendants`,
272
+ });
273
+ }
274
+ else if (collectsDownstream.length > 1) {
275
+ issues.push({
276
+ severity: 'error', nodeId: n.id,
277
+ message: `ForEach "${n.id}" has multiple Collect nodes among its descendants: ${collectsDownstream.map((c) => c.id).join(', ')}`,
278
+ });
279
+ }
280
+ }
281
+ for (const n of flow.nodes) {
282
+ if (n.type !== 'Collect')
283
+ continue;
284
+ const upstream = upstreamNodeIds(flow, n.id);
285
+ const forEachesUpstream = flow.nodes.filter((f) => f.type === 'ForEach' && upstream.has(f.id));
286
+ if (forEachesUpstream.length === 0) {
287
+ issues.push({
288
+ severity: 'error', nodeId: n.id,
289
+ message: `Collect "${n.id}" has no ForEach node among its ancestors`,
290
+ });
291
+ }
292
+ else if (forEachesUpstream.length > 1) {
293
+ issues.push({
294
+ severity: 'error', nodeId: n.id,
295
+ message: `Collect "${n.id}" has multiple ForEach nodes among its ancestors: ${forEachesUpstream.map((f) => f.id).join(', ')}`,
296
+ });
297
+ }
298
+ }
299
+ const pairings = findLoopPairings(flow);
300
+ for (const p of pairings) {
301
+ for (const edge of p.leaks) {
302
+ issues.push({
303
+ severity: 'error',
304
+ nodeId: edge.source,
305
+ message: `Edge "${edge.id}" leaves the ForEach/Collect region rooted at "${p.forEachNode.id}" without targeting the region or its Collect node "${p.collectNode.id}"`,
306
+ });
307
+ }
308
+ }
309
+ const nested = nestedForEachIds(flow);
310
+ for (const forEachId of nested) {
311
+ issues.push({
312
+ severity: 'error',
313
+ nodeId: forEachId,
314
+ message: 'Nested ForEach regions are not supported',
315
+ });
316
+ }
317
+ return issues;
318
+ }
@@ -0,0 +1,23 @@
1
+ import type { WorkflowDefinition } from '../engine/index.js';
2
+ /**
3
+ * Live call: whole-series detection, then branch on severity.
4
+ * build → detect → summarize → cond(anomalyCount > 0?)
5
+ * ├─ anomalous → composeIncident → incidentResult
6
+ * └─ clean → cleanResult
7
+ *
8
+ * Deviation from spec: the spec's Conditional has two rules (`gt 3 → P1`,
9
+ * `gt 0 → P2`) feeding three downstream paths, but this flow only ever had
10
+ * two downstream branches (anomalous/clean). Kept the original two-branch
11
+ * shape as a single rule `gt 0 → anomalous`, fallback `clean`, rather than
12
+ * inventing a third P1/P2 branch nothing here consumes.
13
+ */
14
+ export declare function createDetectEntireFlow(): WorkflowDefinition;
15
+ /** Live call: streaming-style last-point verdict. */
16
+ export declare function createDetectLastFlow(): WorkflowDefinition;
17
+ /** Live call: detection + Adtributor root-cause analysis. */
18
+ export declare function createRootCauseFlow(): WorkflowDefinition;
19
+ /** Replica of today's quota/email business logic (Clerk-gated server-side). */
20
+ export declare function createQuotaFlow(): WorkflowDefinition;
21
+ /** Replica of today's key issuance + 5-key limit guard. */
22
+ export declare function createKeyLifecycleFlow(): WorkflowDefinition;
23
+ export declare function createAnomalyFlows(): WorkflowDefinition[];