stageflow 0.23.0 → 0.27.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 (511) hide show
  1. package/README.md +24 -5
  2. package/dist/a2a/configDiscovery.d.ts +9 -0
  3. package/dist/a2a/configDiscovery.js +18 -0
  4. package/dist/a2a/contracts.d.ts +94 -0
  5. package/dist/a2a/contracts.js +164 -0
  6. package/dist/a2a/limits.d.ts +14 -0
  7. package/dist/a2a/limits.js +29 -0
  8. package/dist/a2a/registry.d.ts +46 -0
  9. package/dist/a2a/registry.js +178 -0
  10. package/dist/a2a/server.d.ts +36 -0
  11. package/dist/a2a/server.js +344 -0
  12. package/dist/a2a/service.d.ts +97 -0
  13. package/dist/a2a/service.js +545 -0
  14. package/dist/a2a/store.d.ts +109 -0
  15. package/dist/a2a/store.js +202 -0
  16. package/dist/agent/activity.d.ts +3 -0
  17. package/dist/agent/bootProviderConfig.d.ts +21 -0
  18. package/dist/agent/bootProviderConfig.js +74 -0
  19. package/dist/agent/piAdapter.d.ts +9 -1
  20. package/dist/agent/piAdapter.js +58 -3
  21. package/dist/agent/piIsolatedMcp.d.ts +2 -0
  22. package/dist/agent/piIsolatedMcp.js +10 -2
  23. package/dist/agent/port.d.ts +6 -0
  24. package/dist/agent/streamLogRedact.d.ts +1 -1
  25. package/dist/agent/streamLogRedact.js +4 -11
  26. package/dist/cli/a2aCommand.d.ts +8 -0
  27. package/dist/cli/a2aCommand.js +131 -0
  28. package/dist/cli/artifactCommand.js +9 -16
  29. package/dist/cli/backupCommand.d.ts +9 -0
  30. package/dist/cli/backupCommand.js +111 -0
  31. package/dist/cli/debugRunCommand.d.ts +10 -0
  32. package/dist/cli/debugRunCommand.js +109 -0
  33. package/dist/cli/doctorCommand.d.ts +32 -0
  34. package/dist/cli/doctorCommand.js +453 -0
  35. package/dist/cli/envelopeCommand.js +9 -2
  36. package/dist/cli/exportAllCommand.d.ts +55 -0
  37. package/dist/cli/exportAllCommand.js +218 -0
  38. package/dist/cli/exportRunCommand.js +23 -21
  39. package/dist/cli/hostClient.d.ts +21 -3
  40. package/dist/cli/hostClient.js +93 -12
  41. package/dist/cli/initTemplates.d.ts +1 -1
  42. package/dist/cli/initTemplates.js +8 -1
  43. package/dist/cli/resolveSafeOutPath.d.ts +2 -0
  44. package/dist/cli/resolveSafeOutPath.js +40 -0
  45. package/dist/cli/restoreCommand.d.ts +10 -0
  46. package/dist/cli/restoreCommand.js +90 -0
  47. package/dist/cli/runCommand.d.ts +3 -2
  48. package/dist/cli/runCommand.js +93 -11
  49. package/dist/cli/runOutput.d.ts +4 -0
  50. package/dist/cli/runOutput.js +33 -7
  51. package/dist/cli/runStageCommand.d.ts +34 -0
  52. package/dist/cli/runStageCommand.js +426 -0
  53. package/dist/cli/runsCommand.d.ts +1 -1
  54. package/dist/cli/runsCommand.js +162 -8
  55. package/dist/cli.js +190 -30
  56. package/dist/config/catalogRelativePath.d.ts +62 -0
  57. package/dist/config/catalogRelativePath.js +118 -0
  58. package/dist/config/configOrigin.d.ts +27 -0
  59. package/dist/config/configOrigin.js +59 -0
  60. package/dist/config/hostConfig.d.ts +55 -0
  61. package/dist/config/hostConfig.js +333 -0
  62. package/dist/config/listSkills.d.ts +26 -0
  63. package/dist/config/listSkills.js +190 -3
  64. package/dist/config/loadOutcome.d.ts +1 -1
  65. package/dist/config/loadPipeline.js +23 -2
  66. package/dist/config/loadStage.js +18 -0
  67. package/dist/config/loadTask.d.ts +2 -0
  68. package/dist/config/loadTask.js +57 -18
  69. package/dist/config/materializeStageModels.js +5 -1
  70. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  71. package/dist/config/mergePipelineIncludes.js +19 -0
  72. package/dist/config/migrateYaml.js +6 -11
  73. package/dist/config/multiProjectCatalog.d.ts +30 -0
  74. package/dist/config/multiProjectCatalog.js +142 -0
  75. package/dist/config/normalizePipelineStageEntry.js +20 -1
  76. package/dist/config/pipelineStageKeys.js +2 -0
  77. package/dist/config/resolveCatalogRoots.d.ts +27 -0
  78. package/dist/config/resolveCatalogRoots.js +76 -0
  79. package/dist/config/resolveModel.d.ts +7 -1
  80. package/dist/config/resolveModel.js +11 -1
  81. package/dist/config/resolveStageMcpServers.d.ts +9 -1
  82. package/dist/config/resolveStageMcpServers.js +36 -9
  83. package/dist/config/secretFromEnvOrFile.d.ts +9 -0
  84. package/dist/config/secretFromEnvOrFile.js +34 -0
  85. package/dist/config/seededCatalog.d.ts +11 -0
  86. package/dist/config/seededCatalog.js +29 -0
  87. package/dist/config/toolRequires.d.ts +24 -0
  88. package/dist/config/toolRequires.js +115 -0
  89. package/dist/config/validateCatalog.d.ts +5 -1
  90. package/dist/config/validateCatalog.js +140 -1
  91. package/dist/diagnostics/checks.d.ts +39 -0
  92. package/dist/diagnostics/checks.js +135 -0
  93. package/dist/errors/codes.d.ts +14 -0
  94. package/dist/errors/codes.js +59 -0
  95. package/dist/git/cache.d.ts +14 -0
  96. package/dist/git/cache.js +150 -0
  97. package/dist/git/credentials.d.ts +9 -0
  98. package/dist/git/credentials.js +88 -0
  99. package/dist/git/errors.d.ts +20 -0
  100. package/dist/git/errors.js +94 -0
  101. package/dist/git/exec.d.ts +16 -0
  102. package/dist/git/exec.js +135 -0
  103. package/dist/git/operations.d.ts +29 -0
  104. package/dist/git/operations.js +153 -0
  105. package/dist/git/version.d.ts +1 -0
  106. package/dist/git/version.js +10 -0
  107. package/dist/logging/audit.d.ts +16 -0
  108. package/dist/logging/audit.js +19 -0
  109. package/dist/logging/commonWords.d.ts +2 -0
  110. package/dist/logging/commonWords.js +13 -0
  111. package/dist/logging/logger.d.ts +49 -0
  112. package/dist/logging/logger.js +193 -0
  113. package/dist/logging/namedSecrets.d.ts +6 -0
  114. package/dist/logging/namedSecrets.js +58 -0
  115. package/dist/logging/redact.d.ts +13 -0
  116. package/dist/logging/redact.js +88 -0
  117. package/dist/mcp/catalogTools.js +591 -76
  118. package/dist/mcp/checkoutTools.d.ts +52 -0
  119. package/dist/mcp/checkoutTools.js +332 -0
  120. package/dist/mcp/controlTools.js +179 -5
  121. package/dist/mcp/deps.d.ts +1 -0
  122. package/dist/mcp/getStartedTool.d.ts +3 -0
  123. package/dist/mcp/getStartedTool.js +62 -0
  124. package/dist/mcp/readArtifact.d.ts +11 -0
  125. package/dist/mcp/readArtifact.js +46 -30
  126. package/dist/mcp/server.js +1 -0
  127. package/dist/mcp/tools.js +4 -0
  128. package/dist/net/proxy.d.ts +14 -0
  129. package/dist/net/proxy.js +78 -0
  130. package/dist/package-meta.d.ts +2 -1
  131. package/dist/package-meta.js +2 -1
  132. package/dist/preflight/bash.d.ts +8 -0
  133. package/dist/preflight/bash.js +34 -0
  134. package/dist/preflight/claudeRoot.d.ts +11 -0
  135. package/dist/preflight/claudeRoot.js +23 -0
  136. package/dist/preflight/mcpCommands.d.ts +8 -0
  137. package/dist/preflight/mcpCommands.js +36 -0
  138. package/dist/preflight/pipelinePreflight.d.ts +40 -0
  139. package/dist/preflight/pipelinePreflight.js +192 -0
  140. package/dist/preflight/tls.d.ts +6 -0
  141. package/dist/preflight/tls.js +18 -0
  142. package/dist/preflight/toolchain.d.ts +45 -0
  143. package/dist/preflight/toolchain.js +219 -0
  144. package/dist/project/findProjectRoot.js +3 -4
  145. package/dist/project/globalHome.d.ts +7 -0
  146. package/dist/project/globalHome.js +63 -2
  147. package/dist/project/resolveProjectContext.js +2 -2
  148. package/dist/project/resolveStageflowContext.js +2 -2
  149. package/dist/projection/projectRun.d.ts +2 -1
  150. package/dist/projection/projectRun.js +1 -0
  151. package/dist/runstore/assertTmpdir.d.ts +1 -0
  152. package/dist/runstore/assertTmpdir.js +21 -0
  153. package/dist/runstore/backup.d.ts +52 -0
  154. package/dist/runstore/backup.js +292 -0
  155. package/dist/runstore/createStore.d.ts +27 -0
  156. package/dist/runstore/createStore.js +75 -7
  157. package/dist/runstore/debugBundle.d.ts +60 -0
  158. package/dist/runstore/debugBundle.js +143 -0
  159. package/dist/runstore/diskUsage.d.ts +50 -0
  160. package/dist/runstore/diskUsage.js +214 -0
  161. package/dist/runstore/exportRunPayload.d.ts +8 -0
  162. package/dist/runstore/exportRunPayload.js +23 -0
  163. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  164. package/dist/runstore/normalizeCatalogPath.js +10 -0
  165. package/dist/runstore/paths.d.ts +5 -0
  166. package/dist/runstore/paths.js +145 -1
  167. package/dist/runstore/port.d.ts +119 -8
  168. package/dist/runstore/port.js +8 -1
  169. package/dist/runstore/restore.d.ts +81 -0
  170. package/dist/runstore/restore.js +355 -0
  171. package/dist/runstore/retention.d.ts +27 -0
  172. package/dist/runstore/retention.js +74 -0
  173. package/dist/runstore/runManifest.d.ts +146 -0
  174. package/dist/runstore/runManifest.js +288 -0
  175. package/dist/runstore/runProjection.d.ts +3 -1
  176. package/dist/runstore/runProjection.js +63 -1
  177. package/dist/runstore/sqlite/SqliteRunStore.d.ts +37 -3
  178. package/dist/runstore/sqlite/SqliteRunStore.js +401 -227
  179. package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
  180. package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
  181. package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
  182. package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
  183. package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
  184. package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
  185. package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
  186. package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
  187. package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
  188. package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
  189. package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
  190. package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
  191. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
  192. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
  193. package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
  194. package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
  195. package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
  196. package/dist/runstore/sqlite/migrations/index.js +72 -0
  197. package/dist/runstore/sqlite/schema.d.ts +20 -1
  198. package/dist/runstore/sqlite/schema.js +283 -1
  199. package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
  200. package/dist/runstore/sqlite/storeOpenError.js +11 -0
  201. package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
  202. package/dist/runstore/sqlite/storeSchemaError.js +8 -0
  203. package/dist/runstore/stageExecution.js +3 -0
  204. package/dist/runstore/storeFilesystem.d.ts +32 -0
  205. package/dist/runstore/storeFilesystem.js +148 -0
  206. package/dist/runstore/submission.d.ts +11 -0
  207. package/dist/runstore/submission.js +7 -0
  208. package/dist/runstore/trackProjection.js +2 -0
  209. package/dist/runstore/workspaceLayout.d.ts +13 -0
  210. package/dist/runstore/workspaceLayout.js +76 -0
  211. package/dist/runtime/completionCheckRunner.d.ts +3 -0
  212. package/dist/runtime/completionCheckRunner.js +45 -7
  213. package/dist/runtime/containerLimits.d.ts +16 -0
  214. package/dist/runtime/containerLimits.js +84 -0
  215. package/dist/runtime/credentialMaterialisation.d.ts +28 -0
  216. package/dist/runtime/credentialMaterialisation.js +128 -0
  217. package/dist/runtime/gitCheckoutCapability.js +7 -13
  218. package/dist/runtime/pipelineRunner.d.ts +38 -1
  219. package/dist/runtime/pipelineRunner.js +179 -15
  220. package/dist/runtime/pipelineScheduler.d.ts +15 -0
  221. package/dist/runtime/pipelineScheduler.js +167 -42
  222. package/dist/runtime/reloadRunCatalog.js +12 -1
  223. package/dist/runtime/repositoryMaterialize.d.ts +47 -0
  224. package/dist/runtime/repositoryMaterialize.js +235 -0
  225. package/dist/runtime/resolveEnvelopeRef.d.ts +30 -0
  226. package/dist/runtime/resolveEnvelopeRef.js +79 -0
  227. package/dist/runtime/resumeTimedOut.d.ts +1 -1
  228. package/dist/runtime/resumeTimedOut.js +5 -2
  229. package/dist/runtime/runChangeBus.js +9 -0
  230. package/dist/runtime/runDeletion.d.ts +7 -0
  231. package/dist/runtime/runDeletion.js +37 -0
  232. package/dist/runtime/runManager.d.ts +179 -4
  233. package/dist/runtime/runManager.js +1644 -83
  234. package/dist/runtime/runRetentionSweep.d.ts +31 -0
  235. package/dist/runtime/runRetentionSweep.js +328 -0
  236. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  237. package/dist/runtime/runRetryCoordinator.js +19 -2
  238. package/dist/runtime/runSkills.d.ts +40 -0
  239. package/dist/runtime/runSkills.js +173 -0
  240. package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
  241. package/dist/runtime/stageAttemptBootstrap.js +195 -24
  242. package/dist/runtime/stageCacheEnv.d.ts +6 -0
  243. package/dist/runtime/stageCacheEnv.js +34 -0
  244. package/dist/runtime/stageConcurrency.d.ts +2 -1
  245. package/dist/runtime/stageConcurrency.js +4 -2
  246. package/dist/runtime/stageEnvironment.d.ts +38 -0
  247. package/dist/runtime/stageEnvironment.js +193 -0
  248. package/dist/runtime/stageProcessLauncher.d.ts +18 -0
  249. package/dist/runtime/stageProcessLauncher.js +194 -38
  250. package/dist/runtime/stageRecovery.d.ts +3 -1
  251. package/dist/runtime/stageRecovery.js +19 -4
  252. package/dist/runtime/stageRoots.d.ts +38 -1
  253. package/dist/runtime/stageRoots.js +118 -0
  254. package/dist/runtime/stageRunner.d.ts +1 -0
  255. package/dist/runtime/stageRunner.js +3 -1
  256. package/dist/runtime/stageSecretDecl.d.ts +9 -0
  257. package/dist/runtime/stageSecretDecl.js +102 -0
  258. package/dist/runtime/stageSecrets.d.ts +40 -0
  259. package/dist/runtime/stageSecrets.js +181 -0
  260. package/dist/runtime/stageWorker.d.ts +3 -2
  261. package/dist/runtime/stageWorker.js +58 -10
  262. package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
  263. package/dist/runtime/stageWorkerProtocol.js +8 -0
  264. package/dist/runtime/startPayload.d.ts +32 -0
  265. package/dist/runtime/startPayload.js +59 -0
  266. package/dist/runtime/taskInput.js +14 -5
  267. package/dist/runtime/verifiedStageExecution.d.ts +1 -0
  268. package/dist/runtime/verifiedStageExecution.js +2 -1
  269. package/dist/runtime/workspaceBinding.d.ts +20 -0
  270. package/dist/runtime/workspaceBinding.js +60 -0
  271. package/dist/server/allowedHosts.d.ts +19 -0
  272. package/dist/server/allowedHosts.js +179 -0
  273. package/dist/server/bootstrap.d.ts +38 -2
  274. package/dist/server/bootstrap.js +219 -4
  275. package/dist/server/controlToken.d.ts +47 -0
  276. package/dist/server/controlToken.js +241 -0
  277. package/dist/server/createHttpHost.d.ts +11 -2
  278. package/dist/server/createHttpHost.js +109 -10
  279. package/dist/server/ensureGlobalService.d.ts +5 -1
  280. package/dist/server/ensureGlobalService.js +35 -1
  281. package/dist/server/healthSurfaces.d.ts +6 -0
  282. package/dist/server/healthSurfaces.js +98 -0
  283. package/dist/server/http.d.ts +12 -1
  284. package/dist/server/http.js +1085 -485
  285. package/dist/server/listenHost.d.ts +5 -0
  286. package/dist/server/listenHost.js +56 -0
  287. package/dist/server/mcpHost.d.ts +10 -1
  288. package/dist/server/mcpHost.js +36 -6
  289. package/dist/server/operatorResults.d.ts +2 -2
  290. package/dist/server/operatorResults.js +40 -29
  291. package/dist/server/requestAuthContext.d.ts +12 -0
  292. package/dist/server/requestAuthContext.js +21 -0
  293. package/dist/server/shutdown.d.ts +69 -0
  294. package/dist/server/shutdown.js +219 -0
  295. package/dist/types/pipeline.d.ts +7 -0
  296. package/dist/types/stage.d.ts +8 -0
  297. package/dist/types/task.d.ts +8 -0
  298. package/dist/ui/assets/index-B6hlSXXn.js +120 -0
  299. package/dist/ui/index.html +1 -1
  300. package/examples/README.md +98 -0
  301. package/examples/archify-on-pr/README.md +213 -0
  302. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
  303. package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
  304. package/examples/archify-on-pr/author-diagrams.yaml +106 -0
  305. package/examples/archify-on-pr/detect-changes.yaml +89 -0
  306. package/examples/ci-validate/README.md +35 -0
  307. package/examples/ci-validate/check.yaml +13 -0
  308. package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
  309. package/examples/ci-validate/validate.sh +5 -0
  310. package/examples/compliance-review-demo/README.md +125 -0
  311. package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
  312. package/examples/compliance-review-demo/connect-account.yaml +47 -0
  313. package/examples/compliance-review-demo/map-to-control.yaml +123 -0
  314. package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
  315. package/examples/compliance-review-demo/publish-report.yaml +79 -0
  316. package/examples/compliance-review-demo/review-verdict.yaml +122 -0
  317. package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
  318. package/examples/compliance-review-demo/store-evidence.yaml +143 -0
  319. package/examples/conditional-fork/README.md +89 -0
  320. package/examples/conditional-fork/branch-a.yaml +13 -0
  321. package/examples/conditional-fork/branch-b.yaml +13 -0
  322. package/examples/conditional-fork/decide.yaml +35 -0
  323. package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
  324. package/examples/conditional-fork/fork-demo.task.yaml +8 -0
  325. package/examples/context7-mcp/README.md +42 -0
  326. package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
  327. package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
  328. package/examples/context7-mcp/fetch-docs.yaml +52 -0
  329. package/examples/context7-mcp/resolve-library.yaml +31 -0
  330. package/examples/context7-mcp/write-brief.yaml +52 -0
  331. package/examples/feature-loop/README.md +104 -0
  332. package/examples/feature-loop/address-feedback.yaml +148 -0
  333. package/examples/feature-loop/align.yaml +116 -0
  334. package/examples/feature-loop/decompose.yaml +86 -0
  335. package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
  336. package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
  337. package/examples/feature-loop/feature-loop.task.yaml +25 -0
  338. package/examples/feature-loop/implement.yaml +128 -0
  339. package/examples/feature-loop/plan.yaml +111 -0
  340. package/examples/feature-loop/publish.yaml +167 -0
  341. package/examples/feature-loop/review.yaml +146 -0
  342. package/examples/feature-loop/verify.yaml +106 -0
  343. package/examples/feedback-loop/README.md +72 -0
  344. package/examples/feedback-loop/VERIFY.md +208 -0
  345. package/examples/feedback-loop/continue-only.task.yaml +4 -0
  346. package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
  347. package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
  348. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
  349. package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
  350. package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
  351. package/examples/feedback-loop/implement.yaml +14 -0
  352. package/examples/feedback-loop/plan.yaml +14 -0
  353. package/examples/feedback-loop/review.yaml +15 -0
  354. package/examples/feedback-loop/send-back-once.task.yaml +6 -0
  355. package/examples/feedback-loop/submit.yaml +12 -0
  356. package/examples/generic-fan-in/README.md +151 -0
  357. package/examples/generic-fan-in/clarify.yaml +18 -0
  358. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
  359. package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
  360. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
  361. package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
  362. package/examples/generic-fan-in/research.yaml +45 -0
  363. package/examples/generic-fan-in/synthesize.yaml +66 -0
  364. package/examples/generic-fan-in/validation.yaml +45 -0
  365. package/examples/github-release/README.md +78 -0
  366. package/examples/github-release/draft-release-notes.yaml +64 -0
  367. package/examples/github-release/github-release.pipeline.yaml +11 -0
  368. package/examples/github-release/github-release.task.yaml +13 -0
  369. package/examples/github-release/publish-github-release.yaml +64 -0
  370. package/examples/hello-world/README.md +28 -0
  371. package/examples/hello-world/hello.pipeline.yaml +4 -0
  372. package/examples/hello-world/my-task.task.yaml +6 -0
  373. package/examples/hello-world/research.yaml +18 -0
  374. package/examples/mcp-hitl-tour/README.md +113 -0
  375. package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
  376. package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
  377. package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
  378. package/examples/mcp-hitl-tour/gather.yaml +31 -0
  379. package/examples/mcp-hitl-tour/intake.yaml +62 -0
  380. package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
  381. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
  382. package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
  383. package/examples/mcp-hitl-tour/polish.yaml +33 -0
  384. package/examples/mcp-hitl-tour/review.yaml +17 -0
  385. package/examples/mcp-hitl-tour/ship.yaml +25 -0
  386. package/examples/oss-issue-contribution/README.md +218 -0
  387. package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
  388. package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
  389. package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
  390. package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
  391. package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
  392. package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
  393. package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
  394. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
  395. package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
  396. package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
  397. package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
  398. package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
  399. package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
  400. package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
  401. package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
  402. package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
  403. package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
  404. package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
  405. package/examples/oss-quick-fix/README.md +65 -0
  406. package/examples/oss-quick-fix/implement-fix.yaml +84 -0
  407. package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
  408. package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
  409. package/examples/oss-quick-fix/ship-fix.yaml +81 -0
  410. package/examples/oss-quick-fix/understand-issue.yaml +67 -0
  411. package/examples/oss-quick-fix/verify-fix.yaml +73 -0
  412. package/examples/plan-review/README.md +37 -0
  413. package/examples/plan-review/plan-review-followup.yaml +13 -0
  414. package/examples/plan-review/plan-review.pipeline.yaml +9 -0
  415. package/examples/plan-review/plan-review.task.yaml +9 -0
  416. package/examples/plan-review/plan-review.yaml +25 -0
  417. package/examples/playwright-mcp/README.md +39 -0
  418. package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
  419. package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
  420. package/examples/playwright-mcp/screenshot.yaml +40 -0
  421. package/examples/retry-tour/README.md +75 -0
  422. package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
  423. package/examples/retry-tour/retry-tour.task.yaml +9 -0
  424. package/examples/route-if-tour/README.md +202 -0
  425. package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
  426. package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
  427. package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
  428. package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
  429. package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
  430. package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
  431. package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
  432. package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
  433. package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
  434. package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
  435. package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
  436. package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
  437. package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
  438. package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
  439. package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
  440. package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
  441. package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
  442. package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
  443. package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
  444. package/examples/route-wiring-smoke-test/README.md +377 -0
  445. package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
  446. package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
  447. package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
  448. package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
  449. package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
  450. package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
  451. package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
  452. package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
  453. package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
  454. package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
  455. package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
  456. package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
  457. package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
  458. package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
  459. package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
  460. package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
  461. package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
  462. package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
  463. package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
  464. package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
  465. package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
  466. package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
  467. package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
  468. package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
  469. package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
  470. package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
  471. package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
  472. package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
  473. package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
  474. package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
  475. package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
  476. package/examples/ship-feature/README.md +190 -0
  477. package/examples/ship-feature/feat-address-feedback.yaml +119 -0
  478. package/examples/ship-feature/feat-implement.yaml +180 -0
  479. package/examples/ship-feature/feat-plan.yaml +120 -0
  480. package/examples/ship-feature/feat-review.yaml +109 -0
  481. package/examples/ship-feature/feat-ship.yaml +203 -0
  482. package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
  483. package/examples/ship-feature/ship-feature.task.yaml +78 -0
  484. package/examples/stage-mcp/README.md +144 -0
  485. package/examples/stage-mcp/echo-mcp.mjs +20 -0
  486. package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
  487. package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
  488. package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
  489. package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
  490. package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
  491. package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
  492. package/examples/stage-mcp/use-echo.yaml +20 -0
  493. package/examples/verify-tour/README.md +80 -0
  494. package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
  495. package/examples/verify-tour/verify-tour.task.yaml +11 -0
  496. package/package.json +6 -1
  497. package/skills/stageflow/SKILL.md +6 -6
  498. package/skills/stageflow/references/control-surface.md +11 -5
  499. package/skills/stageflow/scripts/detect-host.mjs +14 -1
  500. package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
  501. package/skills/stageflow-author/SKILL.md +4 -3
  502. package/skills/stageflow-author/references/catalog-mapping.md +16 -0
  503. package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
  504. package/skills/stageflow-run/SKILL.md +20 -12
  505. package/skills/stageflow-run/references/mcp-call.md +9 -1
  506. package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
  507. package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
  508. package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
  509. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
  510. package/skills/stageflow-setup/SKILL.md +40 -8
  511. package/dist/ui/assets/index-Da5EHU6M.js +0 -119
@@ -0,0 +1,142 @@
1
+ import { listModelsForContext, listPipelinesForContext, listTasksForContext, } from "./browseCatalog.js";
2
+ import { loadStageflowManifestOutcome, } from "./loadStageflowManifest.js";
3
+ import { findCatalogRoot, isRootReadable, resolveCatalogRoots, } from "./resolveCatalogRoots.js";
4
+ import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
5
+ import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
6
+ async function catalogContextForRoot(root) {
7
+ if (root.kind === "seeded") {
8
+ const outcome = await loadStageflowManifestOutcome(root.path);
9
+ if (!outcome.ok) {
10
+ return {
11
+ projectRoot: root.path,
12
+ manifest: null,
13
+ manifestStatus: "invalid",
14
+ issues: outcome.issues,
15
+ };
16
+ }
17
+ return {
18
+ projectRoot: root.path,
19
+ manifest: outcome.value,
20
+ manifestStatus: "ok",
21
+ issues: [],
22
+ };
23
+ }
24
+ return catalogContextFromStageflow(await resolveStageflowContext(root.path));
25
+ }
26
+ async function selectRoots(options) {
27
+ const roots = await resolveCatalogRoots(options);
28
+ const root_errors = [];
29
+ if (options.projectRootFilter !== undefined) {
30
+ const match = findCatalogRoot(roots, options.projectRootFilter);
31
+ if (match === undefined) {
32
+ return {
33
+ roots,
34
+ selected: [],
35
+ root_errors: [
36
+ {
37
+ project_root: options.projectRootFilter,
38
+ code: "unknown_project_root",
39
+ message: `Unknown project_root: ${options.projectRootFilter}`,
40
+ },
41
+ ],
42
+ };
43
+ }
44
+ if (!(await isRootReadable(match.path))) {
45
+ return {
46
+ roots,
47
+ selected: [],
48
+ root_errors: [
49
+ {
50
+ project_root: match.project_root,
51
+ code: "catalog_root_unreadable",
52
+ message: `Catalog root is unreadable: ${match.project_root}`,
53
+ },
54
+ ],
55
+ };
56
+ }
57
+ return { roots, selected: [match], root_errors };
58
+ }
59
+ const selected = [];
60
+ for (const root of roots) {
61
+ if (!(await isRootReadable(root.path))) {
62
+ root_errors.push({
63
+ project_root: root.project_root,
64
+ code: "catalog_root_unreadable",
65
+ message: `Catalog root is unreadable: ${root.project_root}`,
66
+ });
67
+ continue;
68
+ }
69
+ selected.push(root);
70
+ }
71
+ return { roots, selected, root_errors };
72
+ }
73
+ export async function listPipelinesMultiProject(options) {
74
+ const { roots, selected, root_errors } = await selectRoots(options);
75
+ const items = [];
76
+ for (const root of selected) {
77
+ try {
78
+ const ctx = await catalogContextForRoot(root);
79
+ const pipelines = await listPipelinesForContext(ctx);
80
+ for (const p of pipelines) {
81
+ items.push({ ...p, project_root: root.project_root });
82
+ }
83
+ }
84
+ catch (err) {
85
+ root_errors.push({
86
+ project_root: root.project_root,
87
+ code: "catalog_root_unreadable",
88
+ message: err instanceof Error ? err.message : String(err),
89
+ });
90
+ }
91
+ }
92
+ return { items, root_errors, roots };
93
+ }
94
+ export async function listTasksMultiProject(options) {
95
+ const { roots, selected, root_errors } = await selectRoots(options);
96
+ const items = [];
97
+ for (const root of selected) {
98
+ try {
99
+ const ctx = await catalogContextForRoot(root);
100
+ const tasks = await listTasksForContext(ctx);
101
+ for (const t of tasks) {
102
+ items.push({ ...t, project_root: root.project_root });
103
+ }
104
+ }
105
+ catch (err) {
106
+ root_errors.push({
107
+ project_root: root.project_root,
108
+ code: "catalog_root_unreadable",
109
+ message: err instanceof Error ? err.message : String(err),
110
+ });
111
+ }
112
+ }
113
+ return { items, root_errors, roots };
114
+ }
115
+ export async function listModelsMultiProject(options) {
116
+ const { roots, selected, root_errors } = await selectRoots(options);
117
+ const items = [];
118
+ const modelSet = new Set();
119
+ for (const root of selected) {
120
+ try {
121
+ const ctx = await catalogContextForRoot(root);
122
+ const models = await listModelsForContext(ctx);
123
+ for (const id of models) {
124
+ modelSet.add(id);
125
+ items.push({ id, project_root: root.project_root });
126
+ }
127
+ }
128
+ catch (err) {
129
+ root_errors.push({
130
+ project_root: root.project_root,
131
+ code: "catalog_root_unreadable",
132
+ message: err instanceof Error ? err.message : String(err),
133
+ });
134
+ }
135
+ }
136
+ return {
137
+ items,
138
+ models: [...modelSet].sort((a, b) => a.localeCompare(b)),
139
+ root_errors,
140
+ roots,
141
+ };
142
+ }
@@ -7,6 +7,8 @@
7
7
  import path from "node:path";
8
8
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
9
9
  import { parseStageMcp } from "./loadStage.js";
10
+ import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
11
+ import { parseToolRequires } from "./toolRequires.js";
10
12
  import { legacyAuthoringRejected, presentLegacyKeys } from "./legacyYaml.js";
11
13
  import { compileTargetContract, dialectFromKeys, mixedDialectIssue, } from "./yamlDialect.js";
12
14
  import { BODY_KEYS, isAllowedPipelineStageEntryKey, } from "./pipelineStageKeys.js";
@@ -39,7 +41,11 @@ function extractBodyRaw(raw) {
39
41
  return body;
40
42
  }
41
43
  function hasBodyKey(raw) {
42
- return Object.keys(raw).some((key) => BODY_KEYS.has(key) && key !== "skill" && key !== "mcp");
44
+ return Object.keys(raw).some((key) => BODY_KEYS.has(key) &&
45
+ key !== "skill" &&
46
+ key !== "mcp" &&
47
+ key !== "secrets" &&
48
+ key !== "requires");
43
49
  }
44
50
  function readSkill(raw) {
45
51
  if (raw.skill === undefined)
@@ -112,6 +118,17 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
112
118
  if (!mcpOutcome.ok)
113
119
  return mcpOutcome;
114
120
  const mcp = mcpOutcome.value;
121
+ const secretsOutcome = parseStageSecrets(raw.secrets, `entry at index ${index} in ${declaringPath}`);
122
+ if (!secretsOutcome.ok)
123
+ return secretsOutcome;
124
+ const secrets = secretsOutcome.value;
125
+ const requiresOutcome = parseToolRequires(raw.requires, `stage entry at index ${index} in ${declaringPath}`, {
126
+ code: "stage.invalid_requires",
127
+ category: "stage",
128
+ });
129
+ if (!requiresOutcome.ok)
130
+ return requiresOutcome;
131
+ const requires = requiresOutcome.value;
115
132
  if (uses && hasBody) {
116
133
  return loadFailure([
117
134
  {
@@ -339,6 +356,8 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
339
356
  ...(entryFlag !== undefined ? { entry: entryFlag } : {}),
340
357
  ...(skill !== undefined ? { skill } : {}),
341
358
  ...(mcp !== undefined ? { mcp } : {}),
359
+ ...(secrets !== undefined ? { secrets } : {}),
360
+ ...(requires !== undefined ? { requires } : {}),
342
361
  ...(cloneCap !== undefined ? { clone_cap: cloneCap } : {}),
343
362
  ...(cloneMode !== undefined ? { clone_mode: cloneMode } : {}),
344
363
  };
@@ -37,6 +37,8 @@ export const BODY_KEYS = new Set([
37
37
  "timeout_ms",
38
38
  "skill",
39
39
  "mcp",
40
+ "secrets",
41
+ "requires",
40
42
  "io",
41
43
  "verify",
42
44
  ]);
@@ -0,0 +1,27 @@
1
+ import type { RunStore } from "../runstore/port.js";
2
+ export type CatalogRootKind = "registered" | "seeded";
3
+ export type CatalogRoot = {
4
+ /** Wire id: absolute path for registered; symbolic id for seeded (e.g. "examples"). */
5
+ project_root: string;
6
+ /** Absolute filesystem path used for browsing. */
7
+ path: string;
8
+ kind: CatalogRootKind;
9
+ read_only: boolean;
10
+ };
11
+ export type ResolveCatalogRootsOptions = {
12
+ store: RunStore;
13
+ /** Unused for catalog membership; retained so call sites may still pass Host cwd. */
14
+ bootCwd?: string;
15
+ /** Optional seeded roots (U10); default none. */
16
+ seededRoots?: Array<{
17
+ id: string;
18
+ path: string;
19
+ }>;
20
+ };
21
+ /**
22
+ * Root set = registered store roots ∪ seeded roots.
23
+ * Wire project_root for seeded is the symbolic id; store/capacity use absolute paths.
24
+ */
25
+ export declare function resolveCatalogRoots(options: ResolveCatalogRootsOptions): Promise<CatalogRoot[]>;
26
+ export declare function isRootReadable(rootPath: string): Promise<boolean>;
27
+ export declare function findCatalogRoot(roots: CatalogRoot[], projectRoot: string): CatalogRoot | undefined;
@@ -0,0 +1,76 @@
1
+ import path from "node:path";
2
+ import { realpathSync, constants } from "node:fs";
3
+ import { access } from "node:fs/promises";
4
+ function realOrResolve(p) {
5
+ const resolved = path.resolve(p);
6
+ try {
7
+ return realpathSync(resolved);
8
+ }
9
+ catch {
10
+ return resolved;
11
+ }
12
+ }
13
+ /**
14
+ * Root set = registered store roots ∪ seeded roots.
15
+ * Wire project_root for seeded is the symbolic id; store/capacity use absolute paths.
16
+ */
17
+ export async function resolveCatalogRoots(options) {
18
+ const roots = [];
19
+ const seenPaths = new Set();
20
+ const seededRoots = options.seededRoots ??
21
+ (await import("./seededCatalog.js")).defaultSeededRoots();
22
+ let registered = [];
23
+ try {
24
+ registered = await options.store.listRegisteredProjects();
25
+ }
26
+ catch {
27
+ registered = [];
28
+ }
29
+ for (const root of registered) {
30
+ const abs = realOrResolve(root);
31
+ if (seenPaths.has(abs))
32
+ continue;
33
+ seenPaths.add(abs);
34
+ roots.push({
35
+ project_root: abs,
36
+ path: abs,
37
+ kind: "registered",
38
+ read_only: false,
39
+ });
40
+ }
41
+ for (const seeded of seededRoots) {
42
+ const abs = realOrResolve(seeded.path);
43
+ if (seenPaths.has(abs))
44
+ continue;
45
+ seenPaths.add(abs);
46
+ roots.push({
47
+ project_root: seeded.id,
48
+ path: abs,
49
+ kind: "seeded",
50
+ read_only: true,
51
+ });
52
+ }
53
+ return roots;
54
+ }
55
+ export async function isRootReadable(rootPath) {
56
+ try {
57
+ await access(rootPath, constants.R_OK);
58
+ return true;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ export function findCatalogRoot(roots, projectRoot) {
65
+ if (!path.isAbsolute(projectRoot)) {
66
+ return roots.find((r) => r.project_root === projectRoot);
67
+ }
68
+ const normalized = realOrResolve(projectRoot);
69
+ const resolved = path.resolve(projectRoot);
70
+ return roots.find((r) => r.project_root === projectRoot ||
71
+ r.path === projectRoot ||
72
+ r.project_root === resolved ||
73
+ r.path === resolved ||
74
+ r.project_root === normalized ||
75
+ r.path === normalized);
76
+ }
@@ -8,6 +8,12 @@ export type ModelSelection = {
8
8
  /** Stage yaml / inline `model`; overrides pipeline/global. */
9
9
  stage?: string;
10
10
  };
11
+ export type ModelAuthoredTier = "stage" | "pipeline" | "global";
12
+ export type ResolvedModelSelection = {
13
+ model: string;
14
+ tier: ModelAuthoredTier;
15
+ };
16
+ export declare function modelAuthoredTier(selection: ModelSelection): ModelAuthoredTier;
11
17
  /**
12
18
  * stage > pipeline > global. No silent hardcoded fallback — unset is a load error.
13
19
  * Present-but-empty / whitespace follows parseModelField (load failure, not "").
@@ -15,6 +21,6 @@ export type ModelSelection = {
15
21
  export declare function resolveModelOutcome(selection: ModelSelection, ctx: {
16
22
  stageId: string;
17
23
  pipelineId: string;
18
- }): LoadOutcome<string>;
24
+ }): LoadOutcome<ResolvedModelSelection>;
19
25
  /** The global tier's model id from an already-loaded manifest, or undefined when missing/unset. */
20
26
  export declare function globalModelFromManifest(loaded: LoadedManifest | null): string | undefined;
@@ -1,5 +1,12 @@
1
1
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
2
2
  import { parseModelField } from "./modelField.js";
3
+ export function modelAuthoredTier(selection) {
4
+ if (selection.stage !== undefined)
5
+ return "stage";
6
+ if (selection.pipeline !== undefined)
7
+ return "pipeline";
8
+ return "global";
9
+ }
3
10
  /**
4
11
  * stage > pipeline > global. No silent hardcoded fallback — unset is a load error.
5
12
  * Present-but-empty / whitespace follows parseModelField (load failure, not "").
@@ -27,7 +34,10 @@ export function resolveModelOutcome(selection, ctx) {
27
34
  },
28
35
  ]);
29
36
  }
30
- return loadSuccess(parsed.value);
37
+ return loadSuccess({
38
+ model: parsed.value,
39
+ tier: modelAuthoredTier(selection),
40
+ });
31
41
  }
32
42
  /** The global tier's model id from an already-loaded manifest, or undefined when missing/unset. */
33
43
  export function globalModelFromManifest(loaded) {
@@ -1,4 +1,4 @@
1
- export type StageMcpErrorCode = "missing_catalog" | "unknown_server" | "reserved_name" | "unresolved_var" | "invalid_config" | "connect_failed";
1
+ export type StageMcpErrorCode = "missing_catalog" | "unknown_server" | "reserved_name" | "unresolved_var" | "invalid_config" | "untrusted_config_origin" | "connect_failed";
2
2
  export declare class StageMcpError extends Error {
3
3
  readonly code: StageMcpErrorCode;
4
4
  constructor(message: string, code: StageMcpErrorCode);
@@ -15,6 +15,7 @@ export type InspectedMcpCatalog = {
15
15
  };
16
16
  export declare function mcpCatalogPath(projectRoot: string): string;
17
17
  export declare function parseMcpCatalog(raw: string, catalogPath?: string): McpCatalogServers;
18
+ export declare function mcpCatalogExists(projectRoot: string): Promise<boolean>;
18
19
  export declare function loadMcpCatalog(projectRoot: string): Promise<InspectedMcpCatalog>;
19
20
  export type ProjectMcpCatalogTransport = "stdio" | "http";
20
21
  export type ProjectMcpCatalogEntry = {
@@ -32,4 +33,11 @@ export declare function resolveStageMcpServers(options: {
32
33
  projectRoot: string;
33
34
  allowlist?: readonly string[];
34
35
  env: NodeJS.ProcessEnv;
36
+ stageId?: string;
37
+ bindingKind?: "repository" | "checkout" | "none";
38
+ trustWorkspaceConfig?: string[];
39
+ /** Host project root used for trust_workspace_config allowlist matching. */
40
+ trustProjectRoot?: string;
41
+ /** When true, .mcp.json is treated as workspace-sourced. */
42
+ workspaceSourced?: boolean;
35
43
  }): Promise<ResolvedMcpServers>;
@@ -51,6 +51,18 @@ export function parseMcpCatalog(raw, catalogPath = MCP_CATALOG_FILENAME) {
51
51
  }
52
52
  return servers;
53
53
  }
54
+ export async function mcpCatalogExists(projectRoot) {
55
+ try {
56
+ await readFile(mcpCatalogPath(projectRoot), "utf8");
57
+ return true;
58
+ }
59
+ catch (err) {
60
+ const code = err.code;
61
+ if (code === "ENOENT")
62
+ return false;
63
+ throw err;
64
+ }
65
+ }
54
66
  export async function loadMcpCatalog(projectRoot) {
55
67
  const catalogPath = mcpCatalogPath(projectRoot);
56
68
  let raw;
@@ -108,7 +120,7 @@ export function assertMcpAllowlistKnown(servers, allowlist) {
108
120
  const INTERPOLATION_TOKEN = /\$\{([^}]*)\}/g;
109
121
  const ENV_VAR_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
110
122
  const ENV_VAR_WITH_DEFAULT = /^([A-Za-z_][A-Za-z0-9_]*):-(.*)$/;
111
- function interpolateString(value, env, serverName) {
123
+ function interpolateString(value, env, serverName, stageId) {
112
124
  return value.replace(INTERPOLATION_TOKEN, (_match, inner) => {
113
125
  const withDefault = ENV_VAR_WITH_DEFAULT.exec(inner);
114
126
  if (withDefault) {
@@ -120,24 +132,27 @@ function interpolateString(value, env, serverName) {
120
132
  if (found !== undefined) {
121
133
  return found;
122
134
  }
123
- throw new StageMcpError(`Unresolved MCP catalog variable "${inner}"`, "unresolved_var");
135
+ const stagePart = stageId !== undefined ? ` (stage "${stageId}")` : "";
136
+ throw new StageMcpError(`Unresolved MCP catalog variable "${inner}" for server "${serverName}"${stagePart}. Declare it in secrets: (use as: env for tokens needed in MCP env) or use \${${inner}:-default}.`, "unresolved_var");
124
137
  }
125
138
  throw new StageMcpError(`MCP catalog server "${serverName}" has an invalid interpolation form`, "invalid_config");
126
139
  });
127
140
  }
128
- function interpolateField(key, value, env, serverName) {
141
+ function interpolateField(key, value, env, serverName, stageId) {
129
142
  if ((key === "command" || key === "url" || key === "cwd") && typeof value === "string") {
130
- return interpolateString(value, env, serverName);
143
+ return interpolateString(value, env, serverName, stageId);
131
144
  }
132
145
  if (key === "args" && Array.isArray(value)) {
133
- return value.map((item) => typeof item === "string" ? interpolateString(item, env, serverName) : item);
146
+ return value.map((item) => typeof item === "string"
147
+ ? interpolateString(item, env, serverName, stageId)
148
+ : item);
134
149
  }
135
150
  if ((key === "env" || key === "headers") && isPlainObject(value)) {
136
151
  const copied = {};
137
152
  for (const [field, fieldValue] of Object.entries(value)) {
138
153
  copied[field] =
139
154
  typeof fieldValue === "string"
140
- ? interpolateString(fieldValue, env, serverName)
155
+ ? interpolateString(fieldValue, env, serverName, stageId)
141
156
  : fieldValue;
142
157
  }
143
158
  return copied;
@@ -185,10 +200,10 @@ function stampSpawnRoot(resolved, projectRoot, serverName) {
185
200
  }
186
201
  return resolved;
187
202
  }
188
- function interpolateServer(entry, env, serverName, projectRoot) {
203
+ function interpolateServer(entry, env, serverName, projectRoot, stageId) {
189
204
  const resolved = {};
190
205
  for (const [key, value] of Object.entries(entry)) {
191
- resolved[key] = interpolateField(key, value, env, serverName);
206
+ resolved[key] = interpolateField(key, value, env, serverName, stageId);
192
207
  }
193
208
  return stampSpawnRoot(resolved, projectRoot, serverName);
194
209
  }
@@ -197,11 +212,23 @@ export async function resolveStageMcpServers(options) {
197
212
  if (allowlist.length === 0) {
198
213
  return {};
199
214
  }
215
+ if (options.workspaceSourced === true) {
216
+ const { decideWorkspaceConfigTrust } = await import("./configOrigin.js");
217
+ const decision = decideWorkspaceConfigTrust({
218
+ bindingKind: options.bindingKind ?? "none",
219
+ projectRoot: options.trustProjectRoot ?? options.projectRoot,
220
+ trustWorkspaceConfig: options.trustWorkspaceConfig,
221
+ source: "workspace",
222
+ });
223
+ if (!decision.allow) {
224
+ throw new StageMcpError(decision.message ?? "untrusted_config_origin", "untrusted_config_origin");
225
+ }
226
+ }
200
227
  const catalog = await loadMcpCatalog(options.projectRoot);
201
228
  assertMcpAllowlistKnown(catalog.servers, allowlist);
202
229
  const resolved = {};
203
230
  for (const name of allowlist) {
204
- resolved[name] = interpolateServer(catalog.servers[name], options.env, name, options.projectRoot);
231
+ resolved[name] = interpolateServer(catalog.servers[name], options.env, name, options.projectRoot, options.stageId);
205
232
  }
206
233
  return resolved;
207
234
  }
@@ -0,0 +1,9 @@
1
+ export declare class SecretFromEnvError extends Error {
2
+ readonly code = "config_invalid";
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Read a secret from `NAME` or `NAME_FILE`. Both set → error.
7
+ * File values trim exactly one trailing newline (`\n` or `\r\n`).
8
+ */
9
+ export declare function readSecretFromEnvOrFile(env: NodeJS.ProcessEnv, name: string): string | undefined;
@@ -0,0 +1,34 @@
1
+ import { readFileSync } from "node:fs";
2
+ export class SecretFromEnvError extends Error {
3
+ code = "config_invalid";
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = "SecretFromEnvError";
7
+ }
8
+ }
9
+ /**
10
+ * Read a secret from `NAME` or `NAME_FILE`. Both set → error.
11
+ * File values trim exactly one trailing newline (`\n` or `\r\n`).
12
+ */
13
+ export function readSecretFromEnvOrFile(env, name) {
14
+ const fileKey = `${name}_FILE`;
15
+ const plain = env[name];
16
+ const filePath = env[fileKey];
17
+ const hasPlain = plain !== undefined && plain.length > 0;
18
+ const hasFile = filePath !== undefined && filePath.length > 0;
19
+ if (hasPlain && hasFile) {
20
+ throw new SecretFromEnvError(`Set only one of ${name} or ${fileKey}, not both`);
21
+ }
22
+ if (hasFile) {
23
+ try {
24
+ return readFileSync(filePath, "utf8").replace(/\r?\n$/, "");
25
+ }
26
+ catch (err) {
27
+ const detail = err instanceof Error ? err.message : String(err);
28
+ throw new SecretFromEnvError(`Failed to read ${fileKey}=${filePath}: ${detail}`);
29
+ }
30
+ }
31
+ if (hasPlain)
32
+ return plain;
33
+ return undefined;
34
+ }
@@ -0,0 +1,11 @@
1
+ /** Symbolic wire id for the packaged examples catalog root. */
2
+ export declare const SEEDED_EXAMPLES_ID = "examples";
3
+ /**
4
+ * Absolute path to packaged `examples/` when present next to the package root.
5
+ * Does not git-init; callers build CatalogContext with fixed projectRoot + manifest.
6
+ */
7
+ export declare function resolveSeededExamplesPath(fromUrl?: string): string | undefined;
8
+ export declare function defaultSeededRoots(): Array<{
9
+ id: string;
10
+ path: string;
11
+ }>;
@@ -0,0 +1,29 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { existsSync } from "node:fs";
4
+ /** Symbolic wire id for the packaged examples catalog root. */
5
+ export const SEEDED_EXAMPLES_ID = "examples";
6
+ /**
7
+ * Absolute path to packaged `examples/` when present next to the package root.
8
+ * Does not git-init; callers build CatalogContext with fixed projectRoot + manifest.
9
+ */
10
+ export function resolveSeededExamplesPath(fromUrl = import.meta.url) {
11
+ const here = path.dirname(fileURLToPath(fromUrl));
12
+ const candidates = [
13
+ path.resolve(here, "../../examples"),
14
+ path.resolve(here, "../../../examples"),
15
+ path.resolve(process.cwd(), "examples"),
16
+ ];
17
+ for (const candidate of candidates) {
18
+ if (existsSync(path.join(candidate, "README.md"))) {
19
+ return candidate;
20
+ }
21
+ }
22
+ return undefined;
23
+ }
24
+ export function defaultSeededRoots() {
25
+ const examples = resolveSeededExamplesPath();
26
+ if (examples === undefined)
27
+ return [];
28
+ return [{ id: SEEDED_EXAMPLES_ID, path: examples }];
29
+ }
@@ -0,0 +1,24 @@
1
+ import { type LoadOutcome } from "./loadOutcome.js";
2
+ export type ToolRequirement = {
3
+ tool: string;
4
+ version?: string;
5
+ };
6
+ export declare function parseToolRequires(raw: unknown, label: string, options: {
7
+ code: "pipeline.invalid_requires" | "stage.invalid_requires";
8
+ category: "pipeline" | "stage";
9
+ pipelineId?: string;
10
+ stageId?: string;
11
+ }): LoadOutcome<ToolRequirement[] | undefined>;
12
+ /**
13
+ * Merge requirement lists: same tool → intersect version ranges (stricter).
14
+ * Non-intersecting ranges fail with pipeline.requires_conflict.
15
+ */
16
+ export declare function mergeToolRequires(lists: Array<readonly ToolRequirement[] | undefined>, ctx: {
17
+ pipelineId: string;
18
+ label?: string;
19
+ }): LoadOutcome<ToolRequirement[]>;
20
+ export declare function collectEffectiveRequires(options: {
21
+ pipelineRequires?: readonly ToolRequirement[];
22
+ stageRequires: Array<readonly ToolRequirement[] | undefined>;
23
+ pipelineId: string;
24
+ }): LoadOutcome<ToolRequirement[]>;