stageflow 0.32.0 → 0.35.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 (335) hide show
  1. package/README.md +4 -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 +50 -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/fakeAgent.js +0 -6
  12. package/dist/agent/piAdapter.d.ts +2 -2
  13. package/dist/agent/piAdapter.js +116 -15
  14. package/dist/agent/piIsolatedMcp.d.ts +1 -0
  15. package/dist/agent/piIsolatedMcp.js +19 -1
  16. package/dist/agent/piIsolatedMcpProbe.d.ts +11 -0
  17. package/dist/agent/piIsolatedMcpProbe.js +20 -0
  18. package/dist/agent/port.d.ts +2 -2
  19. package/dist/agent/providerAuth.d.ts +6 -0
  20. package/dist/agent/providerAuth.js +86 -17
  21. package/dist/agent/{resolveAgentPort.d.ts → resolveStagePort.d.ts} +8 -6
  22. package/dist/agent/{resolveAgentPort.js → resolveStagePort.js} +13 -9
  23. package/dist/agent/stageTurnDriver.d.ts +33 -0
  24. package/dist/agent/stageTurnDriver.js +64 -0
  25. package/dist/agent/toolOutputBudget.d.ts +46 -0
  26. package/dist/agent/toolOutputBudget.js +97 -0
  27. package/dist/agent/toolOutputBudgetExtension.d.ts +22 -0
  28. package/dist/agent/toolOutputBudgetExtension.js +141 -0
  29. package/dist/agent/toolOutputSpill.d.ts +34 -0
  30. package/dist/agent/toolOutputSpill.js +85 -0
  31. package/dist/browser/agentBrowserLiveViewRelay.d.ts +41 -0
  32. package/dist/browser/agentBrowserLiveViewRelay.js +801 -0
  33. package/dist/browser/anchor.d.ts +2 -0
  34. package/dist/browser/anchor.js +2 -1
  35. package/dist/browser/auditSink.d.ts +8 -0
  36. package/dist/browser/browserHost.d.ts +29 -0
  37. package/dist/browser/browserSweep.d.ts +4 -1
  38. package/dist/browser/browserSweep.js +7 -0
  39. package/dist/browser/browserTeardown.d.ts +1 -0
  40. package/dist/browser/browserTeardown.js +32 -2
  41. package/dist/browser/containerBrowserEndpoint.d.ts +11 -0
  42. package/dist/browser/containerBrowserEndpoint.js +57 -0
  43. package/dist/browser/containerBrowserHost.d.ts +24 -0
  44. package/dist/browser/containerBrowserHost.js +147 -0
  45. package/dist/browser/dockerSandboxOrchestrator.d.ts +26 -0
  46. package/dist/browser/dockerSandboxOrchestrator.js +142 -0
  47. package/dist/browser/fakeLiveViewRelay.d.ts +15 -0
  48. package/dist/browser/fakeLiveViewRelay.js +94 -0
  49. package/dist/browser/fakeLiveViewSource.d.ts +6 -0
  50. package/dist/browser/fakeLiveViewSource.js +16 -0
  51. package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -1
  52. package/dist/browser/fakeRemoteBrowserHost.js +2 -1
  53. package/dist/browser/fakeSandboxOrchestrator.d.ts +9 -0
  54. package/dist/browser/fakeSandboxOrchestrator.js +44 -0
  55. package/dist/browser/gateHandoff.d.ts +0 -2
  56. package/dist/browser/gateHandoff.js +5 -11
  57. package/dist/browser/hostCapabilities.d.ts +23 -0
  58. package/dist/browser/hostCapabilities.js +23 -0
  59. package/dist/browser/humanLogin.d.ts +2 -2
  60. package/dist/browser/humanLogin.js +11 -2
  61. package/dist/browser/liveViewPersisted.d.ts +11 -0
  62. package/dist/browser/liveViewPersisted.js +22 -0
  63. package/dist/browser/liveViewRelay.d.ts +76 -0
  64. package/dist/browser/liveViewRelay.js +1 -0
  65. package/dist/browser/liveViewSessions.d.ts +25 -0
  66. package/dist/browser/liveViewSessions.js +139 -0
  67. package/dist/browser/liveViewSource.d.ts +25 -0
  68. package/dist/browser/liveViewSource.js +7 -0
  69. package/dist/browser/liveViewTickets.d.ts +46 -0
  70. package/dist/browser/liveViewTickets.js +122 -0
  71. package/dist/browser/localBrowserHost.d.ts +10 -0
  72. package/dist/browser/localBrowserHost.js +53 -7
  73. package/dist/browser/ownerScope.d.ts +10 -0
  74. package/dist/browser/ownerScope.js +6 -0
  75. package/dist/browser/profileStore.d.ts +5 -2
  76. package/dist/browser/profileStore.js +3 -5
  77. package/dist/browser/sandboxOrchestrator.d.ts +60 -0
  78. package/dist/browser/sandboxOrchestrator.js +8 -0
  79. package/dist/browser/sessionApiSandboxOrchestrator.d.ts +34 -0
  80. package/dist/browser/sessionApiSandboxOrchestrator.js +108 -0
  81. package/dist/browser/stageBrowserEnv.d.ts +7 -0
  82. package/dist/browser/stageBrowserEnv.js +53 -15
  83. package/dist/browser/stageHandoff.d.ts +47 -0
  84. package/dist/browser/stageHandoff.js +101 -0
  85. package/dist/browser/stageProfileLock.d.ts +1 -0
  86. package/dist/browser/stageProfileLock.js +1 -3
  87. package/dist/browser/volumeProfileStore.d.ts +7 -0
  88. package/dist/browser/volumeProfileStore.js +35 -0
  89. package/dist/cli/browserCommand.d.ts +3 -1
  90. package/dist/cli/browserCommand.js +25 -20
  91. package/dist/cli/resolveCliProjectRoot.d.ts +7 -0
  92. package/dist/cli/resolveCliProjectRoot.js +27 -0
  93. package/dist/cli/runCommand.d.ts +1 -1
  94. package/dist/cli/runCommand.js +59 -17
  95. package/dist/cli/skillsCommand.d.ts +20 -0
  96. package/dist/cli/skillsCommand.js +74 -31
  97. package/dist/cli/validateCommand.d.ts +1 -1
  98. package/dist/cli/validateCommand.js +22 -4
  99. package/dist/cli.js +4 -4
  100. package/dist/config/browseCatalog.d.ts +2 -0
  101. package/dist/config/browseCatalog.js +6 -0
  102. package/dist/config/catalogRelativePath.d.ts +4 -0
  103. package/dist/config/catalogRelativePath.js +37 -9
  104. package/dist/config/createStage.d.ts +1 -0
  105. package/dist/config/createStage.js +11 -2
  106. package/dist/config/createTask.d.ts +30 -0
  107. package/dist/config/createTask.js +161 -0
  108. package/dist/config/createTrigger.d.ts +15 -0
  109. package/dist/config/createTrigger.js +32 -25
  110. package/dist/config/draftPackage.d.ts +41 -0
  111. package/dist/config/draftPackage.js +216 -23
  112. package/dist/config/ensureCatalogScanRoot.d.ts +2 -1
  113. package/dist/config/ensureCatalogScanRoot.js +6 -2
  114. package/dist/config/findTaskInCatalog.d.ts +33 -0
  115. package/dist/config/findTaskInCatalog.js +69 -0
  116. package/dist/config/hostConfig.d.ts +21 -0
  117. package/dist/config/hostConfig.js +113 -1
  118. package/dist/config/importTask.d.ts +19 -0
  119. package/dist/config/importTask.js +133 -0
  120. package/dist/config/installSkillRequest.d.ts +40 -0
  121. package/dist/config/installSkillRequest.js +286 -0
  122. package/dist/config/listConfig.d.ts +0 -16
  123. package/dist/config/listConfig.js +0 -3
  124. package/dist/config/loadOutcome.d.ts +11 -6
  125. package/dist/config/loadPipeline.js +0 -1
  126. package/dist/config/loadStage.js +2 -0
  127. package/dist/config/loadStageflowManifest.js +4 -1
  128. package/dist/config/loadTask.js +2 -0
  129. package/dist/config/loadTrigger.js +2 -0
  130. package/dist/config/mergePipelineIncludes.js +3 -0
  131. package/dist/config/normalizePipelineStageEntry.js +10 -1
  132. package/dist/config/printTargetYaml.js +0 -1
  133. package/dist/config/publishDraftPackage.d.ts +5 -1
  134. package/dist/config/publishDraftPackage.js +4 -1
  135. package/dist/config/resolveCatalogRoots.d.ts +4 -1
  136. package/dist/config/resolveCatalogRoots.js +18 -1
  137. package/dist/config/skillUsageIndex.d.ts +6 -0
  138. package/dist/config/skillUsageIndex.js +39 -0
  139. package/dist/config/stageBrowser.js +13 -0
  140. package/dist/config/triggerAdapterStatus.d.ts +11 -0
  141. package/dist/config/triggerAdapterStatus.js +90 -0
  142. package/dist/config/triggerCatalog.d.ts +41 -2
  143. package/dist/config/triggerCatalog.js +107 -15
  144. package/dist/config/updateTask.d.ts +30 -0
  145. package/dist/config/updateTask.js +119 -0
  146. package/dist/config/updateTrigger.d.ts +38 -0
  147. package/dist/config/updateTrigger.js +220 -0
  148. package/dist/config/validateCatalog.d.ts +6 -2
  149. package/dist/config/validateCatalog.js +48 -7
  150. package/dist/config/workshopCatalogFilenames.d.ts +37 -0
  151. package/dist/config/workshopCatalogFilenames.js +125 -0
  152. package/dist/config/workshopCatalogRepair.d.ts +7 -0
  153. package/dist/config/workshopCatalogRepair.js +144 -0
  154. package/dist/config/yamlParsePosition.d.ts +4 -0
  155. package/dist/config/yamlParsePosition.js +9 -0
  156. package/dist/hosted/containment.d.ts +3 -0
  157. package/dist/hosted/containment.js +36 -0
  158. package/dist/hosted/errors.d.ts +21 -0
  159. package/dist/hosted/errors.js +30 -0
  160. package/dist/hosted/packageSkills.d.ts +3 -0
  161. package/dist/hosted/packageSkills.js +80 -0
  162. package/dist/hosted/runtime.d.ts +12 -0
  163. package/dist/hosted/runtime.js +596 -0
  164. package/dist/hosted/sequencer.d.ts +28 -0
  165. package/dist/hosted/sequencer.js +129 -0
  166. package/dist/hosted/translate.d.ts +3 -0
  167. package/dist/hosted/translate.js +43 -0
  168. package/dist/hosted/types.d.ts +108 -0
  169. package/dist/hosted/types.js +10 -0
  170. package/dist/index.d.ts +9 -1
  171. package/dist/index.js +6 -0
  172. package/dist/mcp/getStartedTool.js +15 -6
  173. package/dist/mcp/triggerTools.js +2 -8
  174. package/dist/operatorAgent/agentPort.d.ts +11 -0
  175. package/dist/operatorAgent/agentPort.js +12 -0
  176. package/dist/operatorAgent/index.d.ts +1 -0
  177. package/dist/operatorAgent/index.js +1 -0
  178. package/dist/operatorAgent/piModel.js +26 -6
  179. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
  180. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +4 -2
  181. package/dist/operatorAgent/profiles/workshopAuthorTools.js +103 -16
  182. package/dist/package-meta.d.ts +1 -1
  183. package/dist/package-meta.js +1 -1
  184. package/dist/project/ensureProjectRootsFromEnv.d.ts +3 -0
  185. package/dist/project/ensureProjectRootsFromEnv.js +22 -0
  186. package/dist/project/globalHome.d.ts +1 -0
  187. package/dist/project/globalHome.js +18 -0
  188. package/dist/project/workspaceCatalog.d.ts +10 -0
  189. package/dist/project/workspaceCatalog.js +91 -0
  190. package/dist/projection/projectRun.d.ts +0 -1
  191. package/dist/projection/projectRun.js +0 -1
  192. package/dist/runstore/backup.js +14 -4
  193. package/dist/runstore/port.d.ts +11 -1
  194. package/dist/runstore/restore.js +5 -2
  195. package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -0
  196. package/dist/runstore/sqlite/SqliteRunStore.js +29 -9
  197. package/dist/runstore/sqlite/migrations/012-trigger-fires.d.ts +7 -0
  198. package/dist/runstore/sqlite/migrations/012-trigger-fires.js +18 -0
  199. package/dist/runstore/sqlite/migrations/index.js +2 -0
  200. package/dist/runstore/stageSnapshot.d.ts +3 -1
  201. package/dist/runstore/stageSnapshot.js +19 -0
  202. package/dist/runstore/workspaceLayout.js +27 -0
  203. package/dist/runstore/writeContainedArtifact.d.ts +1 -0
  204. package/dist/runstore/writeContainedArtifact.js +52 -0
  205. package/dist/runtime/containerLimits.d.ts +0 -3
  206. package/dist/runtime/containerLimits.js +0 -5
  207. package/dist/runtime/credentialBinding.d.ts +3 -0
  208. package/dist/runtime/credentialBinding.js +23 -6
  209. package/dist/runtime/emailSource.js +20 -28
  210. package/dist/runtime/githubPollSource.js +20 -28
  211. package/dist/runtime/pipelineRunner.d.ts +4 -4
  212. package/dist/runtime/pipelineScheduler.d.ts +2 -2
  213. package/dist/runtime/pipelineScheduler.js +3 -0
  214. package/dist/runtime/resumeReconstruct.d.ts +2 -2
  215. package/dist/runtime/resumeTimedOut.d.ts +2 -2
  216. package/dist/runtime/runManager.d.ts +18 -2
  217. package/dist/runtime/runManager.js +95 -30
  218. package/dist/runtime/runRetentionSweep.d.ts +0 -2
  219. package/dist/runtime/runRetentionSweep.js +0 -8
  220. package/dist/runtime/runRetryCoordinator.d.ts +2 -2
  221. package/dist/runtime/scheduleSource.js +15 -24
  222. package/dist/runtime/stageAttemptBootstrap.d.ts +2 -2
  223. package/dist/runtime/stageAttemptBootstrap.js +10 -1
  224. package/dist/runtime/stageProcessLauncher.js +2 -2
  225. package/dist/runtime/stageRoots.js +12 -1
  226. package/dist/runtime/stageRunner.d.ts +2 -2
  227. package/dist/runtime/stageRunner.js +8 -2
  228. package/dist/runtime/stageWorker.js +2 -2
  229. package/dist/runtime/triggerPort.d.ts +5 -3
  230. package/dist/runtime/triggerRunner.d.ts +1 -0
  231. package/dist/runtime/triggerRunner.js +27 -20
  232. package/dist/runtime/webhookAccept.d.ts +25 -0
  233. package/dist/runtime/webhookAccept.js +56 -0
  234. package/dist/server/bootstrap.d.ts +7 -2
  235. package/dist/server/bootstrap.js +15 -1
  236. package/dist/server/controlToken.d.ts +1 -1
  237. package/dist/server/controlToken.js +18 -2
  238. package/dist/server/healthSurfaces.d.ts +12 -0
  239. package/dist/server/healthSurfaces.js +27 -6
  240. package/dist/server/http.d.ts +19 -10
  241. package/dist/server/http.js +605 -85
  242. package/dist/server/liveViewPath.d.ts +9 -0
  243. package/dist/server/liveViewPath.js +8 -0
  244. package/dist/server/liveViewRoutes.d.ts +58 -0
  245. package/dist/server/liveViewRoutes.js +565 -0
  246. package/dist/server/mcpHost.d.ts +4 -2
  247. package/dist/server/mcpHost.js +2 -0
  248. package/dist/server/readCatalogFile.d.ts +29 -0
  249. package/dist/server/readCatalogFile.js +215 -0
  250. package/dist/server/triggerRoutes.d.ts +1 -0
  251. package/dist/server/triggerRoutes.js +200 -73
  252. package/dist/tools/readEmail.d.ts +3 -3
  253. package/dist/tools/writeStageArtifact.d.ts +9 -0
  254. package/dist/tools/writeStageArtifact.js +2 -47
  255. package/dist/types/pipeline.d.ts +1 -1
  256. package/dist/types/stage.d.ts +1 -1
  257. package/dist/types/stageflowManifest.d.ts +1 -1
  258. package/dist/ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  259. package/dist/ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  260. package/dist/ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  261. package/dist/ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  262. package/dist/ui/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  263. package/dist/ui/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  264. package/dist/ui/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  265. package/dist/ui/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  266. package/dist/ui/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  267. package/dist/ui/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  268. package/dist/ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  269. package/dist/ui/assets/index-BoFPkKFg.js +256 -0
  270. package/dist/ui/assets/{index-Bv4p1aPK.css → index-CIPbbBUi.css} +1 -1
  271. package/dist/ui/index.html +4 -4
  272. package/dist/workshop/autosave.d.ts +2 -2
  273. package/dist/workshop/autosave.js +4 -6
  274. package/dist/workshop/buildStore.d.ts +2 -0
  275. package/dist/workshop/chatAttachments.d.ts +27 -0
  276. package/dist/workshop/chatAttachments.js +98 -0
  277. package/dist/workshop/chatTurn.d.ts +5 -2
  278. package/dist/workshop/chatTurn.js +22 -18
  279. package/dist/workshop/sessionMutations.d.ts +17 -0
  280. package/dist/workshop/sessionMutations.js +107 -0
  281. package/dist/workshop/sessionStore.d.ts +10 -0
  282. package/dist/workshop/sessionStore.js +52 -0
  283. package/dist/workshop/workshopPin.d.ts +4 -3
  284. package/dist/workshop/workshopPin.js +26 -6
  285. package/dist/workshop/workshopTranscriptTurn.d.ts +8 -0
  286. package/dist/workshop/workshopTranscriptTurn.js +46 -0
  287. package/examples/README.md +1 -1
  288. package/examples/archify-on-pr/README.md +1 -1
  289. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +0 -1
  290. package/examples/archify-on-pr/author-diagrams.yaml +1 -0
  291. package/examples/conditional-fork/branch-a.yaml +1 -1
  292. package/examples/conditional-fork/decide.yaml +2 -1
  293. package/examples/feature-loop/{implement.yaml → feature-implement.yaml} +1 -1
  294. package/examples/feature-loop/feature-loop.pipeline.yaml +10 -10
  295. package/examples/feature-loop/{plan.yaml → feature-plan.yaml} +1 -1
  296. package/examples/feature-loop/{review.yaml → feature-review.yaml} +1 -1
  297. package/examples/feedback-loop/{implement.yaml → feedback-implement.yaml} +1 -1
  298. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +9 -9
  299. package/examples/feedback-loop/feedback-loop.pipeline.yaml +9 -9
  300. package/examples/feedback-loop/{plan.yaml → feedback-plan.yaml} +1 -1
  301. package/examples/feedback-loop/{review.yaml → feedback-review.yaml} +1 -1
  302. package/examples/generic-fan-in/{research.yaml → fan-in-research.yaml} +1 -1
  303. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +3 -3
  304. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +3 -3
  305. package/examples/hello-world/{research.yaml → hello-research.yaml} +1 -1
  306. package/examples/hello-world/hello.pipeline.yaml +2 -2
  307. package/examples/mcp-hitl-tour/{review.yaml → mcp-hitl-review.yaml} +1 -1
  308. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +3 -3
  309. package/examples/oss-issue-contribution/oss-explain-fix.yaml +1 -0
  310. package/examples/oss-issue-contribution/oss-explain-issue.yaml +1 -0
  311. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +0 -2
  312. package/examples/stageflow.yaml +6 -0
  313. package/examples/triggers/sample-github-pr.trigger.yaml +12 -0
  314. package/examples/triggers/sample-inbox-email.trigger.yaml +14 -0
  315. package/examples/triggers/sample-manual-hello.trigger.yaml +5 -0
  316. package/examples/triggers/sample-nightly-hello.trigger.yaml +8 -0
  317. package/examples/triggers/sample-signed-webhook.trigger.yaml +11 -0
  318. package/examples/triggers-readiness/README.md +48 -0
  319. package/examples/triggers-readiness/readiness-emit.yaml +18 -0
  320. package/examples/triggers-readiness/readiness.pipeline.yaml +4 -0
  321. package/examples/triggers-readiness/readiness.task.yaml +6 -0
  322. package/examples/triggers-readiness/stageflow.yaml +13 -0
  323. package/examples/triggers-readiness/triggers/readiness-dynamic-manual.trigger.yaml +4 -0
  324. package/examples/triggers-readiness/triggers/readiness-email.trigger.yaml +12 -0
  325. package/examples/triggers-readiness/triggers/readiness-github-pr.trigger.yaml +12 -0
  326. package/examples/triggers-readiness/triggers/readiness-manual.trigger.yaml +5 -0
  327. package/examples/triggers-readiness/triggers/readiness-schedule.trigger.yaml +8 -0
  328. package/examples/triggers-readiness/triggers/readiness-webhook.trigger.yaml +11 -0
  329. package/package.json +9 -1
  330. package/skills/stageflow/references/control-surface.md +1 -1
  331. package/skills/stageflow-author/references/catalog-write-conventions.md +2 -2
  332. package/skills/stageflow-run/SKILL.md +1 -1
  333. package/skills/stageflow-run/references/mcp-call.md +1 -1
  334. package/skills/stageflow-setup/SKILL.md +1 -1
  335. package/dist/ui/assets/index-59cjF0OA.js +0 -133
@@ -0,0 +1,29 @@
1
+ import { type ResolveCatalogRelativePathInput } from "../config/catalogRelativePath.js";
2
+ import { type ValidationFinding } from "../config/validateCatalog.js";
3
+ export declare const CATALOG_FILE_MAX_BYTES: number;
4
+ export type CatalogFileReadErrorCode = "unsupported_file_type" | "path_outside_project_root" | "catalog_file_not_found" | "catalog_file_too_large";
5
+ export type ReadCatalogFileResult = {
6
+ ok: true;
7
+ path: string;
8
+ content: string;
9
+ } | {
10
+ ok: false;
11
+ status: 400 | 404 | 413;
12
+ error: string;
13
+ code: CatalogFileReadErrorCode;
14
+ };
15
+ export type WriteCatalogFileResult = {
16
+ ok: true;
17
+ path: string;
18
+ content: string;
19
+ } | {
20
+ ok: false;
21
+ status: 400 | 404 | 413;
22
+ error: string;
23
+ code: CatalogFileReadErrorCode | "stage_invalid";
24
+ findings?: ValidationFinding[];
25
+ };
26
+ export declare function readCatalogFileForHttp(input: ResolveCatalogRelativePathInput): Promise<ReadCatalogFileResult>;
27
+ export declare function writeCatalogFileForHttp(input: ResolveCatalogRelativePathInput & {
28
+ content: string;
29
+ }): Promise<WriteCatalogFileResult>;
@@ -0,0 +1,215 @@
1
+ import { readFile, realpath, stat, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { CatalogPathError, isInsideProjectRoot, resolveCatalogRelativePath, } from "../config/catalogRelativePath.js";
4
+ import { loadStageOutcome } from "../config/loadStage.js";
5
+ import { findingsFromLoadIssues, } from "../config/validateCatalog.js";
6
+ export const CATALOG_FILE_MAX_BYTES = 512 * 1024;
7
+ function isCatalogYamlExtension(inputPath) {
8
+ const ext = path.extname(inputPath).toLowerCase();
9
+ return ext === ".yaml" || ext === ".yml";
10
+ }
11
+ export async function readCatalogFileForHttp(input) {
12
+ if (!isCatalogYamlExtension(input.inputPath)) {
13
+ return {
14
+ ok: false,
15
+ status: 400,
16
+ error: "Only .yaml and .yml catalog files can be read",
17
+ code: "unsupported_file_type",
18
+ };
19
+ }
20
+ let resolved;
21
+ try {
22
+ resolved = resolveCatalogRelativePath(input);
23
+ }
24
+ catch (err) {
25
+ if (err instanceof CatalogPathError) {
26
+ if (err.code === "path_outside_project_root") {
27
+ return {
28
+ ok: false,
29
+ status: 400,
30
+ error: err.message,
31
+ code: "path_outside_project_root",
32
+ };
33
+ }
34
+ throw err;
35
+ }
36
+ throw err;
37
+ }
38
+ let rootReal;
39
+ let fileReal;
40
+ try {
41
+ rootReal = await realpath(resolved.root.path);
42
+ fileReal = await realpath(resolved.absolutePath);
43
+ }
44
+ catch (err) {
45
+ const code = err.code;
46
+ if (code === "ENOENT") {
47
+ return {
48
+ ok: false,
49
+ status: 404,
50
+ error: "Catalog file not found",
51
+ code: "catalog_file_not_found",
52
+ };
53
+ }
54
+ throw err;
55
+ }
56
+ if (!isInsideProjectRoot(rootReal, fileReal)) {
57
+ return {
58
+ ok: false,
59
+ status: 400,
60
+ error: `path escapes project_root ${resolved.root.project_root}`,
61
+ code: "path_outside_project_root",
62
+ };
63
+ }
64
+ if (!isCatalogYamlExtension(fileReal)) {
65
+ return {
66
+ ok: false,
67
+ status: 400,
68
+ error: "Only .yaml and .yml catalog files can be read",
69
+ code: "unsupported_file_type",
70
+ };
71
+ }
72
+ let fileStat;
73
+ try {
74
+ fileStat = await stat(fileReal);
75
+ }
76
+ catch (err) {
77
+ const code = err.code;
78
+ if (code === "ENOENT") {
79
+ return {
80
+ ok: false,
81
+ status: 404,
82
+ error: "Catalog file not found",
83
+ code: "catalog_file_not_found",
84
+ };
85
+ }
86
+ throw err;
87
+ }
88
+ if (!fileStat.isFile()) {
89
+ return {
90
+ ok: false,
91
+ status: 400,
92
+ error: "Only .yaml and .yml catalog files can be read",
93
+ code: "unsupported_file_type",
94
+ };
95
+ }
96
+ if (fileStat.size > CATALOG_FILE_MAX_BYTES) {
97
+ return {
98
+ ok: false,
99
+ status: 413,
100
+ error: `Catalog file exceeds ${CATALOG_FILE_MAX_BYTES} byte limit`,
101
+ code: "catalog_file_too_large",
102
+ };
103
+ }
104
+ const content = await readFile(fileReal, "utf8");
105
+ return { ok: true, path: resolved.relativePath, content };
106
+ }
107
+ export async function writeCatalogFileForHttp(input) {
108
+ if (!isCatalogYamlExtension(input.inputPath)) {
109
+ return {
110
+ ok: false,
111
+ status: 400,
112
+ error: "Only .yaml and .yml catalog files can be written",
113
+ code: "unsupported_file_type",
114
+ };
115
+ }
116
+ if (Buffer.byteLength(input.content, "utf8") > CATALOG_FILE_MAX_BYTES) {
117
+ return {
118
+ ok: false,
119
+ status: 413,
120
+ error: `Catalog file exceeds ${CATALOG_FILE_MAX_BYTES} byte limit`,
121
+ code: "catalog_file_too_large",
122
+ };
123
+ }
124
+ let resolved;
125
+ try {
126
+ resolved = resolveCatalogRelativePath(input);
127
+ }
128
+ catch (err) {
129
+ if (err instanceof CatalogPathError) {
130
+ if (err.code === "path_outside_project_root") {
131
+ return {
132
+ ok: false,
133
+ status: 400,
134
+ error: err.message,
135
+ code: "path_outside_project_root",
136
+ };
137
+ }
138
+ throw err;
139
+ }
140
+ throw err;
141
+ }
142
+ let rootReal;
143
+ let fileReal;
144
+ try {
145
+ rootReal = await realpath(resolved.root.path);
146
+ fileReal = await realpath(resolved.absolutePath);
147
+ }
148
+ catch (err) {
149
+ const code = err.code;
150
+ if (code === "ENOENT") {
151
+ return {
152
+ ok: false,
153
+ status: 404,
154
+ error: "Catalog file not found",
155
+ code: "catalog_file_not_found",
156
+ };
157
+ }
158
+ throw err;
159
+ }
160
+ if (!isInsideProjectRoot(rootReal, fileReal)) {
161
+ return {
162
+ ok: false,
163
+ status: 400,
164
+ error: `path escapes project_root ${resolved.root.project_root}`,
165
+ code: "path_outside_project_root",
166
+ };
167
+ }
168
+ if (!isCatalogYamlExtension(fileReal)) {
169
+ return {
170
+ ok: false,
171
+ status: 400,
172
+ error: "Only .yaml and .yml catalog files can be written",
173
+ code: "unsupported_file_type",
174
+ };
175
+ }
176
+ let fileStat;
177
+ try {
178
+ fileStat = await stat(fileReal);
179
+ }
180
+ catch (err) {
181
+ const code = err.code;
182
+ if (code === "ENOENT") {
183
+ return {
184
+ ok: false,
185
+ status: 404,
186
+ error: "Catalog file not found",
187
+ code: "catalog_file_not_found",
188
+ };
189
+ }
190
+ throw err;
191
+ }
192
+ if (!fileStat.isFile()) {
193
+ return {
194
+ ok: false,
195
+ status: 400,
196
+ error: "Only .yaml and .yml catalog files can be written",
197
+ code: "unsupported_file_type",
198
+ };
199
+ }
200
+ const original = await readFile(fileReal, "utf8");
201
+ await writeFile(fileReal, input.content, "utf8");
202
+ const outcome = await loadStageOutcome(fileReal);
203
+ if (!outcome.ok) {
204
+ await writeFile(fileReal, original, "utf8");
205
+ const findings = findingsFromLoadIssues(resolved.root.path, fileReal, outcome.issues);
206
+ return {
207
+ ok: false,
208
+ status: 400,
209
+ error: findings[0]?.message ?? "Invalid stage YAML",
210
+ code: "stage_invalid",
211
+ findings,
212
+ };
213
+ }
214
+ return { ok: true, path: resolved.relativePath, content: input.content };
215
+ }
@@ -3,6 +3,7 @@ import type { Logger } from "../logging/logger.js";
3
3
  import type { RunManager } from "../runtime/runManager.js";
4
4
  import type { RunStore } from "../runstore/port.js";
5
5
  export type { TriggerListItem } from "../config/triggerCatalog.js";
6
+ export type { TriggerAdapterStatus } from "../config/triggerAdapterStatus.js";
6
7
  export type TriggerRoutesCtx = {
7
8
  cwd: string;
8
9
  manager: RunManager;
@@ -1,18 +1,40 @@
1
1
  import { fireTrigger } from "../runtime/triggerRunner.js";
2
- import { findTriggerDefinition } from "../runtime/triggerCatalog.js";
3
- import { matchesEventFilter } from "../runtime/triggerEventMatch.js";
4
- import { verifyHmacSignature } from "../runtime/webhookSignature.js";
2
+ import { acceptWebhook } from "../runtime/webhookAccept.js";
5
3
  import { mapStartFailure } from "./operatorResults.js";
6
4
  import { writeAudit } from "../logging/audit.js";
7
5
  import { callerIdFromRequestAuth, getRequestAuth, } from "./requestAuthContext.js";
8
- import { loadCatalogTriggers } from "../config/triggerCatalog.js";
6
+ import { findCatalogTrigger, loadCatalogTriggers, triggerStoreId, } from "../config/triggerCatalog.js";
9
7
  import { createTrigger, parseCreateTriggerBody } from "../config/createTrigger.js";
8
+ import { parsePatchTriggerBody, parsePutTriggerBody, updateTriggerDefinition, updateTriggerEnabled, projectRootFilterFromBody, } from "../config/updateTrigger.js";
9
+ import { readTriggerAdapterStatus, } from "../config/triggerAdapterStatus.js";
10
10
  import { CatalogPathError, catalogPathErrorBody, resolveWritableCatalogRoot, } from "../config/catalogRelativePath.js";
11
11
  import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
12
- import { catalogContextFromStageflow } from "../config/resolveCatalogContext.js";
13
- import { getCatalogScanPaths } from "../config/browseCatalog.js";
14
- import { readSecretFromEnvOrFile } from "../config/secretFromEnvOrFile.js";
15
12
  import { coerceTaskFile } from "../config/loadTask.js";
13
+ async function enrichTriggerListItem(item, store) {
14
+ const adapter_status = await readTriggerAdapterStatus(item, store);
15
+ return { ...item, adapter_status };
16
+ }
17
+ function resolveListedTrigger(items, id, projectRootWire) {
18
+ if (projectRootWire) {
19
+ const found = items.find((item) => item.id === id && item.project_root === projectRootWire);
20
+ if (!found) {
21
+ return { error: `Trigger not found: ${id}`, status: 404 };
22
+ }
23
+ return found;
24
+ }
25
+ const matches = items.filter((item) => item.id === id);
26
+ if (matches.length === 0) {
27
+ return { error: `Trigger not found: ${id}`, status: 404 };
28
+ }
29
+ if (matches.length > 1) {
30
+ return {
31
+ error: `Trigger id is ambiguous across catalog roots: ${id}`,
32
+ status: 409,
33
+ project_roots: [...new Set(matches.map((m) => m.project_root))].sort((a, b) => a.localeCompare(b)),
34
+ };
35
+ }
36
+ return matches[0];
37
+ }
16
38
  export async function handleTriggerRoutes(req, res, ctx) {
17
39
  const { cwd, manager, store, json, readJsonBody, readRawBody, auditLog } = ctx;
18
40
  const method = req.method ?? "GET";
@@ -78,12 +100,9 @@ export async function handleTriggerRoutes(req, res, ctx) {
78
100
  return true;
79
101
  }
80
102
  if (method === "GET" && pathname === "/api/triggers") {
81
- const items = await loadCatalogTriggers(cwd, store);
82
- if (items === undefined) {
83
- json(res, 404, { error: "No Stageflow catalog found" });
84
- return true;
85
- }
86
- json(res, 200, { triggers: items });
103
+ const items = await loadCatalogTriggers({ store, bootCwd: cwd });
104
+ const triggers = await Promise.all(items.map((item) => enrichTriggerListItem(item, store)));
105
+ json(res, 200, { triggers });
87
106
  return true;
88
107
  }
89
108
  const fireMatch = pathname.match(/^\/api\/triggers\/([^/]+)\/fire$/);
@@ -107,8 +126,14 @@ export async function handleTriggerRoutes(req, res, ctx) {
107
126
  }
108
127
  }
109
128
  const id = decodeURIComponent(fireMatch[1] ?? "");
129
+ const url = new URL(req.url ?? "/", "http://localhost");
130
+ const projectRootWire = url.searchParams.get("project_root") ?? undefined;
110
131
  const callerId = callerIdFromRequestAuth();
111
- const result = await fireTrigger(id, store, manager, { cwd, task });
132
+ const result = await fireTrigger(id, store, manager, {
133
+ cwd,
134
+ task,
135
+ ...(projectRootWire ? { project_root: projectRootWire } : {}),
136
+ });
112
137
  if (!result.ok) {
113
138
  writeAudit(auditLog, {
114
139
  caller_id: callerId,
@@ -145,41 +170,45 @@ export async function handleTriggerRoutes(req, res, ctx) {
145
170
  if (method === "POST" && webhookMatch) {
146
171
  const id = decodeURIComponent(webhookMatch[1] ?? "");
147
172
  const callerId = callerIdFromRequestAuth();
148
- const catalogCtx = catalogContextFromStageflow(await resolveStageflowContext(cwd));
149
- const scanPaths = await getCatalogScanPaths(catalogCtx);
150
- const found = scanPaths
151
- ? await findTriggerDefinition(scanPaths.triggerPaths, id)
152
- : undefined;
153
- if (!found) {
154
- json(res, 404, { error: `Trigger not found: ${id}` });
155
- return true;
156
- }
157
- const { definition: trigger } = found;
158
- const config = trigger.event?.config;
159
- const secretRef = typeof config?.secretRef === "string" ? config.secretRef : undefined;
160
- const header = typeof config?.header === "string" ? config.header : undefined;
161
- if (secretRef === undefined || header === undefined) {
162
- json(res, 400, { error: "this trigger has no webhook signing configured" });
173
+ const url = new URL(req.url ?? "/", "http://localhost");
174
+ const projectRootWire = url.searchParams.get("project_root") ?? undefined;
175
+ const located = await findCatalogTrigger({
176
+ store,
177
+ bootCwd: cwd,
178
+ triggerId: id,
179
+ ...(projectRootWire ? { projectRootFilter: projectRootWire } : {}),
180
+ });
181
+ if (!located.ok) {
182
+ if (located.status === 409 && located.code === "ambiguous_trigger") {
183
+ json(res, located.status, {
184
+ error: located.reason,
185
+ code: located.code,
186
+ project_roots: located.project_roots,
187
+ });
188
+ }
189
+ else if (located.status === 400 && located.code === "unknown_project_root") {
190
+ json(res, located.status, {
191
+ error: located.reason,
192
+ code: located.code,
193
+ });
194
+ }
195
+ else {
196
+ json(res, located.status, { error: located.reason });
197
+ }
163
198
  return true;
164
199
  }
165
- const scheme = config?.scheme === "base64" ? "base64" : "hex";
166
- let secret;
167
- try {
168
- secret = readSecretFromEnvOrFile(process.env, secretRef);
169
- }
170
- catch {
171
- secret = undefined;
172
- }
173
- if (secret === undefined) {
200
+ const rawBody = await readRawBody(req);
201
+ const accepted = acceptWebhook({
202
+ trigger: located.match.definition,
203
+ rawBody,
204
+ headers: req.headers,
205
+ env: process.env,
206
+ });
207
+ if (accepted.kind === "not_configured") {
174
208
  json(res, 400, { error: "this trigger has no webhook signing configured" });
175
209
  return true;
176
210
  }
177
- const rawBody = await readRawBody(req);
178
- const headerValue = req.headers[header.toLowerCase()];
179
- const signature = Array.isArray(headerValue) ? headerValue[0] : headerValue;
180
- if (typeof signature !== "string" ||
181
- signature.length === 0 ||
182
- !verifyHmacSignature(rawBody, signature, secret, scheme)) {
211
+ if (accepted.kind === "bad_signature") {
183
212
  writeAudit(auditLog, {
184
213
  caller_id: callerId,
185
214
  surface: "webhook",
@@ -190,31 +219,19 @@ export async function handleTriggerRoutes(req, res, ctx) {
190
219
  json(res, 401, { error: "Invalid webhook signature" });
191
220
  return true;
192
221
  }
193
- let payload;
194
- try {
195
- payload = rawBody.length === 0 ? {} : JSON.parse(rawBody.toString("utf8"));
196
- }
197
- catch {
198
- json(res, 400, { error: "Invalid JSON body" });
222
+ if (accepted.kind === "bad_json") {
223
+ json(res, 400, { error: accepted.error });
199
224
  return true;
200
225
  }
201
- if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
202
- json(res, 400, { error: "Invalid JSON body: expected an object" });
203
- return true;
204
- }
205
- const payloadRecord = payload;
206
- if (!matchesEventFilter(trigger.event?.match, payloadRecord)) {
226
+ if (accepted.kind === "no_match") {
207
227
  json(res, 200, { fired: false });
208
228
  return true;
209
229
  }
210
- const task = trigger.task === undefined
211
- ? {
212
- id: `${id}-webhook-${Date.now()}`,
213
- goal: `Handle webhook event for trigger "${id}"`,
214
- input: payloadRecord,
215
- }
216
- : undefined;
217
- const result = await fireTrigger(id, store, manager, { cwd, task });
230
+ const result = await fireTrigger(id, store, manager, {
231
+ cwd,
232
+ task: accepted.task,
233
+ project_root: located.match.project_root,
234
+ });
218
235
  if (!result.ok) {
219
236
  writeAudit(auditLog, {
220
237
  caller_id: callerId,
@@ -248,20 +265,130 @@ export async function handleTriggerRoutes(req, res, ctx) {
248
265
  });
249
266
  return true;
250
267
  }
268
+ const statusMatch = pathname.match(/^\/api\/triggers\/([^/]+)\/status$/);
269
+ if (method === "GET" && statusMatch) {
270
+ const id = decodeURIComponent(statusMatch[1] ?? "");
271
+ const url = new URL(req.url ?? "/", "http://localhost");
272
+ const projectRootWire = url.searchParams.get("project_root") ?? undefined;
273
+ const items = await loadCatalogTriggers({ store, bootCwd: cwd });
274
+ const found = resolveListedTrigger(items, id, projectRootWire);
275
+ if ("error" in found) {
276
+ json(res, found.status, { error: found.error, ...(found.project_roots ? { project_roots: found.project_roots } : {}) });
277
+ return true;
278
+ }
279
+ const adapter_status = await readTriggerAdapterStatus(found, store);
280
+ json(res, 200, adapter_status);
281
+ return true;
282
+ }
283
+ const firesMatch = pathname.match(/^\/api\/triggers\/([^/]+)\/fires$/);
284
+ if (method === "GET" && firesMatch) {
285
+ const id = decodeURIComponent(firesMatch[1] ?? "");
286
+ const url = new URL(req.url ?? "/", "http://localhost");
287
+ const projectRootWire = url.searchParams.get("project_root") ?? undefined;
288
+ const items = await loadCatalogTriggers({ store, bootCwd: cwd });
289
+ const found = resolveListedTrigger(items, id, projectRootWire);
290
+ if ("error" in found) {
291
+ json(res, found.status, { error: found.error, ...(found.project_roots ? { project_roots: found.project_roots } : {}) });
292
+ return true;
293
+ }
294
+ const fires = await store.listTriggerFires(triggerStoreId(found.project_root, found.id), 20);
295
+ json(res, 200, { fires });
296
+ return true;
297
+ }
298
+ const putMatch = pathname.match(/^\/api\/triggers\/([^/]+)$/);
299
+ if (method === "PUT" && putMatch) {
300
+ let body;
301
+ try {
302
+ body = await readJsonBody(req);
303
+ }
304
+ catch {
305
+ json(res, 400, { error: "Invalid JSON body" });
306
+ return true;
307
+ }
308
+ const id = decodeURIComponent(putMatch[1] ?? "");
309
+ const parsed = parsePutTriggerBody(body, id);
310
+ if ("ok" in parsed) {
311
+ json(res, parsed.status, { error: parsed.error });
312
+ return true;
313
+ }
314
+ const projectRootFilter = projectRootFilterFromBody(body);
315
+ const callerId = callerIdFromRequestAuth();
316
+ const result = await updateTriggerDefinition(cwd, store, id, parsed, {
317
+ projectRootFilter,
318
+ });
319
+ if (!result.ok) {
320
+ writeAudit(auditLog, {
321
+ caller_id: callerId,
322
+ surface: getRequestAuth()?.surface ?? "rest",
323
+ action: "trigger_update",
324
+ outcome: "error",
325
+ });
326
+ json(res, result.status, { error: result.error });
327
+ return true;
328
+ }
329
+ writeAudit(auditLog, {
330
+ caller_id: callerId,
331
+ surface: getRequestAuth()?.surface ?? "rest",
332
+ action: "trigger_update",
333
+ outcome: "ok",
334
+ });
335
+ const enriched = await enrichTriggerListItem(result.trigger, store);
336
+ json(res, 200, enriched);
337
+ return true;
338
+ }
339
+ const patchMatch = pathname.match(/^\/api\/triggers\/([^/]+)$/);
340
+ if (method === "PATCH" && patchMatch) {
341
+ let body;
342
+ try {
343
+ body = await readJsonBody(req);
344
+ }
345
+ catch {
346
+ json(res, 400, { error: "Invalid JSON body" });
347
+ return true;
348
+ }
349
+ const parsed = parsePatchTriggerBody(body);
350
+ if ("ok" in parsed) {
351
+ json(res, parsed.status, { error: parsed.error });
352
+ return true;
353
+ }
354
+ const id = decodeURIComponent(patchMatch[1] ?? "");
355
+ const projectRootFilter = projectRootFilterFromBody(body);
356
+ const callerId = callerIdFromRequestAuth();
357
+ const result = await updateTriggerEnabled(cwd, store, id, parsed.enabled, {
358
+ projectRootFilter,
359
+ });
360
+ if (!result.ok) {
361
+ writeAudit(auditLog, {
362
+ caller_id: callerId,
363
+ surface: getRequestAuth()?.surface ?? "rest",
364
+ action: "trigger_patch",
365
+ outcome: "error",
366
+ });
367
+ json(res, result.status, { error: result.error });
368
+ return true;
369
+ }
370
+ writeAudit(auditLog, {
371
+ caller_id: callerId,
372
+ surface: getRequestAuth()?.surface ?? "rest",
373
+ action: "trigger_patch",
374
+ outcome: "ok",
375
+ });
376
+ const enriched = await enrichTriggerListItem(result.trigger, store);
377
+ json(res, 200, enriched);
378
+ return true;
379
+ }
251
380
  const idMatch = pathname.match(/^\/api\/triggers\/([^/]+)$/);
252
381
  if (method === "GET" && idMatch) {
253
382
  const id = decodeURIComponent(idMatch[1] ?? "");
254
- const items = await loadCatalogTriggers(cwd, store);
255
- if (items === undefined) {
256
- json(res, 404, { error: "No Stageflow catalog found" });
257
- return true;
258
- }
259
- const found = items.find((item) => item.id === id);
260
- if (!found) {
261
- json(res, 404, { error: `Trigger not found: ${id}` });
383
+ const url = new URL(req.url ?? "/", "http://localhost");
384
+ const projectRootWire = url.searchParams.get("project_root") ?? undefined;
385
+ const items = await loadCatalogTriggers({ store, bootCwd: cwd });
386
+ const found = resolveListedTrigger(items, id, projectRootWire);
387
+ if ("error" in found) {
388
+ json(res, found.status, { error: found.error, ...(found.project_roots ? { project_roots: found.project_roots } : {}) });
262
389
  return true;
263
390
  }
264
- json(res, 200, found);
391
+ json(res, 200, await enrichTriggerListItem(found, store));
265
392
  return true;
266
393
  }
267
394
  return false;
@@ -6,12 +6,12 @@ export declare function createSearchEmailTool(email: StageEmail): {
6
6
  description: string;
7
7
  parameters: Type.TObject<Type.TProperties>;
8
8
  execute(_toolCallId: string, input: unknown): Promise<{
9
+ isError?: undefined;
9
10
  content: {
10
11
  type: "text";
11
12
  text: string;
12
13
  }[];
13
14
  details: unknown;
14
- isError?: undefined;
15
15
  } | {
16
16
  content: {
17
17
  type: "text";
@@ -31,12 +31,12 @@ export declare function createGetEmailTool(email: StageEmail): {
31
31
  description: string;
32
32
  parameters: Type.TObject<Type.TProperties>;
33
33
  execute(_toolCallId: string, input: unknown): Promise<{
34
+ isError?: undefined;
34
35
  content: {
35
36
  type: "text";
36
37
  text: string;
37
38
  }[];
38
39
  details: unknown;
39
- isError?: undefined;
40
40
  } | {
41
41
  content: {
42
42
  type: "text";
@@ -56,12 +56,12 @@ export declare function createDownloadEmailAttachmentTool(email: StageEmail): {
56
56
  description: string;
57
57
  parameters: Type.TObject<Type.TProperties>;
58
58
  execute(_toolCallId: string, input: unknown): Promise<{
59
+ isError?: undefined;
59
60
  content: {
60
61
  type: "text";
61
62
  text: string;
62
63
  }[];
63
64
  details: unknown;
64
- isError?: undefined;
65
65
  } | {
66
66
  content: {
67
67
  type: "text";
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Custom Pi tool for writing factory stage artifact files under the run
3
+ * workspace. Paths are relative to
4
+ * `stages/<stageId>/attempts/<attempt>/artifacts/` and must resolve inside
5
+ * that directory.
6
+ *
7
+ * Parameter schemas use `typebox` (Pi's `defineTool` TSchema), not
8
+ * `@sinclair/typebox`. Unlike emit, this tool does not terminate the turn.
9
+ */
1
10
  import { Type } from "typebox";
2
11
  export type WriteStageArtifactOptions = {
3
12
  runWorkspaceDir: string;