@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,259 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { changedFiles, diffSince, isGitRepo, revert as gitRevert, snapshot } from './gitScope.js';
3
+ import { buildPrompt } from './prompt.js';
4
+ import { spawnCodex } from './codexAdapter.js';
5
+ import { spawnClaude } from './claudeAdapter.js';
6
+ import { isPathWithin } from '../pathSafety.js';
7
+ /** Thrown by `start()`; `status` maps directly onto the HTTP status the endpoint should return. */
8
+ export class AgentStartError extends Error {
9
+ status;
10
+ constructor(message, status) {
11
+ super(message);
12
+ this.status = status;
13
+ this.name = 'AgentStartError';
14
+ }
15
+ }
16
+ /** Max number of terminal (done/error) runs kept around for diff/revert/replay before eviction. */
17
+ const MAX_TERMINAL_RUNS = 20;
18
+ /**
19
+ * Rejects anything that isn't a safe flow id. Operation ids are path-style
20
+ * (e.g. `"billing/charge"`, the on-disk relative path), so a slash-separated
21
+ * id is legitimate and must be allowed — only traversal (`..` segments),
22
+ * absolute ids, backslashes, and empty segments are rejected, and the file it
23
+ * resolves to must stay inside `apisDir`. Defense in depth — the agent
24
+ * sandbox already confines actual writes — but it keeps a bogus flowId like
25
+ * `"../../etc/passwd"` from ever becoming an existence-probe against paths
26
+ * outside apisDir.
27
+ */
28
+ function isSafeFlowId(flowId, apisDir) {
29
+ if (!flowId)
30
+ return false;
31
+ return isPathWithin(apisDir, `${flowId}.json`);
32
+ }
33
+ /**
34
+ * Resolves a `new-operation` intent's user-supplied `location` (a folder path
35
+ * under `apisDir`, e.g. `"billing"` or `"billing/charges"`) to the directory
36
+ * the new operation file should be created in. An empty string or `"default"`
37
+ * both mean "the default API".
38
+ */
39
+ function resolveLocationDir(location) {
40
+ const trimmed = location.trim();
41
+ return trimmed === '' ? 'default' : trimmed;
42
+ }
43
+ /** Same defense-in-depth as `isSafeFlowId`, but for a target *directory* rather than a flow file. */
44
+ function isSafeLocationDir(dir, apisDir) {
45
+ return isPathWithin(apisDir, dir);
46
+ }
47
+ /**
48
+ * Owns in-flight coding-agent runs for a single project: spawns the adapter,
49
+ * buffers its events for SSE replay + live subscribers, and exposes
50
+ * git-scoped diff/revert against the snapshot taken at run start. One active
51
+ * run per project at a time.
52
+ */
53
+ export class AgentRunManager {
54
+ projectDir;
55
+ apisDir;
56
+ pathOf;
57
+ availableNodes;
58
+ projectLanguage;
59
+ infrastructure;
60
+ runs = new Map();
61
+ activeRunId = null;
62
+ constructor(projectDir, apisDir, pathOf,
63
+ /**
64
+ * Getter (not a static list) so the prompt always reflects the
65
+ * currently-registered node types, even if the registry is populated or
66
+ * changes after this manager is constructed.
67
+ */
68
+ availableNodes = () => [],
69
+ /** The loaded project's authored language (`ProjectConfig.language`,
70
+ * explicit-or-inferred), threaded into every prompt this manager builds.
71
+ * Defaults to 'typescript' — the Emberflow repo itself, when constructed
72
+ * without a loaded consumer project. */
73
+ projectLanguage = 'typescript',
74
+ /**
75
+ * Getter (not a static value) for the loaded `emberflow/infrastructure.json`
76
+ * manifest, so every prompt reflects the manifest currently on disk — a scout
77
+ * run mid-session updates what later runs see. Returns null when the project
78
+ * hasn't been scouted or the file is malformed. Injected as a prompt preamble
79
+ * so agents REUSE known infrastructure instead of inventing parallel config.
80
+ */
81
+ infrastructure = () => null) {
82
+ this.projectDir = projectDir;
83
+ this.apisDir = apisDir;
84
+ this.pathOf = pathOf;
85
+ this.availableNodes = availableNodes;
86
+ this.projectLanguage = projectLanguage;
87
+ this.infrastructure = infrastructure;
88
+ }
89
+ /** Validates the project + flow, snapshots git, spawns the adapter, and returns the new run's id. */
90
+ start(intent, opts = {}) {
91
+ if (this.activeRunId) {
92
+ throw new AgentStartError('An agent run is already active for this project', 409);
93
+ }
94
+ if (!isGitRepo(this.projectDir)) {
95
+ throw new AgentStartError(`${this.projectDir} is not a git repository`, 400);
96
+ }
97
+ // `new-operation` creates a brand-new flow, so there's no existing
98
+ // flowId to validate against pathOf — it validates `location` instead.
99
+ // `setup-auth` targets an environment, not a flow file, and
100
+ // `setup-environments` targets the environments file itself, so
101
+ // neither has a relPath to resolve.
102
+ let relPath;
103
+ if (intent.action === 'new-operation') {
104
+ const dir = resolveLocationDir(intent.location);
105
+ if (!isSafeLocationDir(dir, this.apisDir)) {
106
+ throw new AgentStartError('Invalid location', 400);
107
+ }
108
+ relPath = dir;
109
+ }
110
+ else if (intent.action === 'setup-auth' ||
111
+ intent.action === 'setup-environments' ||
112
+ intent.action === 'scout-infrastructure') {
113
+ // No flow file: setup-auth targets an environment, setup-environments the
114
+ // environments file, and scout-infrastructure reads the whole project and
115
+ // writes emberflow/infrastructure.json — none has a relPath to resolve.
116
+ relPath = '';
117
+ }
118
+ else if (intent.action === 'ask') {
119
+ // `ask`'s flowId is optional: with one, resolve the op's relPath like
120
+ // edit-flow does; without, resolve to the apis root (empty relPath) —
121
+ // there's no specific operation file to point the prompt at.
122
+ if (intent.flowId) {
123
+ if (!isSafeFlowId(intent.flowId, this.apisDir)) {
124
+ throw new AgentStartError('Invalid flowId', 400);
125
+ }
126
+ const found = this.pathOf(intent.flowId);
127
+ if (!found) {
128
+ throw new AgentStartError(`Unknown flow: ${intent.flowId}`, 400);
129
+ }
130
+ relPath = found;
131
+ }
132
+ else {
133
+ relPath = '';
134
+ }
135
+ }
136
+ else {
137
+ if (!isSafeFlowId(intent.flowId, this.apisDir)) {
138
+ throw new AgentStartError('Invalid flowId', 400);
139
+ }
140
+ const found = this.pathOf(intent.flowId);
141
+ if (!found) {
142
+ throw new AgentStartError(`Unknown flow: ${intent.flowId}`, 400);
143
+ }
144
+ relPath = found;
145
+ }
146
+ this.pruneTerminalRuns();
147
+ const snap = snapshot(this.projectDir);
148
+ const prompt = buildPrompt(intent, this.apisDir, relPath, this.availableNodes(), this.projectLanguage, this.infrastructure());
149
+ const adapter = opts.agent === 'claude'
150
+ ? spawnClaude(prompt, this.projectDir, {
151
+ model: opts.model,
152
+ bin: process.env.EMBERFLOW_CLAUDE_BIN,
153
+ })
154
+ : spawnCodex(prompt, this.projectDir, {
155
+ model: opts.model,
156
+ reasoning: opts.reasoning ?? 'medium',
157
+ bin: process.env.EMBERFLOW_CODEX_BIN,
158
+ });
159
+ const id = randomUUID();
160
+ const run = { id, snapshot: snap, adapter, buffer: [], listeners: new Set(), status: 'running' };
161
+ this.runs.set(id, run);
162
+ this.activeRunId = id;
163
+ void this.consume(run);
164
+ return id;
165
+ }
166
+ /** Drains the adapter's events into the run's buffer, fanning each out to live subscribers. */
167
+ async consume(run) {
168
+ const emit = (event) => {
169
+ run.buffer.push(event);
170
+ for (const listener of run.listeners)
171
+ listener(event);
172
+ };
173
+ try {
174
+ for await (const event of run.adapter.events) {
175
+ // Clear the busy slot as soon as a terminal event is *observed*, not
176
+ // once the adapter's generator fully drains — a subscriber reacting
177
+ // synchronously to `done`/`error` (e.g. by starting a new run) must
178
+ // not race against this loop's own bookkeeping.
179
+ if (event.type === 'done') {
180
+ run.status = 'done';
181
+ this.clearActive(run.id);
182
+ }
183
+ else if (event.type === 'error') {
184
+ run.status = 'error';
185
+ this.clearActive(run.id);
186
+ }
187
+ emit(event);
188
+ }
189
+ }
190
+ catch (err) {
191
+ run.status = 'error';
192
+ this.clearActive(run.id);
193
+ emit({ type: 'error', text: err instanceof Error ? err.message : String(err) });
194
+ }
195
+ finally {
196
+ this.clearActive(run.id);
197
+ }
198
+ }
199
+ clearActive(id) {
200
+ if (this.activeRunId === id)
201
+ this.activeRunId = null;
202
+ }
203
+ /** Replay the buffer to the listener, then stream live events. Returns an unsubscribe fn. */
204
+ subscribe(id, listener) {
205
+ const run = this.runs.get(id);
206
+ if (!run)
207
+ return undefined;
208
+ for (const event of run.buffer)
209
+ listener(event);
210
+ run.listeners.add(listener);
211
+ return () => run.listeners.delete(listener);
212
+ }
213
+ has(id) {
214
+ return this.runs.has(id);
215
+ }
216
+ diff(id) {
217
+ const run = this.runs.get(id);
218
+ if (!run)
219
+ return undefined;
220
+ return {
221
+ diff: diffSince(this.projectDir, run.snapshot),
222
+ files: changedFiles(this.projectDir, run.snapshot),
223
+ };
224
+ }
225
+ revert(id) {
226
+ const run = this.runs.get(id);
227
+ if (!run)
228
+ return undefined;
229
+ const files = changedFiles(this.projectDir, run.snapshot);
230
+ gitRevert(this.projectDir, run.snapshot, files);
231
+ return { reverted: files };
232
+ }
233
+ cancel(id) {
234
+ const run = this.runs.get(id);
235
+ if (!run)
236
+ return false;
237
+ run.adapter.cancel();
238
+ return true;
239
+ }
240
+ /**
241
+ * Evicts oldest terminal (done|error) runs beyond MAX_TERMINAL_RUNS so the
242
+ * `runs` map — and each run's full event buffer — doesn't grow unbounded
243
+ * over a long-lived server process. The active run (if any) is never
244
+ * evicted; insertion order on the Map gives us oldest-first for free.
245
+ */
246
+ pruneTerminalRuns() {
247
+ const terminalIds = [];
248
+ for (const [id, run] of this.runs) {
249
+ if (run.status === 'done' || run.status === 'error')
250
+ terminalIds.push(id);
251
+ }
252
+ const excess = terminalIds.length - MAX_TERMINAL_RUNS;
253
+ if (excess <= 0)
254
+ return;
255
+ for (const id of terminalIds.slice(0, excess)) {
256
+ this.runs.delete(id);
257
+ }
258
+ }
259
+ }
@@ -0,0 +1,15 @@
1
+ export type AgentKind = 'codex' | 'claude';
2
+ export interface AgentEvent {
3
+ type: 'started' | 'message' | 'command' | 'mcp' | 'approval-request' | 'done' | 'error';
4
+ text?: string;
5
+ command?: string;
6
+ commandStatus?: 'in_progress' | 'completed' | 'failed';
7
+ exitCode?: number | null;
8
+ output?: string;
9
+ toolUseId?: string;
10
+ approvalId?: string;
11
+ usage?: Record<string, number>;
12
+ mcpServer?: string;
13
+ mcpTool?: string;
14
+ mcpStatus?: 'in_progress' | 'completed' | 'failed';
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ import type { AuthPolicy, HttpTrigger, WorkflowDefinition } from '../src/engine/index.js';
2
+ export interface OpSummary {
3
+ id: string;
4
+ name: string;
5
+ path: string;
6
+ http?: HttpTrigger;
7
+ }
8
+ export interface FolderNode {
9
+ name: string;
10
+ folders: FolderNode[];
11
+ operations: OpSummary[];
12
+ }
13
+ export interface ApiNode {
14
+ name: string;
15
+ folders: FolderNode[];
16
+ operations: OpSummary[];
17
+ }
18
+ export interface ApiTree {
19
+ apis: ApiNode[];
20
+ }
21
+ /** File-backed store over an `apis/<api>/<folder…>/<op>.json` tree. Keys ops by
22
+ * their in-file `id`; tracks each op's relative path (POSIX, no `.json`). */
23
+ export declare class ApiStore {
24
+ readonly dir: string;
25
+ /** id → relative path (POSIX, no extension). Rebuilt on every scan. */
26
+ private index;
27
+ constructor(dir: string);
28
+ private sidecarFor;
29
+ /** Sidecar files come in two shapes: the legacy bare array (scenarios only —
30
+ * still written when an op has no mocks, for human-editability/back-compat)
31
+ * and `{ scenarios?, mocks? }`, used once an op carries op-level mocks. */
32
+ private withSidecar;
33
+ /** Reads just the sidecar's top-level `mocks`, ignoring `scenarios` — used
34
+ * by `save` to preserve mocks when the incoming flow doesn't carry them. */
35
+ private readSidecarMocks;
36
+ /** Recursively collect operation files as { flow, relPath }. */
37
+ private scan;
38
+ list(): WorkflowDefinition[];
39
+ /** One entry per operation with its on-disk relative path and `http` metadata
40
+ * (id/name/http from the file itself), for the studio's tree view. */
41
+ listSummaries(): OpSummary[];
42
+ /** True when an operation file already sits at `relPath` — used by
43
+ * POST /operations to refuse to silently overwrite an existing op with a
44
+ * brand-new one saved at the same path. */
45
+ existsAt(relPath: string): boolean;
46
+ load(id: string): WorkflowDefinition | undefined;
47
+ /** id → relative path. Always rescans so it reflects the current on-disk state
48
+ * (files may be added/renamed/deleted out-of-band by a coding agent). */
49
+ pathOf(id: string): string | undefined;
50
+ tree(): ApiTree;
51
+ save(flow: WorkflowDefinition, relPath: string): void;
52
+ remove(id: string): boolean;
53
+ /** Resolves the effective auth policy for an operation: walks the op's path
54
+ * from the API root down through each folder, reading `_meta.json`'s `auth`
55
+ * (nearest ancestor default), then applies the op's own `http.auth`
56
+ * override — `'none'` -> explicitly public (null), a policy object -> that
57
+ * policy, `'inherit'`/absent -> the inherited default. Returns the
58
+ * effective policy or null (no auth — public by default). */
59
+ resolveAuth(id: string): AuthPolicy | null;
60
+ }
@@ -0,0 +1,249 @@
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ /** File-backed store over an `apis/<api>/<folder…>/<op>.json` tree. Keys ops by
4
+ * their in-file `id`; tracks each op's relative path (POSIX, no `.json`). */
5
+ export class ApiStore {
6
+ dir;
7
+ /** id → relative path (POSIX, no extension). Rebuilt on every scan. */
8
+ index = new Map();
9
+ constructor(dir) {
10
+ this.dir = dir;
11
+ mkdirSync(this.dir, { recursive: true });
12
+ }
13
+ sidecarFor(relPath) {
14
+ return join(this.dir, ...relPath.split('/')) + '.scenarios.json';
15
+ }
16
+ /** Sidecar files come in two shapes: the legacy bare array (scenarios only —
17
+ * still written when an op has no mocks, for human-editability/back-compat)
18
+ * and `{ scenarios?, mocks? }`, used once an op carries op-level mocks. */
19
+ withSidecar(flow, relPath) {
20
+ const path = this.sidecarFor(relPath);
21
+ if (!existsSync(path))
22
+ return flow;
23
+ try {
24
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
25
+ if (Array.isArray(raw)) {
26
+ return raw.length > 0 ? { ...flow, scenarios: raw } : flow;
27
+ }
28
+ if (raw && typeof raw === 'object') {
29
+ const { scenarios, mocks } = raw;
30
+ let out = flow;
31
+ if (Array.isArray(scenarios) && scenarios.length > 0)
32
+ out = { ...out, scenarios };
33
+ if (mocks && typeof mocks === 'object')
34
+ out = { ...out, mocks };
35
+ return out;
36
+ }
37
+ return flow;
38
+ }
39
+ catch (err) {
40
+ console.warn(`[apiStore] skipping unparseable ${relPath}.scenarios.json: ${String(err)}`);
41
+ return flow;
42
+ }
43
+ }
44
+ /** Reads just the sidecar's top-level `mocks`, ignoring `scenarios` — used
45
+ * by `save` to preserve mocks when the incoming flow doesn't carry them. */
46
+ readSidecarMocks(relPath) {
47
+ const path = this.sidecarFor(relPath);
48
+ if (!existsSync(path))
49
+ return undefined;
50
+ try {
51
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
52
+ if (Array.isArray(raw) || !raw || typeof raw !== 'object')
53
+ return undefined;
54
+ const { mocks } = raw;
55
+ return mocks && typeof mocks === 'object' ? mocks : undefined;
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ /** Recursively collect operation files as { flow, relPath }. */
62
+ scan() {
63
+ const out = [];
64
+ this.index = new Map();
65
+ const walk = (absDir, relParts) => {
66
+ for (const entry of readdirSync(absDir)) {
67
+ const abs = join(absDir, entry);
68
+ if (statSync(abs).isDirectory()) {
69
+ walk(abs, [...relParts, entry]);
70
+ continue;
71
+ }
72
+ if (entry === '_meta.json')
73
+ continue;
74
+ if (!entry.endsWith('.json') || entry.endsWith('.scenarios.json'))
75
+ continue;
76
+ const relPath = [...relParts, entry.slice(0, -'.json'.length)].join('/');
77
+ try {
78
+ const flow = JSON.parse(readFileSync(abs, 'utf8'));
79
+ const existing = this.index.get(flow.id);
80
+ if (existing !== undefined && existing !== relPath) {
81
+ console.warn(`[apiStore] duplicate operation id "${flow.id}" at ${existing} and ${relPath} — only one is reachable`);
82
+ }
83
+ else {
84
+ this.index.set(flow.id, relPath);
85
+ }
86
+ out.push({ flow, relPath });
87
+ }
88
+ catch (err) {
89
+ console.warn(`[apiStore] skipping unparseable ${relPath}.json: ${String(err)}`);
90
+ }
91
+ }
92
+ };
93
+ walk(this.dir, []);
94
+ return out;
95
+ }
96
+ list() {
97
+ return this.scan().map(({ flow, relPath }) => this.withSidecar(flow, relPath));
98
+ }
99
+ /** One entry per operation with its on-disk relative path and `http` metadata
100
+ * (id/name/http from the file itself), for the studio's tree view. */
101
+ listSummaries() {
102
+ return this.scan().map(({ flow, relPath }) => ({ id: flow.id, name: flow.name, path: relPath, http: flow.http }));
103
+ }
104
+ /** True when an operation file already sits at `relPath` — used by
105
+ * POST /operations to refuse to silently overwrite an existing op with a
106
+ * brand-new one saved at the same path. */
107
+ existsAt(relPath) {
108
+ const abs = join(this.dir, ...relPath.split('/')) + '.json';
109
+ return existsSync(abs);
110
+ }
111
+ load(id) {
112
+ const relPath = this.pathOf(id);
113
+ if (!relPath)
114
+ return undefined;
115
+ const abs = join(this.dir, ...relPath.split('/')) + '.json';
116
+ if (!existsSync(abs))
117
+ return undefined;
118
+ try {
119
+ const flow = JSON.parse(readFileSync(abs, 'utf8'));
120
+ return this.withSidecar(flow, relPath);
121
+ }
122
+ catch (err) {
123
+ console.warn(`[apiStore] skipping unparseable ${relPath}.json: ${String(err)}`);
124
+ return undefined;
125
+ }
126
+ }
127
+ /** id → relative path. Always rescans so it reflects the current on-disk state
128
+ * (files may be added/renamed/deleted out-of-band by a coding agent). */
129
+ pathOf(id) {
130
+ this.scan();
131
+ return this.index.get(id);
132
+ }
133
+ tree() {
134
+ const ops = this.scan();
135
+ const apis = new Map();
136
+ const folderAt = (parent, name) => {
137
+ let f = parent.folders.find((x) => x.name === name);
138
+ if (!f) {
139
+ f = { name, folders: [], operations: [] };
140
+ parent.folders.push(f);
141
+ }
142
+ return f;
143
+ };
144
+ for (const { flow, relPath } of ops) {
145
+ const parts = relPath.split('/'); // [api, ...folders, opName]
146
+ const apiName = parts[0];
147
+ let api = apis.get(apiName);
148
+ if (!api) {
149
+ api = { name: apiName, folders: [], operations: [] };
150
+ apis.set(apiName, api);
151
+ }
152
+ const folderParts = parts.slice(1, -1);
153
+ let container = api;
154
+ for (const fp of folderParts)
155
+ container = folderAt(container, fp);
156
+ container.operations.push({ id: flow.id, name: flow.name, path: relPath, http: flow.http });
157
+ }
158
+ return { apis: [...apis.values()] };
159
+ }
160
+ save(flow, relPath) {
161
+ const abs = join(this.dir, ...relPath.split('/')) + '.json';
162
+ if (existsSync(abs)) {
163
+ try {
164
+ const existing = JSON.parse(readFileSync(abs, 'utf8'));
165
+ if (existing.id !== undefined && existing.id !== flow.id) {
166
+ console.warn(`[apiStore] overwriting ${relPath} which held a different op id "${existing.id}"`);
167
+ }
168
+ }
169
+ catch {
170
+ // unparseable existing file — nothing sensible to compare, proceed with the write.
171
+ }
172
+ }
173
+ mkdirSync(dirname(abs), { recursive: true });
174
+ const { scenarios, mocks, ...rest } = flow;
175
+ writeFileSync(abs, `${JSON.stringify(rest, null, 2)}\n`, 'utf8');
176
+ const sidecar = this.sidecarFor(relPath);
177
+ // A flow argument that doesn't carry `mocks` at all (undefined — not an
178
+ // empty object) means the caller never touched op-level mocks (e.g. a
179
+ // scenario-only edit round-tripped through a client that doesn't forward
180
+ // unknown fields) — preserve whatever is already on disk rather than
181
+ // silently dropping it.
182
+ const effectiveMocks = mocks !== undefined ? mocks : this.readSidecarMocks(relPath);
183
+ const hasScenarios = scenarios !== undefined && scenarios.length > 0;
184
+ const hasMocks = effectiveMocks !== undefined && Object.keys(effectiveMocks).length > 0;
185
+ if (hasMocks) {
186
+ writeFileSync(sidecar, `${JSON.stringify({ ...(hasScenarios ? { scenarios } : {}), mocks: effectiveMocks }, null, 2)}\n`, 'utf8');
187
+ }
188
+ else if (hasScenarios) {
189
+ writeFileSync(sidecar, `${JSON.stringify(scenarios, null, 2)}\n`, 'utf8');
190
+ }
191
+ else if (existsSync(sidecar)) {
192
+ rmSync(sidecar);
193
+ }
194
+ this.index.set(flow.id, relPath);
195
+ }
196
+ remove(id) {
197
+ const relPath = this.pathOf(id);
198
+ if (!relPath)
199
+ return false;
200
+ const abs = join(this.dir, ...relPath.split('/')) + '.json';
201
+ if (!existsSync(abs))
202
+ return false;
203
+ rmSync(abs);
204
+ const sidecar = this.sidecarFor(relPath);
205
+ if (existsSync(sidecar))
206
+ rmSync(sidecar);
207
+ this.index.delete(id);
208
+ return true;
209
+ }
210
+ /** Resolves the effective auth policy for an operation: walks the op's path
211
+ * from the API root down through each folder, reading `_meta.json`'s `auth`
212
+ * (nearest ancestor default), then applies the op's own `http.auth`
213
+ * override — `'none'` -> explicitly public (null), a policy object -> that
214
+ * policy, `'inherit'`/absent -> the inherited default. Returns the
215
+ * effective policy or null (no auth — public by default). */
216
+ resolveAuth(id) {
217
+ const relPath = this.pathOf(id);
218
+ if (!relPath)
219
+ return null;
220
+ const parts = relPath.split('/'); // [api, ...folders, opName]
221
+ let inherited = null;
222
+ for (let depth = 1; depth < parts.length; depth++) {
223
+ const metaPath = join(this.dir, ...parts.slice(0, depth), '_meta.json');
224
+ if (!existsSync(metaPath))
225
+ continue;
226
+ try {
227
+ const meta = JSON.parse(readFileSync(metaPath, 'utf8'));
228
+ if (meta.auth)
229
+ inherited = meta.auth;
230
+ }
231
+ catch (err) {
232
+ // A present-but-corrupt _meta.json (partial write, typo, etc.) must
233
+ // never silently resolve to `null` (= public) — that's a fail-open
234
+ // security hole. Fail closed: throw and let the caller deny the op
235
+ // rather than mount it open. A merely ABSENT _meta.json is fine (see
236
+ // the `existsSync` check above) — only a broken one throws.
237
+ const metaRelPath = `${parts.slice(0, depth).join('/')}/_meta.json`;
238
+ throw new Error(`unparseable _meta.json at ${metaRelPath} — refusing to resolve auth (fail closed): ${String(err)}`);
239
+ }
240
+ }
241
+ const op = this.load(id);
242
+ const override = op?.http?.auth;
243
+ if (override === 'none')
244
+ return null;
245
+ if (override && override !== 'inherit')
246
+ return override;
247
+ return inherited;
248
+ }
249
+ }
@@ -0,0 +1 @@
1
+ export { enforceAuth } from '../../src/engine/index.js';
@@ -0,0 +1,6 @@
1
+ // Re-exports the shared enforceAuth from src/engine/authVerify.ts. Kept as its
2
+ // own module (rather than importing src/engine directly at call sites) so the
3
+ // server-side auth call path has a stable, server-scoped entry point mirroring
4
+ // the file map in the plan; the underlying logic is shared with the
5
+ // requireAuth node (src/nodes/requireAuth.ts) to avoid divergence.
6
+ export { enforceAuth } from '../../src/engine/index.js';
@@ -0,0 +1 @@
1
+ export type { AuthPolicy, VerifyResult, Verifier } from '../../src/engine/index.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export { bearerVerifier, apiKeyVerifier, VerifierRegistry, createDefaultVerifierRegistry, } from '../../src/engine/index.js';
@@ -0,0 +1,4 @@
1
+ // Re-exports the shared, browser-safe implementation from src/engine/authVerify.ts
2
+ // so server-side auth enforcement and the requireAuth node (bundled into the
3
+ // studio browser build) share one implementation instead of two diverging copies.
4
+ export { bearerVerifier, apiKeyVerifier, VerifierRegistry, createDefaultVerifierRegistry, } from '../../src/engine/index.js';
@@ -0,0 +1,19 @@
1
+ import type { EnvAuth } from './environments.js';
2
+ type LoginCapture = NonNullable<EnvAuth['login']>['capture'];
3
+ /**
4
+ * Attaches a captured credential value onto a headers object for a run.
5
+ * Pure and non-mutating: returns a NEW headers object.
6
+ * Additive + non-destructive — if the target header/cookie-name is already
7
+ * present, the input is returned unchanged (caller-explicit wins).
8
+ */
9
+ export declare function attachCredential(headers: Record<string, unknown>, attach: EnvAuth['attach'], value: string): Record<string, unknown>;
10
+ /**
11
+ * Extracts a captured credential value from a login response.
12
+ * Pure with respect to its inputs (no I/O of its own) — the caller performs
13
+ * the actual fetch and passes in the response-like object.
14
+ */
15
+ export declare function captureCredential(res: {
16
+ headers: Headers;
17
+ json: () => Promise<any>;
18
+ }, capture: LoginCapture): Promise<string | null>;
19
+ export {};