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,32 +1,36 @@
1
1
  import type { ValidationFindingCode } from "./validateCatalog.js";
2
2
  export type TaskLoadCode = "task.invalid_shape" | "task.load_error" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid";
3
3
  export type TriggerLoadCode = "trigger.invalid_shape" | "trigger.load_error" | "trigger.unknown_pipeline" | "trigger.unknown_task";
4
- export type LoadIssue = {
4
+ type LoadIssueLocation = {
5
+ line?: number;
6
+ column?: number;
7
+ };
8
+ export type LoadIssue = ({
5
9
  code: ValidationFindingCode;
6
10
  message: string;
7
11
  category: "pipeline";
8
12
  pipelineId?: string;
9
13
  stageId?: string;
10
- } | {
14
+ } & LoadIssueLocation) | ({
11
15
  code: ValidationFindingCode;
12
16
  message: string;
13
17
  category: "stage";
14
18
  stageId?: string;
15
- } | {
19
+ } & LoadIssueLocation) | ({
16
20
  code: TaskLoadCode;
17
21
  message: string;
18
22
  category: "task";
19
23
  taskId?: string;
20
- } | {
24
+ } & LoadIssueLocation) | ({
21
25
  code: TriggerLoadCode;
22
26
  message: string;
23
27
  category: "trigger";
24
28
  triggerId?: string;
25
- } | {
29
+ } & LoadIssueLocation) | ({
26
30
  code: ValidationFindingCode | string;
27
31
  message: string;
28
32
  category: "catalog";
29
- };
33
+ } & LoadIssueLocation);
30
34
  export type LoadOutcome<T> = {
31
35
  ok: true;
32
36
  value: T;
@@ -37,3 +41,4 @@ export type LoadOutcome<T> = {
37
41
  };
38
42
  export declare function loadFailure<T>(issues: LoadIssue[]): LoadOutcome<T>;
39
43
  export declare function loadSuccess<T>(value: T, issues?: LoadIssue[]): LoadOutcome<T>;
44
+ export {};
@@ -1,3 +1,4 @@
1
+ import { MAX_STAGE_CHANNELS, channelLimitMessage, mergeChannelDefaults, stageChannelLimit } from "../channels/stageChannels.js";
1
2
  import { access } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import { compilePayloadSchema, expandPayloadSchemaRefs, isPayloadSchemaSubset, UnresolvedSchemaRefError, } from "../envelope/payloadSchema.js";
@@ -128,9 +129,25 @@ export async function loadPipelineFromObject(raw, options = {}) {
128
129
  }
129
130
  return outcome.value;
130
131
  }
132
+ function applyPipelineChannels(stage, defaults, pipelineId) {
133
+ const channels = mergeChannelDefaults(defaults, stage.channels);
134
+ if (channels === undefined)
135
+ return loadSuccess(stage);
136
+ if (channels.length > Math.min(MAX_STAGE_CHANNELS, stageChannelLimit())) {
137
+ return loadFailure([
138
+ {
139
+ code: "stage.invalid_channels",
140
+ message: `Pipeline ${pipelineId}: stage "${stage.id}" ends up with ${channels.length} channels after merging pipeline defaults, but ${channelLimitMessage()}. Use \`channels: []\` on the stage to drop the pipeline default.`,
141
+ category: "stage",
142
+ stageId: stage.id,
143
+ },
144
+ ]);
145
+ }
146
+ return loadSuccess({ ...stage, channels });
147
+ }
131
148
  async function buildLoadedPipelineFromMerge(merge, options) {
132
149
  const { projectRoot, requireIo, pipelinePath } = options;
133
- const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, requires: pipelineRequires, warnings: mergeWarnings, } = merge;
150
+ const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, requires: pipelineRequires, channels: pipelineChannels, warnings: mergeWarnings, } = merge;
134
151
  const ctx = { pipelineId, path: pipelinePath };
135
152
  const warnings = [...mergeWarnings];
136
153
  const normalizeOutcome = normalizePipelineStageEntries(rawEntries, ctx);
@@ -199,7 +216,10 @@ async function buildLoadedPipelineFromMerge(merge, options) {
199
216
  if (inlineRequires.value !== undefined) {
200
217
  stage = { ...stage, requires: inlineRequires.value };
201
218
  }
202
- stages.push(stage);
219
+ const inlineChannels = applyPipelineChannels(stage, pipelineChannels, pipelineId);
220
+ if (!inlineChannels.ok)
221
+ return loadFailure(inlineChannels.issues);
222
+ stages.push(inlineChannels.value);
203
223
  stageSources[stageId] = { kind: "inline" };
204
224
  continue;
205
225
  }
@@ -259,10 +279,12 @@ async function buildLoadedPipelineFromMerge(merge, options) {
259
279
  if (!fileRequires.ok)
260
280
  return loadFailure(fileRequires.issues);
261
281
  stageRequires = fileRequires.value;
282
+ const withChannels = applyPipelineChannels(stageOutcome.value, pipelineChannels, pipelineId);
283
+ if (!withChannels.ok)
284
+ return loadFailure(withChannels.issues);
262
285
  const stage = {
263
- ...stageOutcome.value,
286
+ ...withChannels.value,
264
287
  ...(browser !== undefined ? { browser } : {}),
265
- ...(entry.skill !== undefined ? { skill: entry.skill } : {}),
266
288
  ...(entry.mcp !== undefined ? { mcp: entry.mcp } : {}),
267
289
  ...(entry.secrets !== undefined ? { secrets: entry.secrets } : {}),
268
290
  ...(stageRequires !== undefined ? { requires: stageRequires } : {}),
@@ -316,6 +338,7 @@ async function buildLoadedPipelineFromMerge(merge, options) {
316
338
  ...(pipelineModel !== undefined ? { model: pipelineModel } : {}),
317
339
  ...(pipelineSchemas !== undefined ? { schemas: pipelineSchemas } : {}),
318
340
  ...(pipelineRequires !== undefined ? { requires: pipelineRequires } : {}),
341
+ ...(pipelineChannels !== undefined ? { channels: pipelineChannels } : {}),
319
342
  };
320
343
  const effectiveRequires = mergeToolRequires([pipelineRequires, ...loadedStages.map((s) => s.requires)], { pipelineId });
321
344
  if (!effectiveRequires.ok)
@@ -1,3 +1,4 @@
1
+ import { parseChannels } from "../channels/stageChannels.js";
1
2
  import { parseAgentField } from "../agent/agentBackend.js";
2
3
  import { STAGEFLOW_MCP_SERVER_NAME } from "../agent/claudeTools.js";
3
4
  import { STAGE_GATE_KINDS, } from "../types/stage.js";
@@ -7,6 +8,7 @@ import { parseModelField } from "./modelField.js";
7
8
  import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
8
9
  import { parsePreEmitChecks } from "./parsePreEmitChecks.js";
9
10
  import { readYamlObject } from "./readYamlObject.js";
11
+ import { yamlParsePosition } from "./yamlParsePosition.js";
10
12
  import { z } from "zod";
11
13
  import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
12
14
  import { parseToolRequires } from "./toolRequires.js";
@@ -361,6 +363,20 @@ function parseStageFields(raw, label, entryId, deferSchemaRefs, requireIo, compi
361
363
  if (mcpOutcome.value !== undefined) {
362
364
  stage.mcp = mcpOutcome.value;
363
365
  }
366
+ if (raw.channels !== undefined) {
367
+ const channels = parseChannels(raw.channels);
368
+ if (!channels.ok) {
369
+ return loadFailure([
370
+ {
371
+ code: "stage.invalid_channels",
372
+ message: `Invalid stage ${label}: ${channels.message}`,
373
+ category: "stage",
374
+ stageId: entryId,
375
+ },
376
+ ]);
377
+ }
378
+ stage.channels = channels.value;
379
+ }
364
380
  const secretsOutcome = parseStageSecrets(raw.secrets, label, entryId);
365
381
  if (!secretsOutcome.ok)
366
382
  return secretsOutcome;
@@ -436,6 +452,7 @@ export async function loadStageOutcome(filePath, options = {}) {
436
452
  code: "stage.load_error",
437
453
  message,
438
454
  category: "stage",
455
+ ...yamlParsePosition(err),
439
456
  },
440
457
  ]);
441
458
  }
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { parse as parseYaml } from "yaml";
4
4
  import { parseAgentField } from "../agent/agentBackend.js";
5
5
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
6
+ import { yamlParsePosition } from "./yamlParsePosition.js";
6
7
  import { parseModelField } from "./modelField.js";
7
8
  const DEFAULT_PIPELINE_PATTERN = "*.pipeline.yaml";
8
9
  const DEFAULT_TASK_PATTERN = "*.task.yaml";
@@ -87,7 +88,9 @@ export function parseStageflowManifestOutcome(yamlText, manifestPath, projectRoo
87
88
  }
88
89
  catch (err) {
89
90
  const message = err instanceof Error ? err.message : String(err);
90
- return loadFailure([catalogIssue("catalog.manifest_load_error", message)]);
91
+ return loadFailure([
92
+ { ...catalogIssue("catalog.manifest_load_error", message), ...yamlParsePosition(err) },
93
+ ]);
91
94
  }
92
95
  const issues = [];
93
96
  const record = raw;
@@ -2,6 +2,7 @@ import { readFile } from "node:fs/promises";
2
2
  import { parse as parseYaml } from "yaml";
3
3
  import { resolveWorkspaceBinding } from "../runtime/workspaceBinding.js";
4
4
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
5
+ import { yamlParsePosition } from "./yamlParsePosition.js";
5
6
  function isPlainObject(value) {
6
7
  return typeof value === "object" && value !== null && !Array.isArray(value);
7
8
  }
@@ -86,6 +87,7 @@ export function loadTaskFromYamlOutcome(yamlText, source = "task yaml") {
86
87
  code: "task.load_error",
87
88
  message,
88
89
  category: "task",
90
+ ...yamlParsePosition(err),
89
91
  },
90
92
  ]);
91
93
  }
@@ -1,6 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { parse as parseYaml } from "yaml";
3
3
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
4
+ import { yamlParsePosition } from "./yamlParsePosition.js";
4
5
  function isPlainObject(value) {
5
6
  return typeof value === "object" && value !== null && !Array.isArray(value);
6
7
  }
@@ -84,6 +85,7 @@ export function loadTriggerFromYamlOutcome(yamlText, source = "trigger yaml") {
84
85
  code: "trigger.load_error",
85
86
  message,
86
87
  category: "trigger",
88
+ ...yamlParsePosition(err),
87
89
  },
88
90
  ]);
89
91
  }
@@ -2,6 +2,7 @@ import type { PayloadSchemaMap } from "../envelope/payloadSchema.js";
2
2
  import type { InlinePipelineDefinition } from "../types/pipeline.js";
3
3
  import { type LoadIssue, type LoadOutcome } from "./loadOutcome.js";
4
4
  import { type ToolRequirement } from "./toolRequires.js";
5
+ import type { StageChannel } from "../types/stage.js";
5
6
  export type RawMergedEntry = {
6
7
  raw: unknown;
7
8
  declaringPath: string;
@@ -13,6 +14,7 @@ export declare function mergePipelineStages(rootPath: string): Promise<LoadOutco
13
14
  model?: string;
14
15
  schemas?: PayloadSchemaMap;
15
16
  requires?: ToolRequirement[];
17
+ channels?: StageChannel[];
16
18
  warnings: LoadIssue[];
17
19
  }>>;
18
20
  /** Synthetic `declaringPath` for stage entries with no backing file. */
@@ -24,5 +26,6 @@ export declare function mergeInlinePipelineStages(raw: InlinePipelineDefinition)
24
26
  model?: string;
25
27
  schemas?: PayloadSchemaMap;
26
28
  requires?: ToolRequirement[];
29
+ channels?: StageChannel[];
27
30
  warnings: LoadIssue[];
28
31
  }>>;
@@ -4,7 +4,9 @@ import { loadFailure, loadSuccess } from "./loadOutcome.js";
4
4
  import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
5
5
  import { parseModelField } from "./modelField.js";
6
6
  import { readYamlObject } from "./readYamlObject.js";
7
+ import { yamlParsePosition } from "./yamlParsePosition.js";
7
8
  import { parseToolRequires } from "./toolRequires.js";
9
+ import { parseChannels } from "../channels/stageChannels.js";
8
10
  import { classifyYamlDocument, collectDocumentKeys, mixedDialectIssue, } from "./yamlDialect.js";
9
11
  function isPlainObject(value) {
10
12
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -39,6 +41,7 @@ async function visitPipelineFile(filePath, stack, idLocations, entries, warnings
39
41
  code: "pipeline.load_error",
40
42
  message,
41
43
  category: "pipeline",
44
+ ...yamlParsePosition(err),
42
45
  },
43
46
  ]);
44
47
  }
@@ -128,6 +131,7 @@ export async function mergePipelineStages(rootPath) {
128
131
  code: "pipeline.load_error",
129
132
  message,
130
133
  category: "pipeline",
134
+ ...yamlParsePosition(err),
131
135
  },
132
136
  ]);
133
137
  }
@@ -186,6 +190,10 @@ export async function mergePipelineStages(rootPath) {
186
190
  if (!requiresOutcome.ok)
187
191
  return requiresOutcome;
188
192
  const requires = requiresOutcome.value;
193
+ const channelsOutcome = parsePipelineChannels(raw.channels, `pipeline ${absRoot}`, pipelineId);
194
+ if (!channelsOutcome.ok)
195
+ return channelsOutcome;
196
+ const channels = channelsOutcome.value;
189
197
  const idLocations = new Map();
190
198
  const entries = [];
191
199
  const warnings = [];
@@ -208,6 +216,7 @@ export async function mergePipelineStages(rootPath) {
208
216
  ...(model !== undefined ? { model } : {}),
209
217
  ...(schemas !== undefined ? { schemas } : {}),
210
218
  ...(requires !== undefined ? { requires } : {}),
219
+ ...(channels !== undefined ? { channels } : {}),
211
220
  warnings,
212
221
  });
213
222
  }
@@ -270,6 +279,10 @@ export async function mergeInlinePipelineStages(raw) {
270
279
  if (!requiresOutcome.ok)
271
280
  return requiresOutcome;
272
281
  const requires = requiresOutcome.value;
282
+ const channelsOutcome = parsePipelineChannels(raw.channels, `inline pipeline ${pipelineId}`, pipelineId);
283
+ if (!channelsOutcome.ok)
284
+ return channelsOutcome;
285
+ const channels = channelsOutcome.value;
273
286
  const entries = [];
274
287
  for (let index = 0; index < raw.stages.length; index++) {
275
288
  const entry = raw.stages[index];
@@ -292,9 +305,26 @@ export async function mergeInlinePipelineStages(raw) {
292
305
  ...(model !== undefined ? { model } : {}),
293
306
  ...(schemas !== undefined ? { schemas } : {}),
294
307
  ...(requires !== undefined ? { requires } : {}),
308
+ ...(channels !== undefined ? { channels } : {}),
295
309
  warnings: [],
296
310
  });
297
311
  }
312
+ function parsePipelineChannels(raw, label, pipelineId) {
313
+ if (raw === undefined)
314
+ return loadSuccess(undefined);
315
+ const parsed = parseChannels(raw);
316
+ if (!parsed.ok) {
317
+ return loadFailure([
318
+ {
319
+ code: "pipeline.invalid_channels",
320
+ message: `Invalid ${label}: ${parsed.message}`,
321
+ category: "pipeline",
322
+ pipelineId,
323
+ },
324
+ ]);
325
+ }
326
+ return loadSuccess(parsed.value);
327
+ }
298
328
  function parsePipelineSchemas(raw, absPath, pipelineId) {
299
329
  if (raw === undefined)
300
330
  return loadSuccess(undefined);
@@ -43,7 +43,6 @@ function extractBodyRaw(raw) {
43
43
  }
44
44
  function hasBodyKey(raw) {
45
45
  return Object.keys(raw).some((key) => BODY_KEYS.has(key) &&
46
- key !== "skill" &&
47
46
  key !== "mcp" &&
48
47
  key !== "secrets" &&
49
48
  key !== "requires" &&
@@ -116,6 +115,16 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
116
115
  return skillOutcome;
117
116
  }
118
117
  const skill = skillOutcome?.ok ? skillOutcome.value : undefined;
118
+ if (uses && skill !== undefined) {
119
+ return loadFailure([
120
+ {
121
+ code: "pipeline.stage_wrapper_skill_rejected",
122
+ message: `Pipeline ${ctx.pipelineId} (${ctx.path}): stage entry at index ${index} sets skill: on a uses: wrapper; put skill: on the stage file (${uses}) instead`,
123
+ category: "pipeline",
124
+ pipelineId: ctx.pipelineId,
125
+ },
126
+ ]);
127
+ }
119
128
  const mcpOutcome = parseStageMcp(raw.mcp, `entry at index ${index} in ${declaringPath}`);
120
129
  if (!mcpOutcome.ok)
121
130
  return mcpOutcome;
@@ -29,6 +29,7 @@ export const WIRING_KEYS = new Set([
29
29
  /** Stage body keys. Target: `io` / `verify`. IR/legacy: `payload_schema`, `pre_emit_checks`, `clone_input_schema`. */
30
30
  export const BODY_KEYS = new Set([
31
31
  "email",
32
+ "channels",
32
33
  "system_prompt",
33
34
  "model",
34
35
  "payload_schema",
@@ -163,7 +163,6 @@ const STAGE_BODY_ORDER = [
163
163
  const PIPELINE_WIRING_ORDER = [
164
164
  "id",
165
165
  "uses",
166
- "skill",
167
166
  "mcp",
168
167
  "needs",
169
168
  "fork",
@@ -1,7 +1,11 @@
1
1
  import { type CreateDraftPackageInput, type DraftPackageWriteResult } from "./draftPackage.js";
2
+ import type { CatalogRootKind } from "./resolveCatalogRoots.js";
2
3
  export type PublishDraftPackageMode = "create" | "overwrite" | "auto";
4
+ export type PublishDraftPackageOptions = {
5
+ catalogRootKind?: CatalogRootKind;
6
+ };
3
7
  export type PublishDraftPackageResult = {
4
8
  write: DraftPackageWriteResult;
5
9
  catalogChanged: boolean;
6
10
  };
7
- export declare function publishDraftPackage(projectRoot: string, input: CreateDraftPackageInput, mode: PublishDraftPackageMode): Promise<PublishDraftPackageResult>;
11
+ export declare function publishDraftPackage(projectRoot: string, input: CreateDraftPackageInput, mode: PublishDraftPackageMode, options?: PublishDraftPackageOptions): Promise<PublishDraftPackageResult>;
@@ -1,6 +1,6 @@
1
1
  import { createDraftPackage, overwriteDraftPackage, } from "./draftPackage.js";
2
2
  import { ensureCatalogScanRoot } from "./ensureCatalogScanRoot.js";
3
- export async function publishDraftPackage(projectRoot, input, mode) {
3
+ export async function publishDraftPackage(projectRoot, input, mode, options = {}) {
4
4
  let write;
5
5
  if (mode === "create") {
6
6
  write = await createDraftPackage(projectRoot, input);
@@ -20,6 +20,9 @@ export async function publishDraftPackage(projectRoot, input, mode) {
20
20
  if (!write.ok) {
21
21
  return { write, catalogChanged: false };
22
22
  }
23
+ if (options.catalogRootKind === "workspace") {
24
+ return { write, catalogChanged: false };
25
+ }
23
26
  const catalogChanged = await ensureCatalogScanRoot(projectRoot, input.directory);
24
27
  return { write, catalogChanged };
25
28
  }
@@ -1,5 +1,5 @@
1
1
  import type { RunStore } from "../runstore/port.js";
2
- export type CatalogRootKind = "registered" | "seeded";
2
+ export type CatalogRootKind = "registered" | "seeded" | "workspace";
3
3
  export type CatalogRoot = {
4
4
  /** Wire id: absolute path for registered; symbolic id for seeded (e.g. "examples"). */
5
5
  project_root: string;
@@ -7,6 +7,9 @@ export type CatalogRoot = {
7
7
  path: string;
8
8
  kind: CatalogRootKind;
9
9
  read_only: boolean;
10
+ /** False when workspace provisioning failed at boot. */
11
+ available?: boolean;
12
+ unavailable_reason?: string;
10
13
  };
11
14
  export type ResolveCatalogRootsOptions = {
12
15
  store: RunStore;
@@ -1,6 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { realpathSync, constants } from "node:fs";
3
3
  import { access } from "node:fs/promises";
4
+ import { WORKSPACE_CATALOG_ID, lastWorkspaceProvisionResult, workspaceCatalogPath, } from "../project/workspaceCatalog.js";
4
5
  function realOrResolve(p) {
5
6
  const resolved = path.resolve(p);
6
7
  try {
@@ -19,6 +20,7 @@ export async function resolveCatalogRoots(options) {
19
20
  const seenPaths = new Set();
20
21
  const seededRoots = options.seededRoots ??
21
22
  (await import("./seededCatalog.js")).defaultSeededRoots();
23
+ const workspaceAbs = realOrResolve(workspaceCatalogPath());
22
24
  let registered = [];
23
25
  try {
24
26
  registered = await options.store.listRegisteredProjects();
@@ -28,7 +30,7 @@ export async function resolveCatalogRoots(options) {
28
30
  }
29
31
  for (const root of registered) {
30
32
  const abs = realOrResolve(root);
31
- if (seenPaths.has(abs))
33
+ if (seenPaths.has(abs) || abs === workspaceAbs)
32
34
  continue;
33
35
  seenPaths.add(abs);
34
36
  roots.push({
@@ -38,6 +40,21 @@ export async function resolveCatalogRoots(options) {
38
40
  read_only: false,
39
41
  });
40
42
  }
43
+ if (!seenPaths.has(workspaceAbs)) {
44
+ seenPaths.add(workspaceAbs);
45
+ const provision = lastWorkspaceProvisionResult();
46
+ const available = provision === undefined || provision.ok;
47
+ roots.push({
48
+ project_root: WORKSPACE_CATALOG_ID,
49
+ path: workspaceCatalogPath(),
50
+ kind: "workspace",
51
+ read_only: false,
52
+ available,
53
+ ...(provision !== undefined && !provision.ok && provision.reason
54
+ ? { unavailable_reason: provision.reason }
55
+ : {}),
56
+ });
57
+ }
41
58
  for (const seeded of seededRoots) {
42
59
  const abs = realOrResolve(seeded.path);
43
60
  if (seenPaths.has(abs))
@@ -0,0 +1,6 @@
1
+ export type SkillUsageEntry = {
2
+ stage_ids: string[];
3
+ pipeline_ids: string[];
4
+ };
5
+ export type SkillUsageIndex = Record<string, SkillUsageEntry>;
6
+ export declare function buildSkillUsageIndex(cwd: string): Promise<SkillUsageIndex | null>;
@@ -0,0 +1,39 @@
1
+ import { loadPipelineOutcome } from "./loadPipeline.js";
2
+ import { getCatalogScanPaths } from "./browseCatalog.js";
3
+ import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
4
+ import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
5
+ function addUsage(index, skillName, pipelineId, stageId) {
6
+ const entry = index[skillName] ?? { stage_ids: [], pipeline_ids: [] };
7
+ if (!entry.pipeline_ids.includes(pipelineId)) {
8
+ entry.pipeline_ids.push(pipelineId);
9
+ entry.pipeline_ids.sort((a, b) => a.localeCompare(b));
10
+ }
11
+ if (!entry.stage_ids.includes(stageId)) {
12
+ entry.stage_ids.push(stageId);
13
+ entry.stage_ids.sort((a, b) => a.localeCompare(b));
14
+ }
15
+ index[skillName] = entry;
16
+ }
17
+ export async function buildSkillUsageIndex(cwd) {
18
+ const ctx = catalogContextFromStageflow(await resolveStageflowContext(cwd));
19
+ const scanPaths = await getCatalogScanPaths(ctx);
20
+ if (!scanPaths) {
21
+ return null;
22
+ }
23
+ const index = {};
24
+ const loadCwd = ctx.projectRoot ?? cwd;
25
+ for (const pipelinePath of scanPaths.pipelinePaths) {
26
+ const outcome = await loadPipelineOutcome(pipelinePath, { cwd: loadCwd });
27
+ if (!outcome.ok) {
28
+ continue;
29
+ }
30
+ const pipelineId = outcome.value.pipeline.id;
31
+ for (const stage of outcome.value.stages) {
32
+ if (stage.skill === undefined) {
33
+ continue;
34
+ }
35
+ addUsage(index, stage.skill, pipelineId, stage.id);
36
+ }
37
+ }
38
+ return index;
39
+ }
@@ -4,6 +4,16 @@ export const BROWSER_TOOL_NAME = "agent-browser";
4
4
  const ALLOWED_KEYS = new Set(["profile", "headed", "allow_domains", "login_url", "check"]);
5
5
  const CHECK_KEYS = new Set(["url", "logged_in_url", "logged_out_url"]);
6
6
  const REJECTED_KEYS = new Set(["path", "scope", "secret"]);
7
+ const HOST_ONLY_KEYS = new Set([
8
+ "launch_args",
9
+ "args",
10
+ "executable_path",
11
+ "executable",
12
+ "display",
13
+ "headless",
14
+ "xvfb",
15
+ "env",
16
+ ]);
7
17
  const PROFILE_NAME = /^[A-Za-z0-9_-]{1,64}$/;
8
18
  const DOMAIN = /^(\*\.)?[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
9
19
  function isPlainObject(value) {
@@ -67,6 +77,9 @@ export function parseStageBrowser(raw, label, stageId) {
67
77
  if (REJECTED_KEYS.has(key)) {
68
78
  return fail(label, stageId, `"${key}" is not allowed (the Host chooses profile location and scope)`);
69
79
  }
80
+ if (HOST_ONLY_KEYS.has(key)) {
81
+ return fail(label, stageId, `"${key}" is not allowed (browser launch options are Host config: browser.launch_args and browser.executable_path in $STAGEFLOW_HOME/config.yaml)`);
82
+ }
70
83
  if (!ALLOWED_KEYS.has(key)) {
71
84
  return fail(label, stageId, `unknown key "${key}" (allowed: profile, headed, allow_domains, login_url, check)`);
72
85
  }
@@ -0,0 +1,11 @@
1
+ import type { TriggerFile } from "../types/trigger.js";
2
+ import type { RunStore } from "../runstore/port.js";
3
+ export type TriggerAdapterStatus = {
4
+ adapter: string;
5
+ state: string;
6
+ detail?: string;
7
+ last_poll_at?: string;
8
+ last_seen_at?: string;
9
+ last_error?: string;
10
+ };
11
+ export declare function readTriggerAdapterStatus(trigger: TriggerFile, store: RunStore): Promise<TriggerAdapterStatus>;
@@ -0,0 +1,90 @@
1
+ function parseGithubCursor(raw) {
2
+ if (raw === null) {
3
+ return null;
4
+ }
5
+ try {
6
+ const parsed = JSON.parse(raw);
7
+ if (typeof parsed.updatedAt === "string") {
8
+ return { updatedAt: parsed.updatedAt };
9
+ }
10
+ return {};
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ function mailboxKeyForTrigger(trigger) {
17
+ const config = trigger.event?.config;
18
+ const host = config?.host;
19
+ const port = config?.port;
20
+ const user = config?.user;
21
+ if (typeof host !== "string" ||
22
+ host.length === 0 ||
23
+ typeof port !== "number" ||
24
+ !Number.isFinite(port) ||
25
+ typeof user !== "string" ||
26
+ user.length === 0) {
27
+ return undefined;
28
+ }
29
+ return `email:${host}:${port}:${user}`;
30
+ }
31
+ async function adapterStateUpdatedAt(store, adapterId, key) {
32
+ const meta = await store.getTriggerAdapterStateMeta(adapterId, key);
33
+ return meta?.updated_at;
34
+ }
35
+ export async function readTriggerAdapterStatus(trigger, store) {
36
+ if (!trigger.enabled) {
37
+ return { adapter: trigger.kind, state: "disabled" };
38
+ }
39
+ if (trigger.kind === "manual") {
40
+ return { adapter: "manual", state: "idle" };
41
+ }
42
+ if (trigger.kind === "schedule") {
43
+ return { adapter: "schedule", state: "scheduled" };
44
+ }
45
+ const source = trigger.event?.source ?? "";
46
+ if (source === "webhook") {
47
+ return { adapter: "webhook", state: "ready", detail: "Endpoint ready when host is running" };
48
+ }
49
+ if (source.startsWith("github.")) {
50
+ const repo = trigger.event?.config?.repo;
51
+ if (typeof repo !== "string" || repo.length === 0) {
52
+ return {
53
+ adapter: "github",
54
+ state: "error",
55
+ detail: "event.config.repo is required",
56
+ };
57
+ }
58
+ const adapterId = `github:${repo}`;
59
+ const cursor = parseGithubCursor(await store.getTriggerAdapterState(adapterId, "cursor"));
60
+ const lastPoll = await adapterStateUpdatedAt(store, adapterId, "etag");
61
+ const lastSeen = cursor?.updatedAt ?? lastPoll;
62
+ return {
63
+ adapter: "github",
64
+ state: cursor !== null || lastPoll !== undefined ? "polling" : "idle",
65
+ ...(lastPoll !== undefined ? { last_poll_at: lastPoll } : {}),
66
+ ...(lastSeen !== undefined ? { last_seen_at: lastSeen } : {}),
67
+ };
68
+ }
69
+ if (source === "email.message") {
70
+ const mailboxKey = mailboxKeyForTrigger(trigger);
71
+ if (mailboxKey === undefined) {
72
+ return {
73
+ adapter: "email",
74
+ state: "error",
75
+ detail: "Incomplete email event.config",
76
+ };
77
+ }
78
+ const uid = await store.getTriggerAdapterState(mailboxKey, "uid");
79
+ const lastSeen = await adapterStateUpdatedAt(store, mailboxKey, "uid");
80
+ return {
81
+ adapter: "email",
82
+ state: uid !== null ? "connected" : "watching",
83
+ ...(lastSeen !== undefined ? { last_seen_at: lastSeen } : {}),
84
+ };
85
+ }
86
+ return {
87
+ adapter: source.length > 0 ? source : "event",
88
+ state: "idle",
89
+ };
90
+ }