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
@@ -0,0 +1,146 @@
1
+ import { z } from "zod";
2
+ import { ChannelError } from "../errors.js";
3
+ import { httpCall, parseJson, statusFailure } from "../http.js";
4
+ import { healthOf, importModule, receiptFor, withSendTimeout, withSpectrumApp, zodValidator } from "./kit.js";
5
+ import { PHOTON_BASE_URL, PHOTON_CREDENTIAL_YAML, PHOTON_FIELDS, credentialsOf, photonData, photonHeaders } from "./photonImessage.js";
6
+ export const WHATSAPP_META = {
7
+ label: "WhatsApp Business",
8
+ blurb: "Not connected · via Photon",
9
+ icon: "phone",
10
+ via: "Photon",
11
+ note: "Enable WhatsApp for the project in the Photon dashboard first. Uses the Spectrum SDK packages (optional dependencies). Stages pin an approved template per recipient.",
12
+ fields: PHOTON_FIELDS,
13
+ recipient: { label: "Recipient", placeholder: "+14155550123", multiple: false, cc: false, template: true },
14
+ envNames: ["PHOTON_PROJECT_ID", "PHOTON_PROJECT_SECRET"],
15
+ yamlExample: `${PHOTON_CREDENTIAL_YAML}connections:
16
+ - id: orders-whatsapp
17
+ provider: whatsapp
18
+ credential: photon-main
19
+ `,
20
+ stageExample: ` to: "+14155550123"
21
+ template:
22
+ name: order_update
23
+ languageCode: en_US
24
+ bodyParams: ["{{message}}"]`,
25
+ };
26
+ export const MESSAGE_PLACEHOLDER = "{{message}}";
27
+ export const MAX_TEMPLATE_PARAM = 1024;
28
+ const templateSchema = z.object({
29
+ name: z.string().regex(/^[a-z0-9_]{1,512}$/),
30
+ languageCode: z.string().regex(/^[a-z]{2,3}(_[A-Z]{2})?$/),
31
+ bodyParams: z.array(z.string().min(1).max(MAX_TEMPLATE_PARAM)).max(10).optional(),
32
+ }).strict();
33
+ const targetSchema = z.object({
34
+ to: z.string().regex(/^\+[1-9]\d{6,14}$/),
35
+ template: templateSchema.optional(),
36
+ }).strict();
37
+ const validateConfig = zodValidator(z.object({}).strict(), "config", () => ({}));
38
+ const validateTarget = zodValidator(targetSchema, "target", (data) => ({
39
+ recipient: data.to,
40
+ ...(data.template ? { template: data.template } : {}),
41
+ }));
42
+ /** Template parameters cannot hold newlines, tabs or long runs of spaces. */
43
+ export function templateParam(text) {
44
+ return text.replace(/[\r\n\t]+/g, " ").replace(/ {2,}/g, " ").trim();
45
+ }
46
+ /** Fills `{{message}}` in the pinned parameters. Fails before sending if a result is empty or too long. */
47
+ export function fillTemplate(template, message, connectionId) {
48
+ const text = templateParam(message.subject ? `${message.subject}: ${message.text}` : message.text);
49
+ const bodyParams = template.bodyParams?.map(param => (param.includes(MESSAGE_PLACEHOLDER) ? param.split(MESSAGE_PLACEHOLDER).join(text) : param));
50
+ if (bodyParams?.some(param => param.length === 0 || param.length > MAX_TEMPLATE_PARAM)) {
51
+ throw new ChannelError("CHANNEL_INVALID_INPUT", false, { connectionId, field: "text" });
52
+ }
53
+ return { ...template, ...(bodyParams ? { bodyParams } : {}) };
54
+ }
55
+ function metaCode(error) {
56
+ const candidates = [error?.code, error?.error?.code];
57
+ for (const value of candidates)
58
+ if (typeof value === "number")
59
+ return value;
60
+ const match = /\b(13\d{4}|190)\b/.exec(error instanceof Error ? error.message : "");
61
+ return match ? Number(match[1]) : undefined;
62
+ }
63
+ const RECIPIENT_CODES = new Set([131026, 131030, 131021]);
64
+ const INVALID_CODES = new Set([132000, 132001, 132005, 132012, 132015, 132016]);
65
+ const RATE_CODES = new Set([131056, 130429, 131048]);
66
+ /** Maps SDK and Meta errors. Unclassified errors may have happened after the send, so they are unknown. */
67
+ export function classifyWhatsappError(error, connectionId) {
68
+ if (error instanceof ChannelError)
69
+ return error;
70
+ const detail = { connectionId };
71
+ const code = metaCode(error);
72
+ if (code === 131047 || code === 131051)
73
+ return new ChannelError("CHANNEL_WINDOW_CLOSED", false, detail);
74
+ if (code !== undefined && RECIPIENT_CODES.has(code))
75
+ return new ChannelError("CHANNEL_RECIPIENT_REJECTED", false, detail);
76
+ if (code !== undefined && INVALID_CODES.has(code))
77
+ return new ChannelError("CHANNEL_INVALID_INPUT", false, detail);
78
+ if (code !== undefined && RATE_CODES.has(code))
79
+ return new ChannelError("CHANNEL_RATE_LIMIT", true, detail);
80
+ if (code === 190)
81
+ return new ChannelError("CHANNEL_AUTH_FAILED", false, detail);
82
+ const status = error?.status;
83
+ if (status === 401)
84
+ return new ChannelError("CHANNEL_AUTH_FAILED", false, detail);
85
+ if (status === 403)
86
+ return new ChannelError("CHANNEL_UNAUTHORIZED", false, detail);
87
+ if (status === 429)
88
+ return new ChannelError("CHANNEL_RATE_LIMIT", true, detail);
89
+ return new ChannelError("CHANNEL_SEND_OUTCOME_UNKNOWN", false, detail);
90
+ }
91
+ /** The Spectrum SDK send for WhatsApp, on the same shared lifecycle as iMessage. */
92
+ export function spectrumWhatsappTransport(importer = importModule) {
93
+ return {
94
+ send: (credentials, recipient, outbound) => withSpectrumApp(importer, credentials, { pkg: "@spectrum-ts/whatsapp-business", exportName: "whatsappBusiness" }, async ({ platform, module }) => {
95
+ const user = await platform.user(recipient);
96
+ const space = await platform.space.create(user);
97
+ const sent = await space.send("template" in outbound ? module.whatsappTemplate(outbound.template) : outbound.text);
98
+ return typeof sent?.id === "string" ? { messageId: sent.id } : {};
99
+ }),
100
+ };
101
+ }
102
+ /**
103
+ * WhatsApp Business through a Photon project (cloud mode), 1:1 only. Free-form text works only
104
+ * inside the 24-hour window after the recipient last wrote to the business, so a stage that
105
+ * writes first must pin an approved `template`. Receiving is not part of this phase.
106
+ */
107
+ export function createPhotonWhatsappProvider(options = {}) {
108
+ const doFetch = options.fetch ?? fetch;
109
+ const base = options.baseUrl ?? PHOTON_BASE_URL;
110
+ const transport = options.transport ?? spectrumWhatsappTransport();
111
+ return {
112
+ id: "whatsapp",
113
+ meta: WHATSAPP_META,
114
+ operations: ["send"],
115
+ secrets: { required: [] },
116
+ credentialProvider: "photon",
117
+ validateConfig,
118
+ validateTarget,
119
+ check: (connection, signal) => healthOf(async () => {
120
+ const credentials = credentialsOf(connection);
121
+ const result = await httpCall({
122
+ fetch: doFetch, url: `${base}/projects/${encodeURIComponent(credentials.projectId)}/whatsapp-business/tokens`, method: "POST",
123
+ headers: photonHeaders(credentials), body: {}, timeoutMs: options.checkTimeoutMs ?? 10000, signal, mode: "check", connectionId: connection.id,
124
+ });
125
+ if (result.status < 200 || result.status >= 300)
126
+ throw statusFailure(result.status, "check", connection.id);
127
+ const auth = photonData(parseJson(result.text))?.auth;
128
+ if (!(auth && typeof auth === "object" && Object.keys(auth).length > 0)) {
129
+ throw new ChannelError("CHANNEL_INVALID_INPUT", false, { connectionId: connection.id, field: "whatsapp" });
130
+ }
131
+ }),
132
+ async send(connection, target, message, _context) {
133
+ const credentials = credentialsOf(connection);
134
+ const outbound = target.template
135
+ ? { template: fillTemplate(target.template, message, connection.id) }
136
+ : { text: message.subject ? `${message.subject}\n\n${message.text}` : message.text };
137
+ try {
138
+ const sent = await withSendTimeout(options.sendTimeoutMs ?? 45000, connection.id, transport.send(credentials, target.recipient, outbound));
139
+ return receiptFor(sent.messageId);
140
+ }
141
+ catch (error) {
142
+ throw classifyWhatsappError(error, connection.id);
143
+ }
144
+ },
145
+ };
146
+ }
@@ -0,0 +1,25 @@
1
+ import { ChannelError } from "../errors.js";
2
+ import type { HttpMode } from "../http.js";
3
+ import type { ChannelProvider, ProviderMeta } from "../types.js";
4
+ export type SlackConfig = {
5
+ teamId?: string;
6
+ };
7
+ export type SlackTarget = {
8
+ channel: string;
9
+ };
10
+ export declare const SLACK_BASE_URL = "https://slack.com/api";
11
+ export declare const SLACK_META: ProviderMeta;
12
+ export type SlackOptions = {
13
+ fetch?: typeof fetch;
14
+ baseUrl?: string;
15
+ sendTimeoutMs?: number;
16
+ checkTimeoutMs?: number;
17
+ };
18
+ /** Maps a Slack `ok: false` error name. Names are mapped, never echoed. */
19
+ export declare function slackFailure(name: unknown, mode: HttpMode, connectionId: string): ChannelError;
20
+ /**
21
+ * Posts as a Slack bot through `chat.postMessage`. The bot needs `chat:write`; posting to a
22
+ * public channel it has not joined also needs `chat:write.public`, and a direct message to a
23
+ * user id needs `im:write`. Receiving is not part of this phase.
24
+ */
25
+ export declare function createSlackProvider(options?: SlackOptions): ChannelProvider<SlackConfig, SlackTarget>;
@@ -0,0 +1,101 @@
1
+ import { z } from "zod";
2
+ import { ChannelError } from "../errors.js";
3
+ import { httpCall, parseJson, statusFailure } from "../http.js";
4
+ import { healthOf, receiptFor, zodValidator } from "./kit.js";
5
+ export const SLACK_BASE_URL = "https://slack.com/api";
6
+ export const SLACK_META = {
7
+ label: "Slack",
8
+ blurb: "Not connected · post as a bot",
9
+ icon: "hash",
10
+ fields: [
11
+ { key: "botToken", label: "Bot token", hint: "xoxb-… from your Slack app (OAuth & Permissions). Needs chat:write.", target: "secret", input: "password", required: true, placeholder: "xoxb-..." },
12
+ { key: "teamId", label: "Workspace ID (optional)", hint: "Pins the connection to one workspace, such as T0123ABCD.", target: "config", input: "text", required: false, placeholder: "T0123ABCD" },
13
+ ],
14
+ recipient: { label: "Channel id", placeholder: "C0123ABCD (channel, group, DM or user id)", multiple: false, cc: false, template: false },
15
+ envNames: ["SLACK_BOT_TOKEN"],
16
+ yamlExample: `connections:
17
+ - id: ops-slack
18
+ provider: slack
19
+ secrets:
20
+ botToken: env:SLACK_BOT_TOKEN
21
+ `,
22
+ stageExample: " to: C0123ABCD",
23
+ };
24
+ const configSchema = z.object({ teamId: z.string().regex(/^T[A-Z0-9]{2,31}$/).optional() }).strict();
25
+ const targetSchema = z.object({ to: z.string().regex(/^[CGDU][A-Z0-9]{2,31}$/) }).strict();
26
+ const validateConfig = zodValidator(configSchema, "config");
27
+ const validateTarget = zodValidator(targetSchema, "target", (data) => ({ channel: data.to }));
28
+ const AUTH_ERRORS = new Set(["invalid_auth", "not_authed", "account_inactive", "token_revoked", "token_expired"]);
29
+ const SCOPE_ERRORS = new Set(["missing_scope", "not_allowed_token_type", "no_permission", "restricted_action", "access_denied"]);
30
+ const RECIPIENT_ERRORS = new Set([
31
+ "channel_not_found", "user_not_found", "is_archived", "not_in_channel", "cannot_dm_bot", "user_disabled",
32
+ "restricted_action_read_only_channel", "restricted_action_thread_only_channel", "channel_is_archived",
33
+ ]);
34
+ const TRANSIENT_ERRORS = new Set(["internal_error", "fatal_error", "service_unavailable", "request_timeout"]);
35
+ /** Maps a Slack `ok: false` error name. Names are mapped, never echoed. */
36
+ export function slackFailure(name, mode, connectionId) {
37
+ const detail = { connectionId };
38
+ if (typeof name !== "string")
39
+ return new ChannelError(mode === "send" ? "CHANNEL_SEND_OUTCOME_UNKNOWN" : "CHANNEL_CONNECTION_FAILED", mode !== "send", detail);
40
+ if (AUTH_ERRORS.has(name))
41
+ return new ChannelError("CHANNEL_AUTH_FAILED", false, detail);
42
+ if (SCOPE_ERRORS.has(name))
43
+ return new ChannelError("CHANNEL_UNAUTHORIZED", false, detail);
44
+ if (RECIPIENT_ERRORS.has(name))
45
+ return new ChannelError("CHANNEL_RECIPIENT_REJECTED", false, detail);
46
+ if (name === "ratelimited" || name === "rate_limited")
47
+ return new ChannelError("CHANNEL_RATE_LIMIT", true, detail);
48
+ if (TRANSIENT_ERRORS.has(name)) {
49
+ return mode === "send" ? new ChannelError("CHANNEL_SEND_OUTCOME_UNKNOWN", false, detail) : new ChannelError("CHANNEL_CONNECTION_FAILED", true, detail);
50
+ }
51
+ return new ChannelError("CHANNEL_INVALID_INPUT", false, detail);
52
+ }
53
+ /**
54
+ * Posts as a Slack bot through `chat.postMessage`. The bot needs `chat:write`; posting to a
55
+ * public channel it has not joined also needs `chat:write.public`, and a direct message to a
56
+ * user id needs `im:write`. Receiving is not part of this phase.
57
+ */
58
+ export function createSlackProvider(options = {}) {
59
+ const doFetch = options.fetch ?? fetch;
60
+ const base = options.baseUrl ?? SLACK_BASE_URL;
61
+ const headers = (connection) => ({ authorization: `Bearer ${connection.secrets.botToken}`, accept: "application/json" });
62
+ return {
63
+ id: "slack",
64
+ meta: SLACK_META,
65
+ operations: ["send"],
66
+ secrets: { required: ["botToken"] },
67
+ validateConfig,
68
+ validateTarget,
69
+ describe: config => (config.teamId ? { identity: config.teamId } : {}),
70
+ check: (connection, signal) => healthOf(async () => {
71
+ const result = await httpCall({
72
+ fetch: doFetch, url: `${base}/auth.test`, method: "POST", headers: headers(connection),
73
+ timeoutMs: options.checkTimeoutMs ?? 10000, signal, mode: "check", connectionId: connection.id,
74
+ });
75
+ if (result.status < 200 || result.status >= 300)
76
+ throw statusFailure(result.status, "check", connection.id);
77
+ const body = parseJson(result.text);
78
+ if (body?.ok !== true)
79
+ throw slackFailure(body?.error, "check", connection.id);
80
+ if (connection.config.teamId !== undefined && body.team_id !== connection.config.teamId) {
81
+ throw new ChannelError("CHANNEL_INVALID_INPUT", false, { connectionId: connection.id, field: "teamId" });
82
+ }
83
+ }),
84
+ async send(connection, target, message, _context) {
85
+ const text = message.subject ? `*${message.subject}*\n${message.text}` : message.text;
86
+ const result = await httpCall({
87
+ fetch: doFetch, url: `${base}/chat.postMessage`, method: "POST", headers: headers(connection),
88
+ body: { channel: target.channel, text, link_names: false, unfurl_links: false, unfurl_media: false },
89
+ timeoutMs: options.sendTimeoutMs ?? 30000, mode: "send", connectionId: connection.id,
90
+ });
91
+ if (result.status < 200 || result.status >= 300)
92
+ throw statusFailure(result.status, "send", connection.id);
93
+ const body = parseJson(result.text);
94
+ if (body === undefined)
95
+ throw new ChannelError("CHANNEL_SEND_OUTCOME_UNKNOWN", false, { connectionId: connection.id });
96
+ if (body.ok !== true)
97
+ throw slackFailure(body.error, "send", connection.id);
98
+ return receiptFor(typeof body.ts === "string" ? body.ts : undefined);
99
+ },
100
+ };
101
+ }
@@ -0,0 +1,21 @@
1
+ import type { ChannelProvider, ProviderMeta } from "../types.js";
2
+ export type TelegramConfig = {
3
+ botUsername?: string;
4
+ };
5
+ export type TelegramTarget = {
6
+ chatId: string | number;
7
+ };
8
+ export declare const TELEGRAM_BASE_URL = "https://api.telegram.org";
9
+ export declare const TELEGRAM_MAX_TEXT = 4096;
10
+ export declare const TELEGRAM_META: ProviderMeta;
11
+ export type TelegramOptions = {
12
+ fetch?: typeof fetch;
13
+ baseUrl?: string;
14
+ sendTimeoutMs?: number;
15
+ checkTimeoutMs?: number;
16
+ };
17
+ /**
18
+ * Sends through the Telegram Bot API with a bot token. The recipient must have started the
19
+ * bot (or the bot must be a member of the group or channel). Receiving is not part of this phase.
20
+ */
21
+ export declare function createTelegramProvider(options?: TelegramOptions): ChannelProvider<TelegramConfig, TelegramTarget>;
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ import { ChannelError } from "../errors.js";
3
+ import { httpCall, parseJson, statusFailure } from "../http.js";
4
+ import { healthOf, receiptFor, zodValidator } from "./kit.js";
5
+ export const TELEGRAM_BASE_URL = "https://api.telegram.org";
6
+ export const TELEGRAM_MAX_TEXT = 4096;
7
+ export const TELEGRAM_META = {
8
+ label: "Telegram",
9
+ blurb: "Not connected · bot token",
10
+ icon: "send",
11
+ fields: [
12
+ { key: "botToken", label: "Bot token", hint: "From @BotFather. People must start the bot before it can message them.", target: "secret", input: "password", required: true, placeholder: "123456:ABC..." },
13
+ { key: "botUsername", label: "Bot username (optional)", hint: "Fails the check if the token belongs to another bot.", target: "config", input: "text", required: false, placeholder: "acme_alerts_bot" },
14
+ ],
15
+ recipient: { label: "Chat id", placeholder: "123456789 or @channelname", multiple: false, cc: false, template: false },
16
+ envNames: ["TELEGRAM_BOT_TOKEN"],
17
+ yamlExample: `connections:
18
+ - id: alerts-telegram
19
+ provider: telegram
20
+ secrets:
21
+ botToken: env:TELEGRAM_BOT_TOKEN
22
+ `,
23
+ stageExample: ' to: "123456789"',
24
+ };
25
+ const configSchema = z.object({ botUsername: z.string().regex(/^[A-Za-z][A-Za-z0-9_]{4,31}$/).optional() }).strict();
26
+ const chatId = z.union([
27
+ z.number().int().refine(Number.isSafeInteger),
28
+ z.string().regex(/^-?\d{1,20}$/),
29
+ z.string().regex(/^@[A-Za-z][A-Za-z0-9_]{4,31}$/),
30
+ ]);
31
+ const targetSchema = z.object({ to: chatId }).strict();
32
+ const validateConfig = zodValidator(configSchema, "config");
33
+ const validateTarget = zodValidator(targetSchema, "target", (data) => ({ chatId: data.to }));
34
+ /**
35
+ * Telegram mirrors its error in the HTTP status. A bot cannot message a user who has not
36
+ * started it or who blocked it (403), and an unknown chat is a 400. The description is only
37
+ * matched, never echoed.
38
+ */
39
+ function telegramFailure(status, body, mode, connectionId) {
40
+ const detail = { connectionId };
41
+ const description = typeof body?.description === "string" ? body.description.toLowerCase() : "";
42
+ if (status === 404)
43
+ return new ChannelError("CHANNEL_AUTH_FAILED", false, detail);
44
+ if (status === 403 && mode === "send")
45
+ return new ChannelError("CHANNEL_RECIPIENT_REJECTED", false, detail);
46
+ if (status === 400 && mode === "send" && /chat not found|user not found|peer_id_invalid|chat_id is empty/.test(description)) {
47
+ return new ChannelError("CHANNEL_RECIPIENT_REJECTED", false, detail);
48
+ }
49
+ return statusFailure(status, mode, connectionId);
50
+ }
51
+ /**
52
+ * Sends through the Telegram Bot API with a bot token. The recipient must have started the
53
+ * bot (or the bot must be a member of the group or channel). Receiving is not part of this phase.
54
+ */
55
+ export function createTelegramProvider(options = {}) {
56
+ const doFetch = options.fetch ?? fetch;
57
+ const base = options.baseUrl ?? TELEGRAM_BASE_URL;
58
+ const url = (connection, method) => `${base}/bot${connection.secrets.botToken}/${method}`;
59
+ return {
60
+ id: "telegram",
61
+ meta: TELEGRAM_META,
62
+ operations: ["send"],
63
+ secrets: { required: ["botToken"] },
64
+ validateConfig,
65
+ validateTarget,
66
+ describe: config => (config.botUsername ? { identity: `@${config.botUsername}` } : {}),
67
+ check: (connection, signal) => healthOf(async () => {
68
+ const result = await httpCall({
69
+ fetch: doFetch, url: url(connection, "getMe"), method: "GET", headers: { accept: "application/json" },
70
+ timeoutMs: options.checkTimeoutMs ?? 10000, signal, mode: "check", connectionId: connection.id,
71
+ });
72
+ const body = parseJson(result.text);
73
+ if (result.status < 200 || result.status >= 300)
74
+ throw telegramFailure(result.status, body, "check", connection.id);
75
+ if (body?.ok !== true)
76
+ throw new ChannelError("CHANNEL_CONNECTION_FAILED", true, { connectionId: connection.id });
77
+ const pinned = connection.config.botUsername;
78
+ if (pinned !== undefined && String(body.result?.username).toLowerCase() !== pinned.toLowerCase()) {
79
+ throw new ChannelError("CHANNEL_INVALID_INPUT", false, { connectionId: connection.id, field: "botUsername" });
80
+ }
81
+ }),
82
+ async send(connection, target, message, _context) {
83
+ const text = message.subject ? `${message.subject}\n\n${message.text}` : message.text;
84
+ if (text.length > TELEGRAM_MAX_TEXT)
85
+ throw new ChannelError("CHANNEL_INVALID_INPUT", false, { connectionId: connection.id, field: "text" });
86
+ const result = await httpCall({
87
+ fetch: doFetch, url: url(connection, "sendMessage"), method: "POST", headers: { accept: "application/json" },
88
+ body: { chat_id: target.chatId, text, link_preview_options: { is_disabled: true } },
89
+ timeoutMs: options.sendTimeoutMs ?? 30000, mode: "send", connectionId: connection.id,
90
+ });
91
+ const body = parseJson(result.text);
92
+ if (result.status < 200 || result.status >= 300)
93
+ throw telegramFailure(result.status, body, "send", connection.id);
94
+ if (body?.ok !== true)
95
+ throw new ChannelError("CHANNEL_SEND_OUTCOME_UNKNOWN", false, { connectionId: connection.id });
96
+ const id = body.result?.message_id;
97
+ return receiptFor(typeof id === "number" ? String(id) : undefined);
98
+ },
99
+ };
100
+ }
@@ -0,0 +1,5 @@
1
+ import type { AnyChannelProvider } from "./types.js";
2
+ /** Built-in providers are listed in the initial map as they are implemented. */
3
+ export declare function channelProviders(): AnyChannelProvider[];
4
+ export declare function registerChannelProvider(provider: AnyChannelProvider): void;
5
+ export declare function unregisterChannelProvider(id: string): void;
@@ -0,0 +1,22 @@
1
+ import { createAgentMailProvider } from "./providers/agentmail.js";
2
+ import { createSlackProvider } from "./providers/slack.js";
3
+ import { createTelegramProvider } from "./providers/telegram.js";
4
+ import { createPhotonImessageProvider } from "./providers/photonImessage.js";
5
+ import { createPhotonWhatsappProvider } from "./providers/photonWhatsapp.js";
6
+ const providers = new Map([
7
+ ["agentmail", createAgentMailProvider()],
8
+ ["slack", createSlackProvider()],
9
+ ["telegram", createTelegramProvider()],
10
+ ["imessage", createPhotonImessageProvider()],
11
+ ["whatsapp", createPhotonWhatsappProvider()],
12
+ ]);
13
+ /** Built-in providers are listed in the initial map as they are implemented. */
14
+ export function channelProviders() {
15
+ return [...providers.values()];
16
+ }
17
+ export function registerChannelProvider(provider) {
18
+ providers.set(provider.id, provider);
19
+ }
20
+ export function unregisterChannelProvider(id) {
21
+ providers.delete(id);
22
+ }
@@ -0,0 +1,54 @@
1
+ import { type ConnectionsFile } from "./config.js";
2
+ import { ChannelSecretStore, type SecretReader } from "./secretStore.js";
3
+ import type { AnyChannelProvider, ConnectionSummary, ResolvedConnection, ResolvedCredential } from "./types.js";
4
+ export declare const CONNECTIONS_FILE_NAME = "connections.yaml";
5
+ /**
6
+ * Where connections live. Connections are host-level, like provider credentials, so the default is
7
+ * `$STAGEFLOW_HOME/connections.yaml`. A `connections.yaml` in the project root takes precedence when
8
+ * it exists (CI and checked-in setups), and `STAGEFLOW_CONNECTIONS_FILE` overrides both.
9
+ */
10
+ export declare function connectionsFilePath(cwd: string, env?: NodeJS.ProcessEnv): string;
11
+ export declare function defaultSecretStore(): ChannelSecretStore;
12
+ export type ChannelRegistryOptions = {
13
+ cwd: string;
14
+ providers?: readonly AnyChannelProvider[];
15
+ env?: NodeJS.ProcessEnv;
16
+ /** Owner scope. TODO(multi-tenant): the local default is the workspace path, like email accounts. */
17
+ scope?: string;
18
+ file?: string;
19
+ /** Already parsed content, used to validate an edit before it is written. */
20
+ parsed?: ConnectionsFile;
21
+ secretStore?: SecretReader;
22
+ };
23
+ /** Host-owned, read-only view of `connections.yaml`. Reads return copies. */
24
+ export declare class ChannelRegistry {
25
+ readonly scope: string;
26
+ private readonly env;
27
+ private readonly secretStore;
28
+ private readonly providers;
29
+ private readonly credentials;
30
+ private readonly connections;
31
+ constructor(options: ChannelRegistryOptions);
32
+ list(): ConnectionSummary[];
33
+ private summarize;
34
+ get(id: string, requireEnabled?: boolean): ConnectionSummary;
35
+ providerById(providerId: string): AnyChannelProvider;
36
+ /** Environment variable names that connections and credentials point at with `env:` references. */
37
+ envSecretNames(): string[];
38
+ providerList(): AnyChannelProvider[];
39
+ hasCredential(id: string): boolean;
40
+ /** Resolves a shared credential by id, for providers that reference one. */
41
+ resolveCredential(id: string): ResolvedCredential;
42
+ hasConnection(id: string): boolean;
43
+ providerFor(id: string): AnyChannelProvider;
44
+ validateTarget(id: string, target: unknown): unknown;
45
+ /** Reads secrets from the environment at call time. Values are never cached on the registry. */
46
+ resolve(id: string, requireEnabled?: boolean): ResolvedConnection;
47
+ private entry;
48
+ private requireProvider;
49
+ private addCredential;
50
+ private addConnection;
51
+ private checkSecretNames;
52
+ private checkCredential;
53
+ }
54
+ export declare function sealed<T extends ResolvedConnection>(value: T): T;