stageflow 0.33.0 → 0.36.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 (379) hide show
  1. package/README.md +3 -3
  2. package/dist/agent/adapterSpill.d.ts +14 -0
  3. package/dist/agent/adapterSpill.js +83 -0
  4. package/dist/agent/agentBackend.d.ts +2 -2
  5. package/dist/agent/agentBackend.js +2 -2
  6. package/dist/agent/claudeAdapter.d.ts +13 -2
  7. package/dist/agent/claudeAdapter.js +56 -6
  8. package/dist/agent/cursorProvider.d.ts +3 -0
  9. package/dist/agent/cursorProvider.js +23 -6
  10. package/dist/agent/fakeAgent.d.ts +3 -3
  11. package/dist/agent/piAdapter.d.ts +2 -2
  12. package/dist/agent/piAdapter.js +125 -15
  13. package/dist/agent/piIsolatedMcp.d.ts +1 -0
  14. package/dist/agent/piIsolatedMcp.js +19 -1
  15. package/dist/agent/piIsolatedMcpProbe.d.ts +11 -0
  16. package/dist/agent/piIsolatedMcpProbe.js +20 -0
  17. package/dist/agent/port.d.ts +4 -2
  18. package/dist/agent/providerAuth.js +36 -3
  19. package/dist/agent/{resolveAgentPort.d.ts → resolveStagePort.d.ts} +8 -8
  20. package/dist/agent/{resolveAgentPort.js → resolveStagePort.js} +11 -11
  21. package/dist/agent/stageTurnDriver.d.ts +33 -0
  22. package/dist/agent/stageTurnDriver.js +64 -0
  23. package/dist/agent/toolOutputBudget.d.ts +46 -0
  24. package/dist/agent/toolOutputBudget.js +97 -0
  25. package/dist/agent/toolOutputBudgetExtension.d.ts +22 -0
  26. package/dist/agent/toolOutputBudgetExtension.js +141 -0
  27. package/dist/agent/toolOutputSpill.d.ts +34 -0
  28. package/dist/agent/toolOutputSpill.js +85 -0
  29. package/dist/browser/agentBrowserLiveViewRelay.d.ts +41 -0
  30. package/dist/browser/agentBrowserLiveViewRelay.js +801 -0
  31. package/dist/browser/anchor.d.ts +2 -0
  32. package/dist/browser/anchor.js +2 -1
  33. package/dist/browser/auditSink.d.ts +8 -0
  34. package/dist/browser/browserHost.d.ts +29 -0
  35. package/dist/browser/browserSweep.d.ts +4 -1
  36. package/dist/browser/browserSweep.js +7 -0
  37. package/dist/browser/browserTeardown.d.ts +1 -0
  38. package/dist/browser/browserTeardown.js +32 -2
  39. package/dist/browser/containerBrowserEndpoint.d.ts +11 -0
  40. package/dist/browser/containerBrowserEndpoint.js +57 -0
  41. package/dist/browser/containerBrowserHost.d.ts +24 -0
  42. package/dist/browser/containerBrowserHost.js +147 -0
  43. package/dist/browser/dockerSandboxOrchestrator.d.ts +26 -0
  44. package/dist/browser/dockerSandboxOrchestrator.js +142 -0
  45. package/dist/browser/fakeLiveViewRelay.d.ts +15 -0
  46. package/dist/browser/fakeLiveViewRelay.js +94 -0
  47. package/dist/browser/fakeLiveViewSource.d.ts +6 -0
  48. package/dist/browser/fakeLiveViewSource.js +16 -0
  49. package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -1
  50. package/dist/browser/fakeRemoteBrowserHost.js +2 -1
  51. package/dist/browser/fakeSandboxOrchestrator.d.ts +9 -0
  52. package/dist/browser/fakeSandboxOrchestrator.js +44 -0
  53. package/dist/browser/gateHandoff.d.ts +0 -2
  54. package/dist/browser/gateHandoff.js +5 -11
  55. package/dist/browser/hostCapabilities.d.ts +23 -0
  56. package/dist/browser/hostCapabilities.js +23 -0
  57. package/dist/browser/humanLogin.d.ts +2 -2
  58. package/dist/browser/humanLogin.js +11 -2
  59. package/dist/browser/liveViewPersisted.d.ts +11 -0
  60. package/dist/browser/liveViewPersisted.js +22 -0
  61. package/dist/browser/liveViewRelay.d.ts +76 -0
  62. package/dist/browser/liveViewRelay.js +1 -0
  63. package/dist/browser/liveViewSessions.d.ts +25 -0
  64. package/dist/browser/liveViewSessions.js +139 -0
  65. package/dist/browser/liveViewSource.d.ts +25 -0
  66. package/dist/browser/liveViewSource.js +7 -0
  67. package/dist/browser/liveViewTickets.d.ts +46 -0
  68. package/dist/browser/liveViewTickets.js +122 -0
  69. package/dist/browser/localBrowserHost.d.ts +10 -0
  70. package/dist/browser/localBrowserHost.js +53 -7
  71. package/dist/browser/ownerScope.d.ts +10 -0
  72. package/dist/browser/ownerScope.js +6 -0
  73. package/dist/browser/profileStore.d.ts +5 -2
  74. package/dist/browser/profileStore.js +3 -5
  75. package/dist/browser/sandboxOrchestrator.d.ts +60 -0
  76. package/dist/browser/sandboxOrchestrator.js +8 -0
  77. package/dist/browser/sessionApiSandboxOrchestrator.d.ts +34 -0
  78. package/dist/browser/sessionApiSandboxOrchestrator.js +108 -0
  79. package/dist/browser/stageBrowserEnv.d.ts +7 -0
  80. package/dist/browser/stageBrowserEnv.js +53 -15
  81. package/dist/browser/stageHandoff.d.ts +47 -0
  82. package/dist/browser/stageHandoff.js +101 -0
  83. package/dist/browser/stageProfileLock.d.ts +1 -0
  84. package/dist/browser/stageProfileLock.js +1 -3
  85. package/dist/browser/volumeProfileStore.d.ts +7 -0
  86. package/dist/browser/volumeProfileStore.js +35 -0
  87. package/dist/channels/config.d.ts +11 -0
  88. package/dist/channels/config.js +95 -0
  89. package/dist/channels/configWriter.d.ts +40 -0
  90. package/dist/channels/configWriter.js +148 -0
  91. package/dist/channels/connectionEdits.d.ts +34 -0
  92. package/dist/channels/connectionEdits.js +53 -0
  93. package/dist/channels/errorInfo.d.ts +18 -0
  94. package/dist/channels/errorInfo.js +71 -0
  95. package/dist/channels/errors.d.ts +12 -0
  96. package/dist/channels/errors.js +13 -0
  97. package/dist/channels/health.d.ts +41 -0
  98. package/dist/channels/health.js +99 -0
  99. package/dist/channels/host.d.ts +55 -0
  100. package/dist/channels/host.js +185 -0
  101. package/dist/channels/http.d.ts +31 -0
  102. package/dist/channels/http.js +79 -0
  103. package/dist/channels/index.d.ts +10 -0
  104. package/dist/channels/index.js +9 -0
  105. package/dist/channels/ledger.d.ts +37 -0
  106. package/dist/channels/ledger.js +95 -0
  107. package/dist/channels/providers/agentmail.d.ts +26 -0
  108. package/dist/channels/providers/agentmail.js +81 -0
  109. package/dist/channels/providers/kit.d.ts +40 -0
  110. package/dist/channels/providers/kit.js +78 -0
  111. package/dist/channels/providers/photonImessage.d.ts +45 -0
  112. package/dist/channels/providers/photonImessage.js +152 -0
  113. package/dist/channels/providers/photonWhatsapp.d.ts +49 -0
  114. package/dist/channels/providers/photonWhatsapp.js +146 -0
  115. package/dist/channels/providers/slack.d.ts +25 -0
  116. package/dist/channels/providers/slack.js +101 -0
  117. package/dist/channels/providers/telegram.d.ts +21 -0
  118. package/dist/channels/providers/telegram.js +100 -0
  119. package/dist/channels/providers.d.ts +5 -0
  120. package/dist/channels/providers.js +22 -0
  121. package/dist/channels/registry.d.ts +54 -0
  122. package/dist/channels/registry.js +186 -0
  123. package/dist/channels/secretStore.d.ts +21 -0
  124. package/dist/channels/secretStore.js +75 -0
  125. package/dist/channels/secrets.d.ts +15 -0
  126. package/dist/channels/secrets.js +50 -0
  127. package/dist/channels/service.d.ts +54 -0
  128. package/dist/channels/service.js +307 -0
  129. package/dist/channels/stageChannels.d.ts +45 -0
  130. package/dist/channels/stageChannels.js +110 -0
  131. package/dist/channels/types.d.ts +142 -0
  132. package/dist/channels/types.js +1 -0
  133. package/dist/cli/browserCommand.d.ts +3 -1
  134. package/dist/cli/browserCommand.js +25 -20
  135. package/dist/cli/doctorCommand.js +3 -1
  136. package/dist/cli/resolveCliProjectRoot.d.ts +7 -0
  137. package/dist/cli/resolveCliProjectRoot.js +27 -0
  138. package/dist/cli/runCommand.d.ts +1 -1
  139. package/dist/cli/runCommand.js +59 -17
  140. package/dist/cli/skillsCommand.d.ts +20 -0
  141. package/dist/cli/skillsCommand.js +74 -31
  142. package/dist/cli/validateCommand.d.ts +1 -1
  143. package/dist/cli/validateCommand.js +22 -4
  144. package/dist/cli.js +4 -4
  145. package/dist/config/browseCatalog.d.ts +2 -0
  146. package/dist/config/browseCatalog.js +6 -0
  147. package/dist/config/catalogRelativePath.d.ts +4 -0
  148. package/dist/config/catalogRelativePath.js +37 -9
  149. package/dist/config/createStage.d.ts +1 -0
  150. package/dist/config/createStage.js +11 -2
  151. package/dist/config/createTask.d.ts +30 -0
  152. package/dist/config/createTask.js +161 -0
  153. package/dist/config/createTrigger.d.ts +15 -0
  154. package/dist/config/createTrigger.js +32 -25
  155. package/dist/config/draftPackage.d.ts +42 -0
  156. package/dist/config/draftPackage.js +220 -23
  157. package/dist/config/ensureCatalogScanRoot.d.ts +2 -1
  158. package/dist/config/ensureCatalogScanRoot.js +6 -2
  159. package/dist/config/findTaskInCatalog.d.ts +33 -0
  160. package/dist/config/findTaskInCatalog.js +69 -0
  161. package/dist/config/hostConfig.d.ts +21 -0
  162. package/dist/config/hostConfig.js +114 -1
  163. package/dist/config/importTask.d.ts +19 -0
  164. package/dist/config/importTask.js +133 -0
  165. package/dist/config/installSkillRequest.d.ts +40 -0
  166. package/dist/config/installSkillRequest.js +286 -0
  167. package/dist/config/loadOutcome.d.ts +11 -6
  168. package/dist/config/loadPipeline.js +27 -4
  169. package/dist/config/loadStage.js +17 -0
  170. package/dist/config/loadStageflowManifest.js +4 -1
  171. package/dist/config/loadTask.js +2 -0
  172. package/dist/config/loadTrigger.js +2 -0
  173. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  174. package/dist/config/mergePipelineIncludes.js +30 -0
  175. package/dist/config/normalizePipelineStageEntry.js +10 -1
  176. package/dist/config/pipelineStageKeys.js +1 -0
  177. package/dist/config/printTargetYaml.js +0 -1
  178. package/dist/config/publishDraftPackage.d.ts +5 -1
  179. package/dist/config/publishDraftPackage.js +4 -1
  180. package/dist/config/resolveCatalogRoots.d.ts +4 -1
  181. package/dist/config/resolveCatalogRoots.js +18 -1
  182. package/dist/config/skillUsageIndex.d.ts +6 -0
  183. package/dist/config/skillUsageIndex.js +39 -0
  184. package/dist/config/stageBrowser.js +13 -0
  185. package/dist/config/triggerAdapterStatus.d.ts +11 -0
  186. package/dist/config/triggerAdapterStatus.js +90 -0
  187. package/dist/config/triggerCatalog.d.ts +41 -2
  188. package/dist/config/triggerCatalog.js +107 -15
  189. package/dist/config/updateTask.d.ts +30 -0
  190. package/dist/config/updateTask.js +119 -0
  191. package/dist/config/updateTrigger.d.ts +38 -0
  192. package/dist/config/updateTrigger.js +220 -0
  193. package/dist/config/validateCatalog.d.ts +9 -2
  194. package/dist/config/validateCatalog.js +71 -7
  195. package/dist/config/workshopCatalogFilenames.d.ts +37 -0
  196. package/dist/config/workshopCatalogFilenames.js +125 -0
  197. package/dist/config/workshopCatalogRepair.d.ts +7 -0
  198. package/dist/config/workshopCatalogRepair.js +144 -0
  199. package/dist/config/yamlParsePosition.d.ts +4 -0
  200. package/dist/config/yamlParsePosition.js +9 -0
  201. package/dist/errors/codes.d.ts +1 -1
  202. package/dist/errors/codes.js +1 -0
  203. package/dist/hosted/runtime.d.ts +2 -2
  204. package/dist/hosted/types.d.ts +1 -1
  205. package/dist/hosted/types.js +1 -1
  206. package/dist/index.d.ts +3 -2
  207. package/dist/index.js +2 -1
  208. package/dist/mcp/catalogTools.js +1 -0
  209. package/dist/mcp/getStartedTool.js +15 -6
  210. package/dist/mcp/triggerTools.js +2 -8
  211. package/dist/operatorAgent/agentPort.d.ts +11 -0
  212. package/dist/operatorAgent/agentPort.js +12 -0
  213. package/dist/operatorAgent/index.d.ts +1 -0
  214. package/dist/operatorAgent/index.js +1 -0
  215. package/dist/operatorAgent/piModel.js +26 -6
  216. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
  217. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +4 -2
  218. package/dist/operatorAgent/profiles/workshopAuthorTools.js +103 -16
  219. package/dist/package-meta.d.ts +1 -1
  220. package/dist/package-meta.js +1 -1
  221. package/dist/preflight/channelChecks.d.ts +17 -0
  222. package/dist/preflight/channelChecks.js +106 -0
  223. package/dist/preflight/pipelinePreflight.d.ts +9 -2
  224. package/dist/preflight/pipelinePreflight.js +9 -1
  225. package/dist/project/ensureProjectRootsFromEnv.d.ts +3 -0
  226. package/dist/project/ensureProjectRootsFromEnv.js +22 -0
  227. package/dist/project/globalHome.d.ts +1 -0
  228. package/dist/project/globalHome.js +18 -0
  229. package/dist/project/workspaceCatalog.d.ts +10 -0
  230. package/dist/project/workspaceCatalog.js +91 -0
  231. package/dist/runstore/backup.js +14 -4
  232. package/dist/runstore/port.d.ts +11 -1
  233. package/dist/runstore/restore.js +5 -2
  234. package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -0
  235. package/dist/runstore/sqlite/SqliteRunStore.js +29 -9
  236. package/dist/runstore/sqlite/migrations/012-trigger-fires.d.ts +7 -0
  237. package/dist/runstore/sqlite/migrations/012-trigger-fires.js +18 -0
  238. package/dist/runstore/sqlite/migrations/index.js +2 -0
  239. package/dist/runstore/stageSnapshot.d.ts +3 -1
  240. package/dist/runstore/stageSnapshot.js +19 -0
  241. package/dist/runstore/workspaceLayout.js +27 -0
  242. package/dist/runstore/writeContainedArtifact.d.ts +1 -0
  243. package/dist/runstore/writeContainedArtifact.js +52 -0
  244. package/dist/runtime/credentialBinding.js +14 -6
  245. package/dist/runtime/emailSource.js +20 -28
  246. package/dist/runtime/githubPollSource.js +20 -28
  247. package/dist/runtime/pipelineRunner.d.ts +4 -4
  248. package/dist/runtime/pipelineRunner.js +3 -1
  249. package/dist/runtime/pipelineScheduler.d.ts +2 -2
  250. package/dist/runtime/pipelineScheduler.js +3 -0
  251. package/dist/runtime/repositoryMaterialize.d.ts +1 -1
  252. package/dist/runtime/resumeReconstruct.d.ts +2 -2
  253. package/dist/runtime/resumeTimedOut.d.ts +2 -2
  254. package/dist/runtime/runManager.d.ts +18 -2
  255. package/dist/runtime/runManager.js +99 -31
  256. package/dist/runtime/runRetryCoordinator.d.ts +2 -2
  257. package/dist/runtime/scheduleSource.js +15 -24
  258. package/dist/runtime/stageAttemptBootstrap.d.ts +2 -2
  259. package/dist/runtime/stageAttemptBootstrap.js +26 -1
  260. package/dist/runtime/stageProcessLauncher.js +33 -3
  261. package/dist/runtime/stageRoots.js +8 -1
  262. package/dist/runtime/stageRunner.d.ts +2 -2
  263. package/dist/runtime/stageRunner.js +8 -2
  264. package/dist/runtime/stageWorker.js +2 -2
  265. package/dist/runtime/triggerPort.d.ts +5 -3
  266. package/dist/runtime/triggerRunner.d.ts +1 -0
  267. package/dist/runtime/triggerRunner.js +27 -20
  268. package/dist/runtime/webhookAccept.d.ts +25 -0
  269. package/dist/runtime/webhookAccept.js +56 -0
  270. package/dist/server/bootstrap.d.ts +10 -2
  271. package/dist/server/bootstrap.js +19 -1
  272. package/dist/server/channelRoutes.d.ts +9 -0
  273. package/dist/server/channelRoutes.js +88 -0
  274. package/dist/server/controlToken.d.ts +1 -1
  275. package/dist/server/controlToken.js +18 -2
  276. package/dist/server/healthSurfaces.d.ts +12 -0
  277. package/dist/server/healthSurfaces.js +27 -6
  278. package/dist/server/http.d.ts +19 -10
  279. package/dist/server/http.js +616 -85
  280. package/dist/server/liveViewPath.d.ts +9 -0
  281. package/dist/server/liveViewPath.js +8 -0
  282. package/dist/server/liveViewRoutes.d.ts +58 -0
  283. package/dist/server/liveViewRoutes.js +565 -0
  284. package/dist/server/mcpHost.d.ts +4 -2
  285. package/dist/server/mcpHost.js +2 -0
  286. package/dist/server/readCatalogFile.d.ts +29 -0
  287. package/dist/server/readCatalogFile.js +215 -0
  288. package/dist/server/triggerRoutes.d.ts +1 -0
  289. package/dist/server/triggerRoutes.js +200 -73
  290. package/dist/tools/sendMessage.d.ts +21 -0
  291. package/dist/tools/sendMessage.js +25 -0
  292. package/dist/tools/writeStageArtifact.d.ts +9 -0
  293. package/dist/tools/writeStageArtifact.js +2 -47
  294. package/dist/types/pipeline.d.ts +5 -2
  295. package/dist/types/stage.d.ts +14 -1
  296. package/dist/types/stageflowManifest.d.ts +1 -1
  297. package/dist/ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  298. package/dist/ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  299. package/dist/ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  300. package/dist/ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  301. package/dist/ui/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  302. package/dist/ui/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  303. package/dist/ui/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  304. package/dist/ui/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  305. package/dist/ui/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  306. package/dist/ui/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  307. package/dist/ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  308. package/dist/ui/assets/index-BOhqnPNg.js +260 -0
  309. package/dist/ui/assets/{index-Bv4p1aPK.css → index-Clv4sJpU.css} +1 -1
  310. package/dist/ui/index.html +4 -4
  311. package/dist/workshop/autosave.d.ts +2 -2
  312. package/dist/workshop/autosave.js +4 -6
  313. package/dist/workshop/buildStore.d.ts +2 -0
  314. package/dist/workshop/chatAttachments.d.ts +27 -0
  315. package/dist/workshop/chatAttachments.js +98 -0
  316. package/dist/workshop/chatTurn.d.ts +5 -2
  317. package/dist/workshop/chatTurn.js +22 -18
  318. package/dist/workshop/sessionMutations.d.ts +17 -0
  319. package/dist/workshop/sessionMutations.js +107 -0
  320. package/dist/workshop/sessionStore.d.ts +10 -0
  321. package/dist/workshop/sessionStore.js +52 -0
  322. package/dist/workshop/workshopPin.d.ts +4 -3
  323. package/dist/workshop/workshopPin.js +26 -6
  324. package/dist/workshop/workshopTranscriptTurn.d.ts +8 -0
  325. package/dist/workshop/workshopTranscriptTurn.js +46 -0
  326. package/examples/README.md +1 -1
  327. package/examples/archify-on-pr/README.md +1 -1
  328. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +0 -1
  329. package/examples/archify-on-pr/author-diagrams.yaml +1 -0
  330. package/examples/channels-smoke/README.md +12 -0
  331. package/examples/channels-smoke/channels-smoke.pipeline.yaml +11 -0
  332. package/examples/channels-smoke/channels-smoke.task.yaml +3 -0
  333. package/examples/channels-smoke/send-email.yaml +32 -0
  334. package/examples/channels-smoke/send-text.yaml +31 -0
  335. package/examples/conditional-fork/branch-a.yaml +1 -1
  336. package/examples/conditional-fork/decide.yaml +2 -1
  337. package/examples/feature-loop/{implement.yaml → feature-implement.yaml} +1 -1
  338. package/examples/feature-loop/feature-loop.pipeline.yaml +10 -10
  339. package/examples/feature-loop/{plan.yaml → feature-plan.yaml} +1 -1
  340. package/examples/feature-loop/{review.yaml → feature-review.yaml} +1 -1
  341. package/examples/feedback-loop/{implement.yaml → feedback-implement.yaml} +1 -1
  342. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +9 -9
  343. package/examples/feedback-loop/feedback-loop.pipeline.yaml +9 -9
  344. package/examples/feedback-loop/{plan.yaml → feedback-plan.yaml} +1 -1
  345. package/examples/feedback-loop/{review.yaml → feedback-review.yaml} +1 -1
  346. package/examples/generic-fan-in/{research.yaml → fan-in-research.yaml} +1 -1
  347. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +3 -3
  348. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +3 -3
  349. package/examples/hello-world/{research.yaml → hello-research.yaml} +1 -1
  350. package/examples/hello-world/hello.pipeline.yaml +2 -2
  351. package/examples/mcp-hitl-tour/{review.yaml → mcp-hitl-review.yaml} +1 -1
  352. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +3 -3
  353. package/examples/oss-issue-contribution/oss-explain-fix.yaml +1 -0
  354. package/examples/oss-issue-contribution/oss-explain-issue.yaml +1 -0
  355. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +0 -2
  356. package/examples/stageflow.yaml +6 -0
  357. package/examples/triggers/sample-github-pr.trigger.yaml +12 -0
  358. package/examples/triggers/sample-inbox-email.trigger.yaml +14 -0
  359. package/examples/triggers/sample-manual-hello.trigger.yaml +5 -0
  360. package/examples/triggers/sample-nightly-hello.trigger.yaml +8 -0
  361. package/examples/triggers/sample-signed-webhook.trigger.yaml +11 -0
  362. package/examples/triggers-readiness/README.md +48 -0
  363. package/examples/triggers-readiness/readiness-emit.yaml +18 -0
  364. package/examples/triggers-readiness/readiness.pipeline.yaml +4 -0
  365. package/examples/triggers-readiness/readiness.task.yaml +6 -0
  366. package/examples/triggers-readiness/stageflow.yaml +13 -0
  367. package/examples/triggers-readiness/triggers/readiness-dynamic-manual.trigger.yaml +4 -0
  368. package/examples/triggers-readiness/triggers/readiness-email.trigger.yaml +12 -0
  369. package/examples/triggers-readiness/triggers/readiness-github-pr.trigger.yaml +12 -0
  370. package/examples/triggers-readiness/triggers/readiness-manual.trigger.yaml +5 -0
  371. package/examples/triggers-readiness/triggers/readiness-schedule.trigger.yaml +8 -0
  372. package/examples/triggers-readiness/triggers/readiness-webhook.trigger.yaml +11 -0
  373. package/package.json +8 -3
  374. package/skills/stageflow/references/control-surface.md +1 -1
  375. package/skills/stageflow-author/references/catalog-write-conventions.md +2 -2
  376. package/skills/stageflow-run/SKILL.md +1 -1
  377. package/skills/stageflow-run/references/mcp-call.md +1 -1
  378. package/skills/stageflow-setup/SKILL.md +1 -1
  379. package/dist/ui/assets/index-59cjF0OA.js +0 -133
@@ -1,4 +1,4 @@
1
- import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
1
+ import { access, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import path from "node:path";
4
4
  import { loadPipelineOutcome } from "./loadPipeline.js";
@@ -6,6 +6,8 @@ import { parseTaskFile } from "./loadTask.js";
6
6
  import { stringifyTargetYaml } from "./printTargetYaml.js";
7
7
  import { readYamlObject } from "./readYamlObject.js";
8
8
  import { buildValidationResult, findingsFromLoadIssues, loadPipelineValidated, validatePipeline, } from "./validateCatalog.js";
9
+ import { normalizeDraftCatalogFilenames, taskIdFromDraftTask, } from "./workshopCatalogFilenames.js";
10
+ import { reconcileWorkshopCatalogPackageDir } from "./workshopCatalogRepair.js";
9
11
  function isPlainObject(value) {
10
12
  return value !== null && typeof value === "object" && !Array.isArray(value);
11
13
  }
@@ -15,10 +17,57 @@ function normalizeStageRelPath(stagePath) {
15
17
  function pipelineHasExternalUses(pipeline) {
16
18
  return pipeline.stages.some((stage) => typeof stage.uses === "string" && stage.uses.trim().length > 0);
17
19
  }
20
+ function stripUsesWrapperSkill(stages) {
21
+ return stages.map((stage) => {
22
+ if (typeof stage.uses !== "string" || stage.skill === undefined)
23
+ return stage;
24
+ const { skill: _skill, ...rest } = stage;
25
+ return rest;
26
+ });
27
+ }
28
+ /** Move uses-wrapper skill: onto the matching stage artifact body, then clear the wrapper. */
29
+ export function hoistUsesWrapperSkills(draft) {
30
+ const artifacts = draft.stages ? [...draft.stages] : [];
31
+ const byPath = new Map(artifacts.map((artifact, index) => [
32
+ normalizeStageRelPath(artifact.path),
33
+ index,
34
+ ]));
35
+ const stages = draft.pipeline.stages.map((stage) => {
36
+ if (typeof stage.uses !== "string" || stage.skill === undefined)
37
+ return stage;
38
+ const skill = typeof stage.skill === "string" && stage.skill.trim()
39
+ ? stage.skill.trim()
40
+ : undefined;
41
+ if (skill === undefined) {
42
+ const { skill: _skill, ...rest } = stage;
43
+ return rest;
44
+ }
45
+ const key = normalizeStageRelPath(stage.uses);
46
+ const index = byPath.get(key);
47
+ if (index !== undefined) {
48
+ const current = artifacts[index];
49
+ const bodySkill = current.body.skill;
50
+ const bodyHasSkill = typeof bodySkill === "string" && bodySkill.trim().length > 0;
51
+ if (!bodyHasSkill) {
52
+ artifacts[index] = {
53
+ ...current,
54
+ body: { ...current.body, skill },
55
+ };
56
+ }
57
+ }
58
+ const { skill: _skill, ...rest } = stage;
59
+ return rest;
60
+ });
61
+ return {
62
+ ...draft,
63
+ pipeline: { ...draft.pipeline, stages },
64
+ ...(artifacts.length > 0 ? { stages: artifacts } : {}),
65
+ };
66
+ }
18
67
  function pipelineDocument(pipeline) {
19
68
  const doc = {
20
69
  id: pipeline.id,
21
- stages: pipeline.stages,
70
+ stages: stripUsesWrapperSkill(pipeline.stages),
22
71
  };
23
72
  if (pipeline.agent !== undefined)
24
73
  doc.agent = pipeline.agent;
@@ -28,6 +77,8 @@ function pipelineDocument(pipeline) {
28
77
  doc.schemas = pipeline.schemas;
29
78
  if (pipeline.requires !== undefined)
30
79
  doc.requires = pipeline.requires;
80
+ if (pipeline.channels !== undefined)
81
+ doc.channels = pipeline.channels;
31
82
  return doc;
32
83
  }
33
84
  function resolveDirectory(projectRoot, directory) {
@@ -48,9 +99,10 @@ async function fileExists(filePath) {
48
99
  }
49
100
  }
50
101
  async function materializeDraft(draft, dir, pipelineFilename) {
102
+ const migrated = hoistUsesWrapperSkills(draft);
51
103
  await mkdir(dir, { recursive: true });
52
- await writeFile(path.join(dir, pipelineFilename), stringifyTargetYaml(pipelineDocument(draft.pipeline)), "utf8");
53
- for (const stage of draft.stages ?? []) {
104
+ await writeFile(path.join(dir, pipelineFilename), stringifyTargetYaml(pipelineDocument(migrated.pipeline)), "utf8");
105
+ for (const stage of migrated.stages ?? []) {
54
106
  const rel = normalizeStageRelPath(stage.path);
55
107
  const stagePath = path.join(dir, rel);
56
108
  await mkdir(path.dirname(stagePath), { recursive: true });
@@ -114,6 +166,7 @@ export async function validateDraftPackage(draft, options = {}) {
114
166
  ...(draft.pipeline.requires !== undefined
115
167
  ? { requires: draft.pipeline.requires }
116
168
  : {}),
169
+ ...(draft.pipeline.channels !== undefined ? { channels: draft.pipeline.channels } : {}),
117
170
  };
118
171
  const result = await loadPipelineValidated(inline, {
119
172
  cwd,
@@ -185,11 +238,13 @@ function resolveDraftWriteTarget(projectRoot, input) {
185
238
  error: "directory must be inside the project root",
186
239
  };
187
240
  }
188
- const draft = input.draft;
189
- if (!isPlainObject(draft?.pipeline) || typeof draft.pipeline.id !== "string") {
241
+ const rawDraft = input.draft;
242
+ if (!isPlainObject(rawDraft?.pipeline) || typeof rawDraft.pipeline.id !== "string") {
190
243
  return { ok: false, status: 400, error: "draft.pipeline.id is required" };
191
244
  }
192
- const pipelineFilename = input.pipelineFilename?.trim() || `${draft.pipeline.id}.pipeline.yaml`;
245
+ const normalized = normalizeDraftCatalogFilenames(rawDraft, input.pipelineFilename?.trim());
246
+ const draft = hoistUsesWrapperSkills(normalized.draft);
247
+ const pipelineFilename = normalized.pipelineFilename;
193
248
  const pipelineAbsPath = path.join(packageDirectory, path.basename(pipelineFilename));
194
249
  const pipelineRelPath = path
195
250
  .relative(projectRoot, pipelineAbsPath)
@@ -223,9 +278,17 @@ async function gateDraftWrite(projectRoot, draft, allowInvalid) {
223
278
  findings: validation.findings,
224
279
  };
225
280
  }
226
- async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
281
+ function resolveDraftWriteFiles(projectRoot, target) {
227
282
  const { packageDirectory, draft, pipelineAbsPath, pipelineRelPath } = target;
228
- const stagePaths = [];
283
+ const toRel = (abs) => path.relative(projectRoot, abs).replace(/\\/g, "/");
284
+ const files = [
285
+ {
286
+ kind: "pipeline",
287
+ absPath: pipelineAbsPath,
288
+ relPath: pipelineRelPath,
289
+ content: stringifyTargetYaml(pipelineDocument(draft.pipeline)),
290
+ },
291
+ ];
229
292
  for (const stage of draft.stages ?? []) {
230
293
  const rel = normalizeStageRelPath(stage.path);
231
294
  if (!rel || path.isAbsolute(rel) || rel.split(/[/\\]/).includes("..")) {
@@ -244,23 +307,39 @@ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
244
307
  error: `Stage path escapes package directory (${stage.path})`,
245
308
  };
246
309
  }
310
+ files.push({
311
+ kind: "stage",
312
+ absPath: stageAbs,
313
+ relPath: toRel(stageAbs),
314
+ content: stringifyTargetYaml(stage.body),
315
+ });
247
316
  }
317
+ if (draft.task) {
318
+ const taskAbs = path.join(packageDirectory, path.basename(draft.task.filename));
319
+ files.push({
320
+ kind: "task",
321
+ absPath: taskAbs,
322
+ relPath: toRel(taskAbs),
323
+ content: stringifyTargetYaml(draft.task.body),
324
+ });
325
+ }
326
+ return { ok: true, files };
327
+ }
328
+ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
329
+ const { packageDirectory, draft, pipelineRelPath } = target;
330
+ const resolved = resolveDraftWriteFiles(projectRoot, target);
331
+ if (!resolved.ok)
332
+ return resolved;
248
333
  try {
249
334
  await mkdir(packageDirectory, { recursive: true });
250
- await writeFile(pipelineAbsPath, stringifyTargetYaml(pipelineDocument(draft.pipeline)), "utf8");
251
- for (const stage of draft.stages ?? []) {
252
- const rel = normalizeStageRelPath(stage.path);
253
- const stageAbs = path.resolve(packageDirectory, rel);
254
- await mkdir(path.dirname(stageAbs), { recursive: true });
255
- await writeFile(stageAbs, stringifyTargetYaml(stage.body), "utf8");
256
- stagePaths.push(path.relative(projectRoot, stageAbs).replace(/\\/g, "/"));
257
- }
258
- let taskPath;
259
- if (draft.task) {
260
- const taskAbs = path.join(packageDirectory, path.basename(draft.task.filename));
261
- await writeFile(taskAbs, stringifyTargetYaml(draft.task.body), "utf8");
262
- taskPath = path.relative(projectRoot, taskAbs).replace(/\\/g, "/");
335
+ for (const file of resolved.files) {
336
+ await mkdir(path.dirname(file.absPath), { recursive: true });
337
+ await writeFile(file.absPath, file.content, "utf8");
263
338
  }
339
+ const stagePaths = resolved.files
340
+ .filter((file) => file.kind === "stage")
341
+ .map((file) => file.relPath);
342
+ const taskPath = resolved.files.find((file) => file.kind === "task")?.relPath;
264
343
  const loadOutcome = await loadPipelineOutcome(pipelineRelPath, {
265
344
  cwd: projectRoot,
266
345
  });
@@ -274,6 +353,11 @@ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
274
353
  error: loadOutcome.issues[0]?.message ?? "Failed to load written pipeline",
275
354
  };
276
355
  }
356
+ const taskId = draft.task ? taskIdFromDraftTask(draft.task) : null;
357
+ await reconcileWorkshopCatalogPackageDir(packageDirectory, draft.pipeline.id, taskId, {
358
+ pipelineBasename: path.basename(target.pipelineAbsPath),
359
+ taskBasename: draft.task ? path.basename(draft.task.filename) : null,
360
+ });
277
361
  return {
278
362
  ok: true,
279
363
  pipeline,
@@ -287,10 +371,22 @@ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
287
371
  return { ok: false, status: 500, error: message };
288
372
  }
289
373
  }
374
+ async function prepareDraftPackageDirectory(target) {
375
+ const taskId = target.draft.task
376
+ ? taskIdFromDraftTask(target.draft.task)
377
+ : null;
378
+ await reconcileWorkshopCatalogPackageDir(target.packageDirectory, target.draft.pipeline.id, taskId, {
379
+ pipelineBasename: path.basename(target.pipelineAbsPath),
380
+ taskBasename: target.draft.task
381
+ ? path.basename(path.join(target.packageDirectory, path.basename(target.draft.task.filename)))
382
+ : null,
383
+ });
384
+ }
290
385
  export async function overwriteDraftPackage(projectRoot, input) {
291
386
  const resolved = resolveDraftWriteTarget(projectRoot, input);
292
387
  if (!resolved.ok)
293
388
  return resolved;
389
+ await prepareDraftPackageDirectory(resolved.value);
294
390
  if (!(await fileExists(resolved.value.pipelineAbsPath))) {
295
391
  return {
296
392
  ok: false,
@@ -307,6 +403,7 @@ export async function createDraftPackage(projectRoot, input) {
307
403
  const resolved = resolveDraftWriteTarget(projectRoot, input);
308
404
  if (!resolved.ok)
309
405
  return resolved;
406
+ await prepareDraftPackageDirectory(resolved.value);
310
407
  if (await fileExists(resolved.value.pipelineAbsPath)) {
311
408
  return {
312
409
  ok: false,
@@ -319,6 +416,104 @@ export async function createDraftPackage(projectRoot, input) {
319
416
  return blocked;
320
417
  return writeDraftPackageFiles(projectRoot, resolved.value, input.allowInvalid);
321
418
  }
419
+ function splitLines(text) {
420
+ if (!text)
421
+ return [];
422
+ return (text.endsWith("\n") ? text.slice(0, -1) : text).split("\n");
423
+ }
424
+ export function countLineChanges(before, after) {
425
+ const a = splitLines(before);
426
+ const b = splitLines(after);
427
+ let start = 0;
428
+ while (start < a.length && start < b.length && a[start] === b[start])
429
+ start += 1;
430
+ let endA = a.length;
431
+ let endB = b.length;
432
+ while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {
433
+ endA -= 1;
434
+ endB -= 1;
435
+ }
436
+ const midA = a.slice(start, endA);
437
+ const midB = b.slice(start, endB);
438
+ let prev = new Uint32Array(midB.length + 1);
439
+ let curr = new Uint32Array(midB.length + 1);
440
+ for (const lineA of midA) {
441
+ for (let j = 1; j <= midB.length; j += 1) {
442
+ curr[j] =
443
+ lineA === midB[j - 1] ? prev[j - 1] + 1 : Math.max(prev[j], curr[j - 1]);
444
+ }
445
+ [prev, curr] = [curr, prev];
446
+ }
447
+ const common = prev[midB.length];
448
+ return { added: midB.length - common, removed: midA.length - common };
449
+ }
450
+ async function readExisting(filePath) {
451
+ try {
452
+ return await readFile(filePath, "utf8");
453
+ }
454
+ catch {
455
+ return null;
456
+ }
457
+ }
458
+ export async function planDraftPackage(projectRoot, input, options = {}) {
459
+ const resolved = resolveDraftWriteTarget(projectRoot, input);
460
+ if (!resolved.ok)
461
+ return resolved;
462
+ const writeFiles = resolveDraftWriteFiles(projectRoot, resolved.value);
463
+ if (!writeFiles.ok)
464
+ return writeFiles;
465
+ const files = [];
466
+ for (const file of writeFiles.files) {
467
+ const existing = await readExisting(file.absPath);
468
+ if (existing === null) {
469
+ files.push({
470
+ path: file.relPath,
471
+ kind: file.kind,
472
+ action: "new",
473
+ added: splitLines(file.content).length,
474
+ removed: 0,
475
+ });
476
+ }
477
+ else if (existing === file.content) {
478
+ files.push({
479
+ path: file.relPath,
480
+ kind: file.kind,
481
+ action: "unchanged",
482
+ added: 0,
483
+ removed: 0,
484
+ });
485
+ }
486
+ else {
487
+ files.push({
488
+ path: file.relPath,
489
+ kind: file.kind,
490
+ action: "overwrite",
491
+ ...countLineChanges(existing, file.content),
492
+ });
493
+ }
494
+ }
495
+ const { pipelineRelPath, packageDirectory, draft } = resolved.value;
496
+ const pipelineIdTaken = (options.mode ?? "create") === "create" &&
497
+ (options.catalogPipelines ?? []).some((listing) => listing.id === draft.pipeline.id &&
498
+ listing.path.replace(/\\/g, "/") !== pipelineRelPath);
499
+ return {
500
+ ok: true,
501
+ pipelinePath: pipelineRelPath,
502
+ directory: path.relative(projectRoot, packageDirectory).replace(/\\/g, "/") || ".",
503
+ files,
504
+ pipelineIdTaken,
505
+ };
506
+ }
507
+ export function parsePlanDraftPackageBody(body) {
508
+ const parsed = parseCreateDraftPackageBody(body);
509
+ if ("ok" in parsed)
510
+ return parsed;
511
+ const mode = isPlainObject(body) ? body.mode : undefined;
512
+ if (mode !== undefined && mode !== "create" && mode !== "overwrite") {
513
+ return { ok: false, status: 400, error: 'mode must be "create" or "overwrite"' };
514
+ }
515
+ return { ...parsed, mode: mode ?? "create" };
516
+ }
322
517
  export function parseDraftPackageBody(body) {
323
518
  if (!isPlainObject(body)) {
324
519
  return { ok: false, status: 400, error: "JSON object body required" };
@@ -524,6 +719,7 @@ export async function loadDraftPackage(projectRoot, pipelineRelPath, options = {
524
719
  ...(raw.model !== undefined ? { model: raw.model } : {}),
525
720
  ...(raw.schemas !== undefined ? { schemas: raw.schemas } : {}),
526
721
  ...(raw.requires !== undefined ? { requires: raw.requires } : {}),
722
+ ...(raw.channels !== undefined ? { channels: raw.channels } : {}),
527
723
  },
528
724
  ...(stageArtifacts.length > 0 ? { stages: stageArtifacts } : {}),
529
725
  };
@@ -540,9 +736,10 @@ export async function loadDraftPackage(projectRoot, pipelineRelPath, options = {
540
736
  draft.task = loaded.task;
541
737
  attachedTaskPath = loaded.taskPath;
542
738
  }
739
+ const migrated = hoistUsesWrapperSkills(draft);
543
740
  return {
544
741
  ok: true,
545
- draft,
742
+ draft: migrated,
546
743
  destination: { directory, pipelineFilename },
547
744
  pipelinePath,
548
745
  ...(attachedTaskPath !== undefined ? { taskPath: attachedTaskPath } : {}),
@@ -1,8 +1,9 @@
1
+ import type { CatalogRootKind } from "./resolveCatalogRoots.js";
1
2
  /** Directory scanned for workshop-authored pipelines and tasks. */
2
3
  export declare const WORKSHOP_PACKAGE_ROOT = "workshop";
3
4
  export declare function normalizeCatalogDir(directory: string): string;
4
5
  /** Untitled workshop saves land here so Run can see them without a new catalog edit. */
5
- export declare function defaultWorkshopPackageDirectory(pipelineId: string | undefined): string;
6
+ export declare function defaultWorkshopPackageDirectory(pipelineId: string | undefined, catalogRootKind?: CatalogRootKind): string;
6
7
  /**
7
8
  * Catalog root that covers this package directory.
8
9
  * Packages under `workshop/` share one root. Any other folder is listed itself
@@ -7,13 +7,17 @@ export function normalizeCatalogDir(directory) {
7
7
  return directory.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
8
8
  }
9
9
  /** Untitled workshop saves land here so Run can see them without a new catalog edit. */
10
- export function defaultWorkshopPackageDirectory(pipelineId) {
10
+ export function defaultWorkshopPackageDirectory(pipelineId, catalogRootKind) {
11
11
  const slug = (pipelineId ?? "")
12
12
  .toLowerCase()
13
13
  .replace(/[^a-z0-9]+/g, "-")
14
14
  .replace(/^-+|-+$/g, "")
15
15
  .slice(0, 40);
16
- return `${WORKSHOP_PACKAGE_ROOT}/${slug || "untitled"}`;
16
+ const id = slug || "untitled";
17
+ if (catalogRootKind === "workspace") {
18
+ return id;
19
+ }
20
+ return `${WORKSHOP_PACKAGE_ROOT}/${id}`;
17
21
  }
18
22
  /**
19
23
  * Catalog root that covers this package directory.
@@ -0,0 +1,33 @@
1
+ import type { TaskFile } from "../types/task.js";
2
+ import { type ResolveCatalogRootsOptions } from "./resolveCatalogRoots.js";
3
+ export type TaskDetail = TaskFile & {
4
+ path: string;
5
+ };
6
+ export type TaskDetailWithRoot = TaskDetail & {
7
+ project_root: string;
8
+ };
9
+ export type FindTaskInCatalogMultiResult = {
10
+ ok: true;
11
+ task: TaskDetailWithRoot;
12
+ } | {
13
+ ok: false;
14
+ status: 404;
15
+ error: string;
16
+ } | {
17
+ ok: false;
18
+ status: 400;
19
+ error: string;
20
+ code: "unknown_project_root";
21
+ } | {
22
+ ok: false;
23
+ status: 409;
24
+ error: string;
25
+ code: "ambiguous_task";
26
+ project_roots: string[];
27
+ };
28
+ export declare function findTaskInProjectRoot(projectRoot: string, taskId: string): Promise<TaskDetail | null>;
29
+ export declare function findTaskInCatalogMulti(options: ResolveCatalogRootsOptions & {
30
+ taskId: string;
31
+ projectRootFilter?: string;
32
+ }): Promise<FindTaskInCatalogMultiResult>;
33
+ export declare function findTaskInCatalog(cwd: string, taskId: string): Promise<TaskDetail | null>;
@@ -0,0 +1,69 @@
1
+ import path from "node:path";
2
+ import { getCatalogScanPaths } from "./browseCatalog.js";
3
+ import { loadTaskOutcome } from "./loadTask.js";
4
+ import { listTasksMultiProject } from "./multiProjectCatalog.js";
5
+ import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
6
+ import { findCatalogRoot, } from "./resolveCatalogRoots.js";
7
+ import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
8
+ export async function findTaskInProjectRoot(projectRoot, taskId) {
9
+ const ctx = catalogContextFromStageflow(await resolveStageflowContext(projectRoot));
10
+ const scanPaths = await getCatalogScanPaths(ctx);
11
+ if (!scanPaths || ctx.projectRoot === null) {
12
+ return null;
13
+ }
14
+ const root = ctx.projectRoot;
15
+ for (const filePath of scanPaths.taskPaths) {
16
+ const outcome = await loadTaskOutcome(filePath);
17
+ if (!outcome.ok || outcome.value.id !== taskId) {
18
+ continue;
19
+ }
20
+ return {
21
+ ...outcome.value,
22
+ path: path.relative(root, filePath).replace(/\\/g, "/"),
23
+ };
24
+ }
25
+ return null;
26
+ }
27
+ export async function findTaskInCatalogMulti(options) {
28
+ const { taskId, projectRootFilter, ...rootOptions } = options;
29
+ const listed = await listTasksMultiProject({
30
+ ...rootOptions,
31
+ projectRootFilter,
32
+ });
33
+ if (projectRootFilter !== undefined &&
34
+ listed.root_errors.some((e) => e.code === "unknown_project_root")) {
35
+ return {
36
+ ok: false,
37
+ status: 400,
38
+ error: listed.root_errors[0].message,
39
+ code: "unknown_project_root",
40
+ };
41
+ }
42
+ const matches = listed.items.filter((t) => t.id === taskId);
43
+ if (matches.length === 0) {
44
+ return { ok: false, status: 404, error: `Task not found: ${taskId}` };
45
+ }
46
+ const projectRoots = [...new Set(matches.map((m) => m.project_root))];
47
+ if (projectRoots.length > 1) {
48
+ return {
49
+ ok: false,
50
+ status: 409,
51
+ error: `Task id is ambiguous across catalog roots: ${taskId}`,
52
+ code: "ambiguous_task",
53
+ project_roots: projectRoots.sort((a, b) => a.localeCompare(b)),
54
+ };
55
+ }
56
+ const wireRoot = projectRoots[0];
57
+ const catalogRoot = findCatalogRoot(listed.roots, wireRoot);
58
+ if (catalogRoot === undefined) {
59
+ return { ok: false, status: 404, error: `Task not found: ${taskId}` };
60
+ }
61
+ const detail = await findTaskInProjectRoot(catalogRoot.path, taskId);
62
+ if (!detail) {
63
+ return { ok: false, status: 404, error: `Task not found: ${taskId}` };
64
+ }
65
+ return { ok: true, task: { ...detail, project_root: wireRoot } };
66
+ }
67
+ export async function findTaskInCatalog(cwd, taskId) {
68
+ return findTaskInProjectRoot(cwd, taskId);
69
+ }
@@ -9,6 +9,14 @@ export declare const KNOWN_STAGEFLOW_ENV_KEYS: Set<string>;
9
9
  export type CallerQuotaConfig = {
10
10
  maxConcurrent: number;
11
11
  };
12
+ export declare const DEFAULT_BROWSER_DIALOG_TIMEOUT_SECONDS = 60;
13
+ export type BrowserContainerConfig = {
14
+ image: string;
15
+ shmSize: string;
16
+ memory: string;
17
+ pidsLimit: number;
18
+ };
19
+ export declare const DEFAULT_BROWSER_CONTAINER_IMAGE = "stageflow-browser-sandbox:local";
12
20
  export type HostConfig = {
13
21
  maxConcurrentRuns: number;
14
22
  maxConcurrentRunsPerProject: number | undefined;
@@ -22,6 +30,18 @@ export type HostConfig = {
22
30
  callers: Record<string, CallerQuotaConfig>;
23
31
  /** Domains no browser stage may use (`browser.blocked_sites` in config.yaml). */
24
32
  browserBlockedSites: string[];
33
+ /** Chrome launch arguments (`browser.launch_args`); empty when unset. */
34
+ browserLaunchArgs: string[];
35
+ /** Explicit Chrome path (`browser.executable_path`); undefined when unset. */
36
+ browserExecutablePath: string | undefined;
37
+ /** Seconds an unanswered live view page dialog waits before the Host dismisses it (`browser.dialog_timeout_seconds`). */
38
+ browserDialogTimeoutSeconds: number;
39
+ /** Where shared profile browsers run (`browser.host`): this machine, or one container per run. */
40
+ browserHost: "local" | "container";
41
+ /** Per-owner adapter override (`browser.owner_hosts`, owner scope to host); scopes absent here use `browserHost`. */
42
+ browserOwnerHosts: Record<string, "local" | "container">;
43
+ /** Container host settings (`browser.container`); defaults apply when unset. */
44
+ browserContainer: BrowserContainerConfig;
25
45
  /** Absolute path of config.yaml when loaded; undefined if absent. */
26
46
  configFilePath: string | undefined;
27
47
  warnings: string[];
@@ -45,6 +65,7 @@ export type HostConfigPublicEcho = {
45
65
  callers: Record<string, CallerQuotaConfig>;
46
66
  secrets: HostConfigSecretsEcho;
47
67
  };
68
+ export declare function browserHostForOwner(config: Pick<HostConfig, "browserHost" | "browserOwnerHosts">, scope: string): "local" | "container";
48
69
  /**
49
70
  * Assemble HostConfig once at boot. Precedence: overrides (CLI flags) > env > file > default.
50
71
  */