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,8 +1,8 @@
1
- import path from "node:path";
2
1
  import { catalogContextFromStageflow } from "../config/resolveCatalogContext.js";
3
2
  import { getCatalogScanPaths } from "../config/browseCatalog.js";
4
3
  import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
5
- import { findCatalogPathById, findTriggerDefinition } from "./triggerCatalog.js";
4
+ import { findCatalogPathById } from "./triggerCatalog.js";
5
+ import { findCatalogTrigger, triggerStoreId, } from "../config/triggerCatalog.js";
6
6
  /**
7
7
  * Resolves a trigger id to its `*.trigger.yaml` catalog definition, resolves its
8
8
  * `pipeline`/`task` refs to catalog files, and starts a real run through
@@ -14,17 +14,22 @@ import { findCatalogPathById, findTriggerDefinition } from "./triggerCatalog.js"
14
14
  * dynamic-mode trigger (`task` absent) requires one.
15
15
  */
16
16
  export async function fireTrigger(triggerId, store, runManager, options = {}) {
17
- const cwd = options.cwd ?? process.cwd();
18
- const ctx = catalogContextFromStageflow(await resolveStageflowContext(cwd));
19
- const scanPaths = await getCatalogScanPaths(ctx);
20
- if (!scanPaths) {
21
- return { ok: false, reason: "No Stageflow catalog found", status: 404 };
22
- }
23
- const found = await findTriggerDefinition(scanPaths.triggerPaths, triggerId);
24
- if (!found) {
25
- return { ok: false, reason: `Trigger not found: ${triggerId}`, status: 404 };
17
+ const bootCwd = options.cwd ?? process.cwd();
18
+ const located = await findCatalogTrigger({
19
+ store,
20
+ bootCwd,
21
+ triggerId,
22
+ projectRootFilter: options.project_root,
23
+ });
24
+ if (!located.ok) {
25
+ return {
26
+ ok: false,
27
+ reason: located.reason,
28
+ status: located.status,
29
+ };
26
30
  }
27
- const { path: triggerPath, definition: trigger } = found;
31
+ const { match } = located;
32
+ const trigger = match.definition;
28
33
  if (!trigger.enabled) {
29
34
  return { ok: false, reason: `Trigger is disabled: ${triggerId}`, status: 409 };
30
35
  }
@@ -45,6 +50,11 @@ export async function fireTrigger(triggerId, store, runManager, options = {}) {
45
50
  code: "trigger.task_required",
46
51
  };
47
52
  }
53
+ const ctx = catalogContextFromStageflow(await resolveStageflowContext(match.rootPath));
54
+ const scanPaths = await getCatalogScanPaths(ctx);
55
+ if (!scanPaths) {
56
+ return { ok: false, reason: "No Stageflow catalog found", status: 404 };
57
+ }
48
58
  const pipelinePath = await findCatalogPathById(scanPaths.pipelinePaths, trigger.pipeline);
49
59
  if (!pipelinePath) {
50
60
  return {
@@ -68,22 +78,19 @@ export async function fireTrigger(triggerId, store, runManager, options = {}) {
68
78
  else {
69
79
  taskInput = suppliedTask;
70
80
  }
71
- const projectRoot = ctx.projectRoot ?? undefined;
72
- const definitionRef = projectRoot !== undefined
73
- ? path.relative(projectRoot, triggerPath).replace(/\\/g, "/")
74
- : triggerPath;
81
+ const storeId = triggerStoreId(match.project_root, trigger.id);
75
82
  await store.upsertTrigger({
76
- id: triggerId,
77
- definitionRef,
83
+ id: storeId,
84
+ definitionRef: match.definition_ref,
78
85
  enabled: trigger.enabled,
79
86
  });
80
87
  const started = await runManager.startRun({
81
88
  pipeline: pipelinePath,
82
89
  task: taskInput,
83
- ...(projectRoot !== undefined ? { projectRoot } : {}),
90
+ projectRoot: match.rootPath,
84
91
  });
85
92
  if (started.ok) {
86
- await store.recordTriggerFired(triggerId, started.runId);
93
+ await store.recordTriggerFired(storeId, started.runId);
87
94
  }
88
95
  return started;
89
96
  }
@@ -0,0 +1,25 @@
1
+ import type { TaskFile } from "../types/task.js";
2
+ import type { TriggerFile } from "../types/trigger.js";
3
+ export type WebhookHeaderMap = {
4
+ readonly [name: string]: string | string[] | undefined;
5
+ };
6
+ export type WebhookAcceptResult = {
7
+ kind: "not_configured";
8
+ } | {
9
+ kind: "bad_signature";
10
+ } | {
11
+ kind: "bad_json";
12
+ error: "Invalid JSON body" | "Invalid JSON body: expected an object";
13
+ } | {
14
+ kind: "no_match";
15
+ } | {
16
+ kind: "fire";
17
+ task?: TaskFile;
18
+ };
19
+ export declare function acceptWebhook(input: {
20
+ trigger: TriggerFile;
21
+ rawBody: Buffer;
22
+ headers: WebhookHeaderMap;
23
+ env: NodeJS.ProcessEnv;
24
+ now?: () => number;
25
+ }): WebhookAcceptResult;
@@ -0,0 +1,56 @@
1
+ import { readSecretFromEnvOrFile } from "../config/secretFromEnvOrFile.js";
2
+ import { matchesEventFilter } from "./triggerEventMatch.js";
3
+ import { verifyHmacSignature } from "./webhookSignature.js";
4
+ export function acceptWebhook(input) {
5
+ const { trigger, rawBody, headers, env } = input;
6
+ const now = input.now ?? Date.now;
7
+ const config = trigger.event?.config;
8
+ const secretRef = typeof config?.secretRef === "string" ? config.secretRef : undefined;
9
+ const header = typeof config?.header === "string" ? config.header : undefined;
10
+ if (secretRef === undefined || header === undefined) {
11
+ return { kind: "not_configured" };
12
+ }
13
+ const scheme = config?.scheme === "base64" ? "base64" : "hex";
14
+ let secret;
15
+ try {
16
+ secret = readSecretFromEnvOrFile(env, secretRef);
17
+ }
18
+ catch {
19
+ secret = undefined;
20
+ }
21
+ if (secret === undefined) {
22
+ return { kind: "not_configured" };
23
+ }
24
+ const headerValue = headers[header.toLowerCase()];
25
+ const signature = Array.isArray(headerValue) ? headerValue[0] : headerValue;
26
+ if (typeof signature !== "string" ||
27
+ signature.length === 0 ||
28
+ !verifyHmacSignature(rawBody, signature, secret, scheme)) {
29
+ return { kind: "bad_signature" };
30
+ }
31
+ let payload;
32
+ try {
33
+ payload = rawBody.length === 0 ? {} : JSON.parse(rawBody.toString("utf8"));
34
+ }
35
+ catch {
36
+ return { kind: "bad_json", error: "Invalid JSON body" };
37
+ }
38
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
39
+ return { kind: "bad_json", error: "Invalid JSON body: expected an object" };
40
+ }
41
+ const payloadRecord = payload;
42
+ if (!matchesEventFilter(trigger.event?.match, payloadRecord)) {
43
+ return { kind: "no_match" };
44
+ }
45
+ if (trigger.task !== undefined) {
46
+ return { kind: "fire" };
47
+ }
48
+ return {
49
+ kind: "fire",
50
+ task: {
51
+ id: `${trigger.id}-webhook-${now()}`,
52
+ goal: `Handle webhook event for trigger "${trigger.id}"`,
53
+ input: payloadRecord,
54
+ },
55
+ };
56
+ }
@@ -1,19 +1,22 @@
1
1
  import { type A2aHost } from "../a2a/server.js";
2
- import type { AgentPort } from "../agent/port.js";
2
+ import type { StagePort } from "../agent/port.js";
3
3
  import type { ProviderAuthContext } from "../agent/providerAuth.js";
4
4
  import { type RunStoreKind } from "../runstore/createStore.js";
5
+ import { type WorkspaceProvisionResult } from "../project/workspaceCatalog.js";
5
6
  import type { RunStore } from "../runstore/port.js";
6
7
  import type { StoreFilesystemClassification } from "../runstore/storeFilesystem.js";
8
+ import type { StageBrowserSupport } from "../browser/browserHost.js";
7
9
  import { RunManager } from "../runtime/runManager.js";
8
10
  import { emailHostFor } from "../email/host.js";
9
11
  import { EmailTriggers } from "../email/triggers.js";
12
+ import { type ChannelService } from "../channels/service.js";
10
13
  import { type RunChangeBus } from "../runtime/runChangeBus.js";
11
14
  import { type McpHttpHandler } from "../mcp/server.js";
12
15
  import { type HostConfig } from "../config/hostConfig.js";
13
16
  import { bootProviderConfig } from "../agent/bootProviderConfig.js";
14
17
  export declare const DEFAULT_GC_INTERVAL_MS: number;
15
18
  export type StageflowHostOptions = {
16
- agent: AgentPort;
19
+ agent: StagePort;
17
20
  cwd?: string;
18
21
  agentDir?: string;
19
22
  rootDir?: string;
@@ -27,6 +30,8 @@ export type StageflowHostOptions = {
27
30
  hostConfig?: HostConfig;
28
31
  /** Skip HostConfig load (tests that inject store/manager pieces only). */
29
32
  skipHostConfig?: boolean;
33
+ /** Browser support for the runs this Host executes; defaults to the local host with the live view relay. */
34
+ browser?: StageBrowserSupport;
30
35
  emailTriggerQueue?: ConstructorParameters<typeof EmailTriggers>[0]["queue"];
31
36
  };
32
37
  export type StageflowHostBootstrap = {
@@ -48,12 +53,15 @@ export type StageflowHostBootstrap = {
48
53
  /** Periodic retention GC handle when enabled; already `.unref()`'d. */
49
54
  gcInterval?: NodeJS.Timeout;
50
55
  stopGcInterval: () => void;
56
+ workspaceCatalog?: WorkspaceProvisionResult;
51
57
  /** Stops the schedule-trigger tick loop started at boot. */
52
58
  stopScheduleSource: () => void;
53
59
  /** Stops the GitHub poll-trigger loop started at boot. */
54
60
  stopGithubPollSource: () => void;
55
61
  /** Stops the email-trigger IMAP/IDLE listeners started at boot. */
56
62
  stopEmailSource: () => void;
63
+ /** Connections page read model and background health checks. */
64
+ channels?: ChannelService;
57
65
  email?: ReturnType<typeof emailHostFor> & {
58
66
  triggers: EmailTriggers;
59
67
  stop: () => Promise<void>;
@@ -4,12 +4,15 @@ import { createA2aHost } from "../a2a/server.js";
4
4
  import { A2aStore } from "../a2a/store.js";
5
5
  import { createRunStoreWithConnection } from "../runstore/createStore.js";
6
6
  import { resolveA2aConfigPath } from "../a2a/configDiscovery.js";
7
- import { ensureGlobalHome } from "../project/globalHome.js";
7
+ import { ensureProjectRootsFromEnv } from "../project/ensureProjectRootsFromEnv.js";
8
+ import { ensureGlobalHome, globalStageflowHome } from "../project/globalHome.js";
9
+ import { ensureWorkspaceCatalog, } from "../project/workspaceCatalog.js";
8
10
  import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
9
11
  import { findProjectRoot } from "../project/findProjectRoot.js";
10
12
  import { warnDurableRootDiskIfNeeded } from "../runstore/diskUsage.js";
11
13
  import { assertStoreFilesystemSupported } from "../runstore/storeFilesystem.js";
12
14
  import { assertStoreQuickCheck, isSqliteCorruptError, maybeCheckpointResidualWal, rethrowAsStoreIntegrityFailed, } from "../runstore/sqlite/applyStorePragmas.js";
15
+ import { consoleStageBrowserSupport } from "../browser/stageBrowserEnv.js";
13
16
  import { RunManager } from "../runtime/runManager.js";
14
17
  import { PI_CODING_AGENT_DIR_ENV } from "../runtime/stageRoots.js";
15
18
  import { ScheduleSource, triggerTickIntervalMsFromEnv, } from "../runtime/scheduleSource.js";
@@ -17,6 +20,7 @@ import { GithubPollSource, githubPollIntervalMsFromEnv, } from "../runtime/githu
17
20
  import { EmailSource } from "../runtime/emailSource.js";
18
21
  import { emailHostFor, releaseEmailHost } from "../email/host.js";
19
22
  import { EmailTriggers } from "../email/triggers.js";
23
+ import { startChannelService } from "../channels/service.js";
20
24
  import { fireTrigger } from "../runtime/triggerRunner.js";
21
25
  import { createRunChangeBus, getRunChangeBusFromWrappedStore, isRunStoreWrapped, wrapRunStoreWithChangeBus, } from "../runtime/runChangeBus.js";
22
26
  import { createMcpHttpHandler, resolveMcpStateless, } from "../mcp/server.js";
@@ -82,6 +86,7 @@ export async function bootstrapStageflowHost(options) {
82
86
  const invocationCwd = options.cwd ?? process.cwd();
83
87
  const ctx = await resolveStageflowContext(invocationCwd);
84
88
  const cwd = ctx.invocationCwd;
89
+ void globalStageflowHome();
85
90
  ensureGlobalHome();
86
91
  const cursorKey = readCursorApiKey(env);
87
92
  if (cursorKey !== undefined &&
@@ -227,6 +232,11 @@ export async function bootstrapStageflowHost(options) {
227
232
  }
228
233
  const runChangeBus = options.runChangeBus ?? boundBus ?? createRunChangeBus();
229
234
  const store = wrapRunStoreWithChangeBus(rawStore, runChangeBus);
235
+ await ensureProjectRootsFromEnv(env, store);
236
+ const workspaceCatalog = ensureWorkspaceCatalog(ctx.globalHome);
237
+ if (!workspaceCatalog.ok) {
238
+ bootLog.warn("workspace.provision_failed", workspaceCatalog.reason ?? "unknown");
239
+ }
230
240
  const manager = new RunManager({
231
241
  agent: options.agent,
232
242
  cwd,
@@ -245,6 +255,7 @@ export async function bootstrapStageflowHost(options) {
245
255
  ])),
246
256
  operatorCatalog: { cwd, agentDir },
247
257
  a2aStore,
258
+ browser: options.browser ?? consoleStageBrowserSupport(),
248
259
  });
249
260
  await manager.attachWaitingStages();
250
261
  await manager.reconcileOrphanedStages();
@@ -269,6 +280,9 @@ export async function bootstrapStageflowHost(options) {
269
280
  const result = await fireTrigger(event.triggerId, store, manager, {
270
281
  cwd,
271
282
  task: event.task,
283
+ ...(event.project_root !== undefined
284
+ ? { project_root: event.project_root }
285
+ : {}),
272
286
  });
273
287
  if (!result.ok) {
274
288
  bootLog.error("trigger.fire_failed", `trigger "${event.triggerId}" fire failed: ${result.reason}`);
@@ -318,9 +332,11 @@ export async function bootstrapStageflowHost(options) {
318
332
  await Promise.all([stopAccountEmail(), emailSource.stop(), scheduleSource.stop(), githubPollSource.stop()]);
319
333
  throw error;
320
334
  }
335
+ const channels = startChannelService(cwd);
321
336
  const stopEmailSource = () => {
322
337
  void emailSource.stop();
323
338
  void stopAccountEmail();
339
+ void channels.stop();
324
340
  };
325
341
  const mcpStateless = resolveMcpStateless({
326
342
  mcpStateless: options.mcpStateless,
@@ -361,6 +377,8 @@ export async function bootstrapStageflowHost(options) {
361
377
  stopGithubPollSource,
362
378
  stopEmailSource,
363
379
  email: { ...emailHost, triggers: emailTriggers, stop: stopAccountEmail },
380
+ channels,
364
381
  storeFilesystem,
382
+ workspaceCatalog,
365
383
  };
366
384
  }
@@ -0,0 +1,9 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { ChannelService } from "../channels/service.js";
3
+ type Json = (res: ServerResponse, status: number, body: unknown) => void;
4
+ /**
5
+ * Listing, live checks and edits. Request bodies carry secret values on the way in only; nothing
6
+ * the API returns contains one, and failures answer with a code, never the request or its values.
7
+ */
8
+ export declare function handleChannelRoutes(req: IncomingMessage, method: string, pathname: string, service: ChannelService, res: ServerResponse, json: Json): Promise<boolean>;
9
+ export {};
@@ -0,0 +1,88 @@
1
+ import { ChannelError } from "../channels/errors.js";
2
+ import { channelErrorStatus } from "../channels/errorInfo.js";
3
+ const MAX_BODY_BYTES = 65536;
4
+ async function readBody(req) {
5
+ const chunks = [];
6
+ let size = 0;
7
+ for await (const chunk of req) {
8
+ const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
9
+ size += buffer.length;
10
+ if (size > MAX_BODY_BYTES)
11
+ throw new ChannelError("CHANNEL_RESOURCE_LIMIT");
12
+ chunks.push(buffer);
13
+ }
14
+ if (chunks.length === 0)
15
+ return {};
16
+ try {
17
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
18
+ }
19
+ catch {
20
+ throw new ChannelError("CHANNEL_INVALID_INPUT");
21
+ }
22
+ }
23
+ /**
24
+ * Listing, live checks and edits. Request bodies carry secret values on the way in only; nothing
25
+ * the API returns contains one, and failures answer with a code, never the request or its values.
26
+ */
27
+ export async function handleChannelRoutes(req, method, pathname, service, res, json) {
28
+ const idMatch = pathname.match(/^\/api\/connections\/([^/]+)(?:\/(check|validate-target))?$/);
29
+ const isCollection = pathname === "/api/connections";
30
+ const isTest = pathname === "/api/connections/test";
31
+ const isMeta = pathname === "/api/connections/meta";
32
+ if (!isCollection && !isTest && !isMeta && !idMatch)
33
+ return false;
34
+ try {
35
+ if (isMeta && method === "GET") {
36
+ json(res, 200, service.meta());
37
+ return true;
38
+ }
39
+ if (isCollection && method === "GET") {
40
+ json(res, 200, service.list());
41
+ return true;
42
+ }
43
+ if (isCollection && method === "POST") {
44
+ json(res, 201, await service.create(await readBody(req)));
45
+ return true;
46
+ }
47
+ if (isTest && method === "POST") {
48
+ json(res, 200, await service.test(await readBody(req)));
49
+ return true;
50
+ }
51
+ if (idMatch) {
52
+ let id;
53
+ try {
54
+ id = decodeURIComponent(idMatch[1]);
55
+ }
56
+ catch {
57
+ throw new ChannelError("CHANNEL_INVALID_INPUT");
58
+ }
59
+ if (idMatch[2] === "check" && method === "POST") {
60
+ const health = await service.checkNow(id);
61
+ if (health)
62
+ json(res, 200, health);
63
+ else
64
+ json(res, 404, { code: "CHANNEL_NOT_FOUND" });
65
+ return true;
66
+ }
67
+ if (idMatch[2] === "validate-target" && method === "POST") {
68
+ json(res, 200, service.validateTarget(id, await readBody(req)));
69
+ return true;
70
+ }
71
+ if (!idMatch[2] && method === "PATCH") {
72
+ json(res, 200, await service.update(id, await readBody(req)));
73
+ return true;
74
+ }
75
+ if (!idMatch[2] && method === "DELETE") {
76
+ await service.remove(id);
77
+ json(res, 200, { removed: true });
78
+ return true;
79
+ }
80
+ }
81
+ }
82
+ catch (error) {
83
+ const code = error instanceof ChannelError ? error.code : "CHANNEL_STORAGE_FAILED";
84
+ json(res, channelErrorStatus(code), { code });
85
+ return true;
86
+ }
87
+ return false;
88
+ }
@@ -27,7 +27,7 @@ export declare function hasDriveToken(tokens: ControlTokens): boolean;
27
27
  export declare function hasAnyToken(tokens: ControlTokens): boolean;
28
28
  export declare function isLoopbackBind(bind: string): boolean;
29
29
  export declare function refuseBindMessage(bind: string): string;
30
- export declare function assertBindAllowed(bind: string, tokens: ControlTokens): void;
30
+ export declare function assertBindAllowed(bind: string, tokens: ControlTokens, env?: NodeJS.ProcessEnv): void;
31
31
  export declare class BindRefusedError extends Error {
32
32
  readonly exitCode = 1;
33
33
  constructor(message: string);
@@ -1,6 +1,7 @@
1
1
  import { createHash, timingSafeEqual } from "node:crypto";
2
2
  import { readSecretFromEnvOrFile } from "../config/secretFromEnvOrFile.js";
3
3
  import { isLoopbackHostname } from "./allowedHosts.js";
4
+ import { matchLiveViewRoute } from "./liveViewPath.js";
4
5
  const CONTROL_TOKEN_PREFIX = "STAGEFLOW_CONTROL_TOKEN_";
5
6
  const DEFAULT_CALLER_ID = "default";
6
7
  function digest(value) {
@@ -144,9 +145,14 @@ Set one of:
144
145
  STAGEFLOW_CONTROL_TOKEN_<NAME>=<at least 32 characters>
145
146
 
146
147
  Or bind to loopback instead:
147
- --host 127.0.0.1 (or unset STAGEFLOW_BIND)`;
148
+ --host 127.0.0.1 (or unset STAGEFLOW_BIND)
149
+
150
+ Or, only when the published port stays on this machine:
151
+ STAGEFLOW_ALLOW_UNAUTHENTICATED_BIND=1`;
148
152
  }
149
- export function assertBindAllowed(bind, tokens) {
153
+ export function assertBindAllowed(bind, tokens, env = process.env) {
154
+ if (env.STAGEFLOW_ALLOW_UNAUTHENTICATED_BIND === "1")
155
+ return;
150
156
  if (!isLoopbackBind(bind) && !hasDriveToken(tokens)) {
151
157
  throw new BindRefusedError(refuseBindMessage(bind));
152
158
  }
@@ -169,6 +175,14 @@ export class BindRefusedError extends Error {
169
175
  function isTriggerWebhookRoute(method, pathname) {
170
176
  return method === "POST" && /^\/api\/triggers\/[^/]+\/webhook$/.test(pathname);
171
177
  }
178
+ /**
179
+ * Live view routes authenticate themselves: the ticket route checks the bearer
180
+ * scope for the requested mode, and the browser's event stream and input posts
181
+ * carry a ticket-derived cookie instead of a bearer token.
182
+ */
183
+ function isLiveViewRoute(pathname) {
184
+ return matchLiveViewRoute(pathname) !== null;
185
+ }
172
186
  export function requiredScopeFor(method, pathname) {
173
187
  if (pathname === "/mcp")
174
188
  return "drive";
@@ -176,6 +190,8 @@ export function requiredScopeFor(method, pathname) {
176
190
  return null;
177
191
  if (isTriggerWebhookRoute(method, pathname))
178
192
  return null;
193
+ if (isLiveViewRoute(pathname))
194
+ return null;
179
195
  if (pathname === "/api/backup" || pathname.startsWith("/api/backup/")) {
180
196
  return "drive";
181
197
  }
@@ -1,5 +1,17 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type CatalogRoot, type ResolveCatalogRootsOptions } from "../config/resolveCatalogRoots.js";
2
3
  import type { StageflowHostBootstrap } from "./bootstrap.js";
4
+ export type CatalogRootApiRecord = {
5
+ project_root: string;
6
+ kind: CatalogRoot["kind"];
7
+ label: string;
8
+ read_only: boolean;
9
+ available: boolean;
10
+ unavailable_reason?: string;
11
+ };
12
+ export declare function catalogRootLabel(root: CatalogRoot): string;
13
+ export declare function mapCatalogRootForApi(root: CatalogRoot): CatalogRootApiRecord;
14
+ export declare function listCatalogRootsForApi(options: ResolveCatalogRootsOptions): Promise<CatalogRootApiRecord[]>;
3
15
  export declare function handleLivez(_req: IncomingMessage, res: ServerResponse): void;
4
16
  export declare function handleReadyz(_req: IncomingMessage, res: ServerResponse, boot: StageflowHostBootstrap): Promise<void>;
5
17
  export declare function buildRichHealthPayload(boot: StageflowHostBootstrap): Promise<Record<string, unknown>>;
@@ -1,12 +1,37 @@
1
+ import path from "node:path";
1
2
  import { getAuthStatus, } from "../agent/providerAuth.js";
2
3
  import { PACKAGE_VERSION, BUILD_SHA } from "../package-meta.js";
3
4
  import { globalStageflowHome } from "../project/globalHome.js";
4
5
  import { redactHostConfig } from "../config/hostConfig.js";
5
- import { resolveCatalogRoots } from "../config/resolveCatalogRoots.js";
6
+ import { resolveCatalogRoots, } from "../config/resolveCatalogRoots.js";
6
7
  import { json } from "./createHttpHost.js";
7
8
  import { livezBody, probeGitVersion, readSchemaHealth, runReadyzChecks, } from "../diagnostics/checks.js";
8
9
  import { buildEgressHealth } from "../net/proxy.js";
9
10
  import { toolchainHealthMap } from "../preflight/toolchain.js";
11
+ export function catalogRootLabel(root) {
12
+ if (root.kind === "workspace")
13
+ return "Workspace";
14
+ if (root.kind === "seeded")
15
+ return "Examples (read-only)";
16
+ const base = path.basename(root.path.replace(/\\/g, "/"));
17
+ return base || root.project_root;
18
+ }
19
+ export function mapCatalogRootForApi(root) {
20
+ return {
21
+ project_root: root.project_root,
22
+ kind: root.kind,
23
+ label: catalogRootLabel(root),
24
+ read_only: root.read_only,
25
+ available: root.available !== false,
26
+ ...(root.available === false && root.unavailable_reason
27
+ ? { unavailable_reason: root.unavailable_reason }
28
+ : {}),
29
+ };
30
+ }
31
+ export async function listCatalogRootsForApi(options) {
32
+ const roots = await resolveCatalogRoots(options);
33
+ return roots.map(mapCatalogRootForApi);
34
+ }
10
35
  function bootProvidersSnapshot(providerBoot) {
11
36
  return providerBoot
12
37
  ? {
@@ -101,11 +126,7 @@ export async function buildRichHealthPayload(boot) {
101
126
  toolchain: toolchainHealthMap(),
102
127
  store_filesystem: boot.storeFilesystem ?? null,
103
128
  egress: buildEgressHealth(),
104
- catalog_roots: catalogRoots.map((r) => ({
105
- project_root: r.project_root,
106
- kind: r.kind,
107
- read_only: r.read_only,
108
- })),
129
+ catalog_roots: catalogRoots.map(mapCatalogRootForApi),
109
130
  boot_providers,
110
131
  providers_live,
111
132
  providers: boot_providers,
@@ -1,18 +1,20 @@
1
- import type { AgentPort } from "../agent/port.js";
1
+ import type { StagePort } from "../agent/port.js";
2
2
  import { type ProviderAuthContext } from "../agent/providerAuth.js";
3
+ import { type LiveViewRoutesOptions } from "./liveViewRoutes.js";
3
4
  import { WorkshopChatSessionRegistry } from "../workshop/chatTurn.js";
4
- import { type OperatorAgentHost } from "../operatorAgent/index.js";
5
+ import { type AgentPort } from "../operatorAgent/index.js";
5
6
  import type { RunStoreKind } from "../runstore/createStore.js";
6
7
  import type { RunStore } from "../runstore/port.js";
7
8
  import type { RunManager } from "../runtime/runManager.js";
8
9
  import type { RunChangeBus } from "../runtime/runChangeBus.js";
10
+ import type { StageBrowserSupport } from "../browser/browserHost.js";
9
11
  import { EmailTriggers } from "../email/triggers.js";
10
12
  import { type AllowedHosts } from "./allowedHosts.js";
11
13
  import { type ControlTokens } from "./controlToken.js";
12
14
  import { DEFAULT_PORT, type HttpHostEnvelope, type HttpHostRouteContext } from "./createHttpHost.js";
13
15
  import { type ShutdownController } from "./shutdown.js";
14
16
  export type UiServerOptions = {
15
- agent: AgentPort;
17
+ agent: StagePort;
16
18
  cwd?: string;
17
19
  agentDir?: string;
18
20
  rootDir?: string;
@@ -28,8 +30,9 @@ export type UiServerOptions = {
28
30
  runChangeBus?: RunChangeBus;
29
31
  allowedHosts?: AllowedHosts;
30
32
  controlTokens?: ControlTokens;
31
- /** Optional Workshop Operator Agent Host (fake in tests). */
32
- workshopOperatorHost?: OperatorAgentHost;
33
+ browser?: StageBrowserSupport;
34
+ /** Optional AgentPort. Workshop is the caller today; tests inject a fake. */
35
+ workshopOperatorHost?: AgentPort;
33
36
  };
34
37
  export declare function defaultUiDistDir(): string;
35
38
  export type OperatorRouteDeps = {
@@ -43,14 +46,16 @@ export type OperatorRouteDeps = {
43
46
  uiDistDir?: string;
44
47
  allowedHosts?: AllowedHosts;
45
48
  controlTokens?: ControlTokens;
49
+ /** Test seams for live view (fake relay, clock, audit sink); production builds everything from persisted state. */
50
+ liveView?: Omit<LiveViewRoutesOptions, "store" | "controlTokens">;
46
51
  /** Live shutdown controller; set after listen so restore can beginDrain. */
47
52
  getShutdown?: () => import("./shutdown.js").ShutdownController | undefined;
48
53
  /**
49
- * Optional Operator Agent Host for Workshop chat (tests inject the fake host).
50
- * Distinct from stage-execution AgentPort. Defaults to live Pi Workshop Author
51
- * (fake remains available via createWorkshopOperatorHost / test injection).
54
+ * Optional AgentPort (tests inject the fake host).
55
+ * Distinct from StagePort. Defaults to resolveAgentPort (Pi).
56
+ * The fake host remains available via createWorkshopOperatorHost.
52
57
  */
53
- workshopOperatorHost?: OperatorAgentHost;
58
+ workshopOperatorHost?: AgentPort;
54
59
  /**
55
60
  * Optional durable Workshop chat registry (host sessions keyed by session id).
56
61
  * Defaults to a registry owned by this route surface.
@@ -64,7 +69,11 @@ export type OperatorRouteDeps = {
64
69
  * `startMcpServer` (headless global-service daemon) — both need the REST
65
70
  * API; only the former needs the UI files.
66
71
  */
67
- export declare function createOperatorRoutes(deps: OperatorRouteDeps): (ctx: HttpHostRouteContext) => Promise<boolean | void>;
72
+ export type OperatorRoutes = ((ctx: HttpHostRouteContext) => Promise<boolean | void>) & {
73
+ /** Ends live view streams, credentials and relay sessions. Browsers are not torn down. */
74
+ dispose(): Promise<void>;
75
+ };
76
+ export declare function createOperatorRoutes(deps: OperatorRouteDeps): OperatorRoutes;
68
77
  export declare function startUiServer(options: UiServerOptions): Promise<HttpHostEnvelope & {
69
78
  shutdown: ShutdownController;
70
79
  }>;