stageflow 0.25.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 (501) hide show
  1. package/README.md +10 -3
  2. package/dist/a2a/contracts.d.ts +1 -0
  3. package/dist/a2a/contracts.js +1 -0
  4. package/dist/a2a/registry.d.ts +2 -0
  5. package/dist/a2a/registry.js +20 -1
  6. package/dist/a2a/server.d.ts +7 -0
  7. package/dist/a2a/server.js +5 -2
  8. package/dist/a2a/service.d.ts +1 -1
  9. package/dist/a2a/service.js +57 -8
  10. package/dist/a2a/store.d.ts +8 -5
  11. package/dist/a2a/store.js +24 -67
  12. package/dist/agent/activity.d.ts +3 -0
  13. package/dist/agent/bootProviderConfig.d.ts +21 -0
  14. package/dist/agent/bootProviderConfig.js +74 -0
  15. package/dist/agent/piAdapter.d.ts +9 -1
  16. package/dist/agent/piAdapter.js +58 -3
  17. package/dist/agent/piIsolatedMcp.d.ts +2 -0
  18. package/dist/agent/piIsolatedMcp.js +10 -2
  19. package/dist/agent/port.d.ts +6 -0
  20. package/dist/agent/streamLogRedact.d.ts +1 -1
  21. package/dist/agent/streamLogRedact.js +4 -11
  22. package/dist/cli/artifactCommand.js +9 -16
  23. package/dist/cli/backupCommand.d.ts +9 -0
  24. package/dist/cli/backupCommand.js +111 -0
  25. package/dist/cli/debugRunCommand.d.ts +10 -0
  26. package/dist/cli/debugRunCommand.js +109 -0
  27. package/dist/cli/doctorCommand.d.ts +32 -0
  28. package/dist/cli/doctorCommand.js +453 -0
  29. package/dist/cli/envelopeCommand.js +9 -2
  30. package/dist/cli/exportAllCommand.d.ts +55 -0
  31. package/dist/cli/exportAllCommand.js +218 -0
  32. package/dist/cli/exportRunCommand.js +23 -21
  33. package/dist/cli/hostClient.d.ts +21 -3
  34. package/dist/cli/hostClient.js +93 -12
  35. package/dist/cli/initTemplates.d.ts +1 -1
  36. package/dist/cli/initTemplates.js +8 -1
  37. package/dist/cli/resolveSafeOutPath.d.ts +2 -0
  38. package/dist/cli/resolveSafeOutPath.js +40 -0
  39. package/dist/cli/restoreCommand.d.ts +10 -0
  40. package/dist/cli/restoreCommand.js +90 -0
  41. package/dist/cli/runCommand.d.ts +3 -2
  42. package/dist/cli/runCommand.js +93 -11
  43. package/dist/cli/runOutput.d.ts +4 -0
  44. package/dist/cli/runOutput.js +33 -7
  45. package/dist/cli/runStageCommand.d.ts +1 -0
  46. package/dist/cli/runStageCommand.js +44 -25
  47. package/dist/cli/runsCommand.d.ts +1 -1
  48. package/dist/cli/runsCommand.js +162 -8
  49. package/dist/cli.js +171 -30
  50. package/dist/config/catalogRelativePath.d.ts +62 -0
  51. package/dist/config/catalogRelativePath.js +118 -0
  52. package/dist/config/configOrigin.d.ts +27 -0
  53. package/dist/config/configOrigin.js +59 -0
  54. package/dist/config/hostConfig.d.ts +55 -0
  55. package/dist/config/hostConfig.js +333 -0
  56. package/dist/config/listSkills.d.ts +26 -0
  57. package/dist/config/listSkills.js +190 -3
  58. package/dist/config/loadOutcome.d.ts +1 -1
  59. package/dist/config/loadPipeline.js +23 -2
  60. package/dist/config/loadStage.js +18 -0
  61. package/dist/config/loadTask.d.ts +2 -0
  62. package/dist/config/loadTask.js +57 -18
  63. package/dist/config/materializeStageModels.js +5 -1
  64. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  65. package/dist/config/mergePipelineIncludes.js +19 -0
  66. package/dist/config/migrateYaml.js +6 -11
  67. package/dist/config/multiProjectCatalog.d.ts +30 -0
  68. package/dist/config/multiProjectCatalog.js +142 -0
  69. package/dist/config/normalizePipelineStageEntry.js +20 -1
  70. package/dist/config/pipelineStageKeys.js +2 -0
  71. package/dist/config/resolveCatalogRoots.d.ts +27 -0
  72. package/dist/config/resolveCatalogRoots.js +76 -0
  73. package/dist/config/resolveModel.d.ts +7 -1
  74. package/dist/config/resolveModel.js +11 -1
  75. package/dist/config/resolveStageMcpServers.d.ts +9 -1
  76. package/dist/config/resolveStageMcpServers.js +36 -9
  77. package/dist/config/secretFromEnvOrFile.d.ts +9 -0
  78. package/dist/config/secretFromEnvOrFile.js +34 -0
  79. package/dist/config/seededCatalog.d.ts +11 -0
  80. package/dist/config/seededCatalog.js +29 -0
  81. package/dist/config/toolRequires.d.ts +24 -0
  82. package/dist/config/toolRequires.js +115 -0
  83. package/dist/config/validateCatalog.d.ts +5 -1
  84. package/dist/config/validateCatalog.js +140 -1
  85. package/dist/diagnostics/checks.d.ts +39 -0
  86. package/dist/diagnostics/checks.js +135 -0
  87. package/dist/errors/codes.d.ts +14 -0
  88. package/dist/errors/codes.js +59 -0
  89. package/dist/git/cache.d.ts +14 -0
  90. package/dist/git/cache.js +150 -0
  91. package/dist/git/credentials.d.ts +9 -0
  92. package/dist/git/credentials.js +88 -0
  93. package/dist/git/errors.d.ts +20 -0
  94. package/dist/git/errors.js +94 -0
  95. package/dist/git/exec.d.ts +16 -0
  96. package/dist/git/exec.js +135 -0
  97. package/dist/git/operations.d.ts +29 -0
  98. package/dist/git/operations.js +153 -0
  99. package/dist/git/version.d.ts +1 -0
  100. package/dist/git/version.js +10 -0
  101. package/dist/logging/audit.d.ts +16 -0
  102. package/dist/logging/audit.js +19 -0
  103. package/dist/logging/commonWords.d.ts +2 -0
  104. package/dist/logging/commonWords.js +13 -0
  105. package/dist/logging/logger.d.ts +49 -0
  106. package/dist/logging/logger.js +193 -0
  107. package/dist/logging/namedSecrets.d.ts +6 -0
  108. package/dist/logging/namedSecrets.js +58 -0
  109. package/dist/logging/redact.d.ts +13 -0
  110. package/dist/logging/redact.js +88 -0
  111. package/dist/mcp/catalogTools.js +456 -80
  112. package/dist/mcp/checkoutTools.d.ts +52 -0
  113. package/dist/mcp/checkoutTools.js +332 -0
  114. package/dist/mcp/controlTools.js +179 -5
  115. package/dist/mcp/deps.d.ts +1 -0
  116. package/dist/mcp/getStartedTool.d.ts +3 -0
  117. package/dist/mcp/getStartedTool.js +62 -0
  118. package/dist/mcp/readArtifact.d.ts +11 -0
  119. package/dist/mcp/readArtifact.js +46 -30
  120. package/dist/mcp/server.js +1 -0
  121. package/dist/mcp/tools.js +4 -0
  122. package/dist/net/proxy.d.ts +14 -0
  123. package/dist/net/proxy.js +78 -0
  124. package/dist/package-meta.d.ts +2 -1
  125. package/dist/package-meta.js +2 -1
  126. package/dist/preflight/bash.d.ts +8 -0
  127. package/dist/preflight/bash.js +34 -0
  128. package/dist/preflight/claudeRoot.d.ts +11 -0
  129. package/dist/preflight/claudeRoot.js +23 -0
  130. package/dist/preflight/mcpCommands.d.ts +8 -0
  131. package/dist/preflight/mcpCommands.js +36 -0
  132. package/dist/preflight/pipelinePreflight.d.ts +40 -0
  133. package/dist/preflight/pipelinePreflight.js +192 -0
  134. package/dist/preflight/tls.d.ts +6 -0
  135. package/dist/preflight/tls.js +18 -0
  136. package/dist/preflight/toolchain.d.ts +45 -0
  137. package/dist/preflight/toolchain.js +219 -0
  138. package/dist/project/findProjectRoot.js +3 -4
  139. package/dist/project/globalHome.d.ts +7 -0
  140. package/dist/project/globalHome.js +63 -2
  141. package/dist/project/resolveProjectContext.js +2 -2
  142. package/dist/project/resolveStageflowContext.js +2 -2
  143. package/dist/projection/projectRun.d.ts +2 -1
  144. package/dist/projection/projectRun.js +1 -0
  145. package/dist/runstore/assertTmpdir.d.ts +1 -0
  146. package/dist/runstore/assertTmpdir.js +21 -0
  147. package/dist/runstore/backup.d.ts +52 -0
  148. package/dist/runstore/backup.js +292 -0
  149. package/dist/runstore/createStore.d.ts +18 -1
  150. package/dist/runstore/createStore.js +64 -5
  151. package/dist/runstore/debugBundle.d.ts +60 -0
  152. package/dist/runstore/debugBundle.js +143 -0
  153. package/dist/runstore/diskUsage.d.ts +50 -0
  154. package/dist/runstore/diskUsage.js +214 -0
  155. package/dist/runstore/exportRunPayload.d.ts +8 -0
  156. package/dist/runstore/exportRunPayload.js +23 -0
  157. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  158. package/dist/runstore/normalizeCatalogPath.js +10 -0
  159. package/dist/runstore/paths.d.ts +5 -0
  160. package/dist/runstore/paths.js +145 -1
  161. package/dist/runstore/port.d.ts +111 -13
  162. package/dist/runstore/port.js +8 -1
  163. package/dist/runstore/restore.d.ts +81 -0
  164. package/dist/runstore/restore.js +355 -0
  165. package/dist/runstore/retention.d.ts +27 -0
  166. package/dist/runstore/retention.js +74 -0
  167. package/dist/runstore/runManifest.d.ts +146 -0
  168. package/dist/runstore/runManifest.js +288 -0
  169. package/dist/runstore/runProjection.d.ts +3 -1
  170. package/dist/runstore/runProjection.js +63 -1
  171. package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -3
  172. package/dist/runstore/sqlite/SqliteRunStore.js +352 -219
  173. package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
  174. package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
  175. package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
  176. package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
  177. package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
  178. package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
  179. package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
  180. package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
  181. package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
  182. package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
  183. package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
  184. package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
  185. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
  186. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
  187. package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
  188. package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
  189. package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
  190. package/dist/runstore/sqlite/migrations/index.js +72 -0
  191. package/dist/runstore/sqlite/schema.d.ts +20 -1
  192. package/dist/runstore/sqlite/schema.js +277 -1
  193. package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
  194. package/dist/runstore/sqlite/storeOpenError.js +11 -0
  195. package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
  196. package/dist/runstore/sqlite/storeSchemaError.js +8 -0
  197. package/dist/runstore/stageExecution.js +3 -0
  198. package/dist/runstore/storeFilesystem.d.ts +32 -0
  199. package/dist/runstore/storeFilesystem.js +148 -0
  200. package/dist/runstore/trackProjection.js +2 -0
  201. package/dist/runstore/workspaceLayout.d.ts +13 -0
  202. package/dist/runstore/workspaceLayout.js +76 -0
  203. package/dist/runtime/completionCheckRunner.d.ts +3 -0
  204. package/dist/runtime/completionCheckRunner.js +45 -7
  205. package/dist/runtime/containerLimits.d.ts +16 -0
  206. package/dist/runtime/containerLimits.js +84 -0
  207. package/dist/runtime/credentialMaterialisation.d.ts +28 -0
  208. package/dist/runtime/credentialMaterialisation.js +128 -0
  209. package/dist/runtime/gitCheckoutCapability.js +7 -13
  210. package/dist/runtime/pipelineRunner.d.ts +36 -1
  211. package/dist/runtime/pipelineRunner.js +178 -17
  212. package/dist/runtime/pipelineScheduler.d.ts +15 -0
  213. package/dist/runtime/pipelineScheduler.js +135 -27
  214. package/dist/runtime/reloadRunCatalog.js +6 -1
  215. package/dist/runtime/repositoryMaterialize.d.ts +47 -0
  216. package/dist/runtime/repositoryMaterialize.js +235 -0
  217. package/dist/runtime/resumeTimedOut.d.ts +1 -1
  218. package/dist/runtime/resumeTimedOut.js +5 -2
  219. package/dist/runtime/runChangeBus.js +9 -0
  220. package/dist/runtime/runDeletion.d.ts +7 -0
  221. package/dist/runtime/runDeletion.js +37 -0
  222. package/dist/runtime/runManager.d.ts +158 -4
  223. package/dist/runtime/runManager.js +1596 -79
  224. package/dist/runtime/runRetentionSweep.d.ts +31 -0
  225. package/dist/runtime/runRetentionSweep.js +328 -0
  226. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  227. package/dist/runtime/runRetryCoordinator.js +19 -2
  228. package/dist/runtime/runSkills.d.ts +40 -0
  229. package/dist/runtime/runSkills.js +173 -0
  230. package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
  231. package/dist/runtime/stageAttemptBootstrap.js +195 -24
  232. package/dist/runtime/stageCacheEnv.d.ts +6 -0
  233. package/dist/runtime/stageCacheEnv.js +34 -0
  234. package/dist/runtime/stageConcurrency.d.ts +2 -1
  235. package/dist/runtime/stageConcurrency.js +4 -2
  236. package/dist/runtime/stageEnvironment.d.ts +38 -0
  237. package/dist/runtime/stageEnvironment.js +193 -0
  238. package/dist/runtime/stageProcessLauncher.d.ts +18 -0
  239. package/dist/runtime/stageProcessLauncher.js +194 -38
  240. package/dist/runtime/stageRecovery.d.ts +3 -1
  241. package/dist/runtime/stageRecovery.js +19 -4
  242. package/dist/runtime/stageRoots.d.ts +38 -1
  243. package/dist/runtime/stageRoots.js +118 -0
  244. package/dist/runtime/stageRunner.d.ts +1 -0
  245. package/dist/runtime/stageRunner.js +3 -1
  246. package/dist/runtime/stageSecretDecl.d.ts +9 -0
  247. package/dist/runtime/stageSecretDecl.js +102 -0
  248. package/dist/runtime/stageSecrets.d.ts +40 -0
  249. package/dist/runtime/stageSecrets.js +181 -0
  250. package/dist/runtime/stageWorker.d.ts +3 -2
  251. package/dist/runtime/stageWorker.js +58 -10
  252. package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
  253. package/dist/runtime/stageWorkerProtocol.js +8 -0
  254. package/dist/runtime/startPayload.d.ts +32 -0
  255. package/dist/runtime/startPayload.js +59 -0
  256. package/dist/runtime/taskInput.js +14 -5
  257. package/dist/runtime/verifiedStageExecution.d.ts +1 -0
  258. package/dist/runtime/verifiedStageExecution.js +2 -1
  259. package/dist/runtime/workspaceBinding.d.ts +20 -0
  260. package/dist/runtime/workspaceBinding.js +60 -0
  261. package/dist/server/allowedHosts.d.ts +19 -0
  262. package/dist/server/allowedHosts.js +179 -0
  263. package/dist/server/bootstrap.d.ts +36 -2
  264. package/dist/server/bootstrap.js +209 -5
  265. package/dist/server/controlToken.d.ts +47 -0
  266. package/dist/server/controlToken.js +241 -0
  267. package/dist/server/createHttpHost.d.ts +11 -2
  268. package/dist/server/createHttpHost.js +103 -10
  269. package/dist/server/ensureGlobalService.d.ts +5 -1
  270. package/dist/server/ensureGlobalService.js +35 -1
  271. package/dist/server/healthSurfaces.d.ts +6 -0
  272. package/dist/server/healthSurfaces.js +98 -0
  273. package/dist/server/http.d.ts +12 -1
  274. package/dist/server/http.js +1085 -485
  275. package/dist/server/listenHost.d.ts +5 -0
  276. package/dist/server/listenHost.js +56 -0
  277. package/dist/server/mcpHost.d.ts +10 -1
  278. package/dist/server/mcpHost.js +36 -6
  279. package/dist/server/operatorResults.d.ts +2 -2
  280. package/dist/server/operatorResults.js +40 -29
  281. package/dist/server/requestAuthContext.d.ts +12 -0
  282. package/dist/server/requestAuthContext.js +21 -0
  283. package/dist/server/shutdown.d.ts +69 -0
  284. package/dist/server/shutdown.js +219 -0
  285. package/dist/types/pipeline.d.ts +7 -0
  286. package/dist/types/stage.d.ts +8 -0
  287. package/dist/types/task.d.ts +8 -0
  288. package/dist/ui/assets/index-B6hlSXXn.js +120 -0
  289. package/dist/ui/index.html +1 -1
  290. package/examples/README.md +98 -0
  291. package/examples/archify-on-pr/README.md +213 -0
  292. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
  293. package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
  294. package/examples/archify-on-pr/author-diagrams.yaml +106 -0
  295. package/examples/archify-on-pr/detect-changes.yaml +89 -0
  296. package/examples/ci-validate/README.md +35 -0
  297. package/examples/ci-validate/check.yaml +13 -0
  298. package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
  299. package/examples/ci-validate/validate.sh +5 -0
  300. package/examples/compliance-review-demo/README.md +125 -0
  301. package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
  302. package/examples/compliance-review-demo/connect-account.yaml +47 -0
  303. package/examples/compliance-review-demo/map-to-control.yaml +123 -0
  304. package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
  305. package/examples/compliance-review-demo/publish-report.yaml +79 -0
  306. package/examples/compliance-review-demo/review-verdict.yaml +122 -0
  307. package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
  308. package/examples/compliance-review-demo/store-evidence.yaml +143 -0
  309. package/examples/conditional-fork/README.md +89 -0
  310. package/examples/conditional-fork/branch-a.yaml +13 -0
  311. package/examples/conditional-fork/branch-b.yaml +13 -0
  312. package/examples/conditional-fork/decide.yaml +35 -0
  313. package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
  314. package/examples/conditional-fork/fork-demo.task.yaml +8 -0
  315. package/examples/context7-mcp/README.md +42 -0
  316. package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
  317. package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
  318. package/examples/context7-mcp/fetch-docs.yaml +52 -0
  319. package/examples/context7-mcp/resolve-library.yaml +31 -0
  320. package/examples/context7-mcp/write-brief.yaml +52 -0
  321. package/examples/feature-loop/README.md +104 -0
  322. package/examples/feature-loop/address-feedback.yaml +148 -0
  323. package/examples/feature-loop/align.yaml +116 -0
  324. package/examples/feature-loop/decompose.yaml +86 -0
  325. package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
  326. package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
  327. package/examples/feature-loop/feature-loop.task.yaml +25 -0
  328. package/examples/feature-loop/implement.yaml +128 -0
  329. package/examples/feature-loop/plan.yaml +111 -0
  330. package/examples/feature-loop/publish.yaml +167 -0
  331. package/examples/feature-loop/review.yaml +146 -0
  332. package/examples/feature-loop/verify.yaml +106 -0
  333. package/examples/feedback-loop/README.md +72 -0
  334. package/examples/feedback-loop/VERIFY.md +208 -0
  335. package/examples/feedback-loop/continue-only.task.yaml +4 -0
  336. package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
  337. package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
  338. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
  339. package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
  340. package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
  341. package/examples/feedback-loop/implement.yaml +14 -0
  342. package/examples/feedback-loop/plan.yaml +14 -0
  343. package/examples/feedback-loop/review.yaml +15 -0
  344. package/examples/feedback-loop/send-back-once.task.yaml +6 -0
  345. package/examples/feedback-loop/submit.yaml +12 -0
  346. package/examples/generic-fan-in/README.md +151 -0
  347. package/examples/generic-fan-in/clarify.yaml +18 -0
  348. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
  349. package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
  350. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
  351. package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
  352. package/examples/generic-fan-in/research.yaml +45 -0
  353. package/examples/generic-fan-in/synthesize.yaml +66 -0
  354. package/examples/generic-fan-in/validation.yaml +45 -0
  355. package/examples/github-release/README.md +78 -0
  356. package/examples/github-release/draft-release-notes.yaml +64 -0
  357. package/examples/github-release/github-release.pipeline.yaml +11 -0
  358. package/examples/github-release/github-release.task.yaml +13 -0
  359. package/examples/github-release/publish-github-release.yaml +64 -0
  360. package/examples/hello-world/README.md +28 -0
  361. package/examples/hello-world/hello.pipeline.yaml +4 -0
  362. package/examples/hello-world/my-task.task.yaml +6 -0
  363. package/examples/hello-world/research.yaml +18 -0
  364. package/examples/mcp-hitl-tour/README.md +113 -0
  365. package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
  366. package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
  367. package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
  368. package/examples/mcp-hitl-tour/gather.yaml +31 -0
  369. package/examples/mcp-hitl-tour/intake.yaml +62 -0
  370. package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
  371. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
  372. package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
  373. package/examples/mcp-hitl-tour/polish.yaml +33 -0
  374. package/examples/mcp-hitl-tour/review.yaml +17 -0
  375. package/examples/mcp-hitl-tour/ship.yaml +25 -0
  376. package/examples/oss-issue-contribution/README.md +218 -0
  377. package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
  378. package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
  379. package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
  380. package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
  381. package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
  382. package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
  383. package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
  384. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
  385. package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
  386. package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
  387. package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
  388. package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
  389. package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
  390. package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
  391. package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
  392. package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
  393. package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
  394. package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
  395. package/examples/oss-quick-fix/README.md +65 -0
  396. package/examples/oss-quick-fix/implement-fix.yaml +84 -0
  397. package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
  398. package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
  399. package/examples/oss-quick-fix/ship-fix.yaml +81 -0
  400. package/examples/oss-quick-fix/understand-issue.yaml +67 -0
  401. package/examples/oss-quick-fix/verify-fix.yaml +73 -0
  402. package/examples/plan-review/README.md +37 -0
  403. package/examples/plan-review/plan-review-followup.yaml +13 -0
  404. package/examples/plan-review/plan-review.pipeline.yaml +9 -0
  405. package/examples/plan-review/plan-review.task.yaml +9 -0
  406. package/examples/plan-review/plan-review.yaml +25 -0
  407. package/examples/playwright-mcp/README.md +39 -0
  408. package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
  409. package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
  410. package/examples/playwright-mcp/screenshot.yaml +40 -0
  411. package/examples/retry-tour/README.md +75 -0
  412. package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
  413. package/examples/retry-tour/retry-tour.task.yaml +9 -0
  414. package/examples/route-if-tour/README.md +202 -0
  415. package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
  416. package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
  417. package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
  418. package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
  419. package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
  420. package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
  421. package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
  422. package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
  423. package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
  424. package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
  425. package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
  426. package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
  427. package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
  428. package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
  429. package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
  430. package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
  431. package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
  432. package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
  433. package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
  434. package/examples/route-wiring-smoke-test/README.md +377 -0
  435. package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
  436. package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
  437. package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
  438. package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
  439. package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
  440. package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
  441. package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
  442. package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
  443. package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
  444. package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
  445. package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
  446. package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
  447. package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
  448. package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
  449. package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
  450. package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
  451. package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
  452. package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
  453. package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
  454. package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
  455. package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
  456. package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
  457. package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
  458. package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
  459. package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
  460. package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
  461. package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
  462. package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
  463. package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
  464. package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
  465. package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
  466. package/examples/ship-feature/README.md +190 -0
  467. package/examples/ship-feature/feat-address-feedback.yaml +119 -0
  468. package/examples/ship-feature/feat-implement.yaml +180 -0
  469. package/examples/ship-feature/feat-plan.yaml +120 -0
  470. package/examples/ship-feature/feat-review.yaml +109 -0
  471. package/examples/ship-feature/feat-ship.yaml +203 -0
  472. package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
  473. package/examples/ship-feature/ship-feature.task.yaml +78 -0
  474. package/examples/stage-mcp/README.md +144 -0
  475. package/examples/stage-mcp/echo-mcp.mjs +20 -0
  476. package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
  477. package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
  478. package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
  479. package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
  480. package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
  481. package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
  482. package/examples/stage-mcp/use-echo.yaml +20 -0
  483. package/examples/verify-tour/README.md +80 -0
  484. package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
  485. package/examples/verify-tour/verify-tour.task.yaml +11 -0
  486. package/package.json +5 -1
  487. package/skills/stageflow/SKILL.md +6 -6
  488. package/skills/stageflow/references/control-surface.md +11 -5
  489. package/skills/stageflow/scripts/detect-host.mjs +14 -1
  490. package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
  491. package/skills/stageflow-author/SKILL.md +4 -3
  492. package/skills/stageflow-author/references/catalog-mapping.md +16 -0
  493. package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
  494. package/skills/stageflow-run/SKILL.md +20 -12
  495. package/skills/stageflow-run/references/mcp-call.md +9 -1
  496. package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
  497. package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
  498. package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
  499. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
  500. package/skills/stageflow-setup/SKILL.md +40 -8
  501. package/dist/ui/assets/index-Da5EHU6M.js +0 -119
@@ -12,6 +12,7 @@ import { recoveryRequiresCompletionIssue } from "./parseCompletionContract.js";
12
12
  import { validateCompletionContractForStage } from "./validateCompletionContract.js";
13
13
  import { applyCloneChains } from "./cloneChain.js";
14
14
  import { collectRouteIfSchemaIssues, collectRouteIfIllegalCombos, collectRouteAllGatedWarnings, } from "./routeIf.js";
15
+ import { mergeToolRequires } from "./toolRequires.js";
15
16
  function schemaCompileIssue(stageId, field, err, pipelineId) {
16
17
  const message = err instanceof Error ? err.message : String(err);
17
18
  if (err instanceof UnresolvedSchemaRefError) {
@@ -128,7 +129,7 @@ export async function loadPipelineFromObject(raw, options = {}) {
128
129
  }
129
130
  async function buildLoadedPipelineFromMerge(merge, options) {
130
131
  const { projectRoot, requireIo, pipelinePath } = options;
131
- const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, warnings: mergeWarnings, } = merge;
132
+ const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, requires: pipelineRequires, warnings: mergeWarnings, } = merge;
132
133
  const ctx = { pipelineId, path: pipelinePath };
133
134
  const warnings = [...mergeWarnings];
134
135
  const normalizeOutcome = normalizePipelineStageEntries(rawEntries, ctx);
@@ -181,7 +182,14 @@ async function buildLoadedPipelineFromMerge(merge, options) {
181
182
  if (!inlineOutcome.ok) {
182
183
  return loadFailure(inlineOutcome.issues);
183
184
  }
184
- stages.push(inlineOutcome.value);
185
+ let stage = inlineOutcome.value;
186
+ if (entry.requires !== undefined) {
187
+ const merged = mergeToolRequires([stage.requires, entry.requires], { pipelineId, label: `stage "${entry.id}"` });
188
+ if (!merged.ok)
189
+ return loadFailure(merged.issues);
190
+ stage = { ...stage, requires: merged.value };
191
+ }
192
+ stages.push(stage);
185
193
  stageSources[stageId] = { kind: "inline" };
186
194
  continue;
187
195
  }
@@ -229,10 +237,19 @@ async function buildLoadedPipelineFromMerge(merge, options) {
229
237
  },
230
238
  ]);
231
239
  }
240
+ let stageRequires = stageOutcome.value.requires;
241
+ if (entry.requires !== undefined) {
242
+ const merged = mergeToolRequires([stageRequires, entry.requires], { pipelineId, label: `stage "${entry.id}"` });
243
+ if (!merged.ok)
244
+ return loadFailure(merged.issues);
245
+ stageRequires = merged.value;
246
+ }
232
247
  const stage = {
233
248
  ...stageOutcome.value,
234
249
  ...(entry.skill !== undefined ? { skill: entry.skill } : {}),
235
250
  ...(entry.mcp !== undefined ? { mcp: entry.mcp } : {}),
251
+ ...(entry.secrets !== undefined ? { secrets: entry.secrets } : {}),
252
+ ...(stageRequires !== undefined ? { requires: stageRequires } : {}),
236
253
  };
237
254
  stages.push(stage);
238
255
  stageSources[stageId] = { kind: "file", path: entry.body.absolutePath };
@@ -282,7 +299,11 @@ async function buildLoadedPipelineFromMerge(merge, options) {
282
299
  ...(pipelineAgent !== undefined ? { agent: pipelineAgent } : {}),
283
300
  ...(pipelineModel !== undefined ? { model: pipelineModel } : {}),
284
301
  ...(pipelineSchemas !== undefined ? { schemas: pipelineSchemas } : {}),
302
+ ...(pipelineRequires !== undefined ? { requires: pipelineRequires } : {}),
285
303
  };
304
+ const effectiveRequires = mergeToolRequires([pipelineRequires, ...loadedStages.map((s) => s.requires)], { pipelineId });
305
+ if (!effectiveRequires.ok)
306
+ return loadFailure(effectiveRequires.issues);
286
307
  const nodeById = new Map(dag.nodes.map((node) => [node.id, node]));
287
308
  for (const [stageId, after] of fileAfterById) {
288
309
  const node = nodeById.get(stageId);
@@ -7,6 +7,8 @@ import { parseModelField } from "./modelField.js";
7
7
  import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
8
8
  import { parsePreEmitChecks } from "./parsePreEmitChecks.js";
9
9
  import { readYamlObject } from "./readYamlObject.js";
10
+ import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
11
+ import { parseToolRequires } from "./toolRequires.js";
10
12
  import { classifyYamlDocument, compileTargetContract, dialectFromKeys, mixedDialectIssue, STAGE_FILE_WIRING_KEYS, } from "./yamlDialect.js";
11
13
  const afterCompletionByStage = new WeakMap();
12
14
  /** After-phase IR from target `verify` (`when` includes after). Stamped onto DAG `completion`. */
@@ -348,6 +350,22 @@ function parseStageFields(raw, label, entryId, deferSchemaRefs, requireIo, compi
348
350
  if (mcpOutcome.value !== undefined) {
349
351
  stage.mcp = mcpOutcome.value;
350
352
  }
353
+ const secretsOutcome = parseStageSecrets(raw.secrets, label, entryId);
354
+ if (!secretsOutcome.ok)
355
+ return secretsOutcome;
356
+ if (secretsOutcome.value !== undefined) {
357
+ stage.secrets = secretsOutcome.value;
358
+ }
359
+ const requiresOutcome = parseToolRequires(raw.requires, `stage ${label}`, {
360
+ code: "stage.invalid_requires",
361
+ category: "stage",
362
+ stageId: entryId,
363
+ });
364
+ if (!requiresOutcome.ok)
365
+ return requiresOutcome;
366
+ if (requiresOutcome.value !== undefined) {
367
+ stage.requires = requiresOutcome.value;
368
+ }
351
369
  const agentField = parseAgentField(raw.agent);
352
370
  if (!agentField.ok) {
353
371
  return loadFailure([
@@ -1,5 +1,7 @@
1
1
  import type { TaskFile } from "../types/task.js";
2
2
  import { type LoadOutcome } from "./loadOutcome.js";
3
+ /** Structural TaskFile shape only — does not enforce workspace binding XOR. */
4
+ export declare function coerceTaskFile(raw: unknown): TaskFile | undefined;
3
5
  export declare function parseTaskFile(raw: unknown, source?: string): LoadOutcome<TaskFile>;
4
6
  export declare function loadTaskFromYamlOutcome(yamlText: string, source?: string): LoadOutcome<TaskFile>;
5
7
  export declare function loadTaskOutcome(filePath: string): Promise<LoadOutcome<TaskFile>>;
@@ -1,12 +1,60 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { parse as parseYaml } from "yaml";
3
+ import { resolveWorkspaceBinding } from "../runtime/workspaceBinding.js";
3
4
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
4
5
  function isPlainObject(value) {
5
6
  return typeof value === "object" && value !== null && !Array.isArray(value);
6
7
  }
7
- export function parseTaskFile(raw, source = "task") {
8
+ function parseGitIdentity(raw) {
9
+ if (!isPlainObject(raw))
10
+ return undefined;
11
+ const identity = {};
12
+ if (typeof raw.name === "string")
13
+ identity.name = raw.name;
14
+ if (typeof raw.email === "string")
15
+ identity.email = raw.email;
16
+ return identity;
17
+ }
18
+ /** Structural TaskFile shape only — does not enforce workspace binding XOR. */
19
+ export function coerceTaskFile(raw) {
8
20
  const record = raw;
9
21
  if (typeof record?.id !== "string" || typeof record?.goal !== "string") {
22
+ return undefined;
23
+ }
24
+ if (record.input !== undefined && !isPlainObject(record.input)) {
25
+ return undefined;
26
+ }
27
+ return {
28
+ id: record.id,
29
+ goal: record.goal,
30
+ context: typeof record.context === "string" ? record.context : undefined,
31
+ constraints: typeof record.constraints === "string" ? record.constraints : undefined,
32
+ checkout: typeof record.checkout === "string" ? record.checkout : undefined,
33
+ ...(typeof record.repository === "string" ? { repository: record.repository } : {}),
34
+ ...(typeof record.ref === "string" ? { ref: record.ref } : {}),
35
+ ...(typeof record.run_branch_template === "string"
36
+ ? { run_branch_template: record.run_branch_template }
37
+ : {}),
38
+ ...(isPlainObject(record.git_identity)
39
+ ? { git_identity: parseGitIdentity(record.git_identity) }
40
+ : {}),
41
+ ...(record.input !== undefined ? { input: record.input } : {}),
42
+ };
43
+ }
44
+ export function parseTaskFile(raw, source = "task") {
45
+ const record = raw;
46
+ const task = coerceTaskFile(raw);
47
+ if (task === undefined) {
48
+ if (typeof record?.id === "string" && typeof record?.goal === "string") {
49
+ return loadFailure([
50
+ {
51
+ code: "task.invalid_shape",
52
+ message: `Invalid ${source}: input must be an object`,
53
+ category: "task",
54
+ taskId: record.id,
55
+ },
56
+ ]);
57
+ }
10
58
  return loadFailure([
11
59
  {
12
60
  code: "task.invalid_shape",
@@ -16,24 +64,15 @@ export function parseTaskFile(raw, source = "task") {
16
64
  },
17
65
  ]);
18
66
  }
19
- if (record.input !== undefined && !isPlainObject(record.input)) {
20
- return loadFailure([
21
- {
22
- code: "task.invalid_shape",
23
- message: `Invalid ${source}: input must be an object`,
24
- category: "task",
25
- taskId: record.id,
26
- },
27
- ]);
67
+ const binding = resolveWorkspaceBinding(task);
68
+ if (!binding.ok) {
69
+ return loadFailure(binding.issues.map((issue) => {
70
+ if (issue.category !== "task")
71
+ return issue;
72
+ return { ...issue, taskId: task.id };
73
+ }));
28
74
  }
29
- return loadSuccess({
30
- id: record.id,
31
- goal: record.goal,
32
- context: typeof record.context === "string" ? record.context : undefined,
33
- constraints: typeof record.constraints === "string" ? record.constraints : undefined,
34
- checkout: typeof record.checkout === "string" ? record.checkout : undefined,
35
- ...(record.input !== undefined ? { input: record.input } : {}),
36
- });
75
+ return loadSuccess(task);
37
76
  }
38
77
  export function loadTaskFromYamlOutcome(yamlText, source = "task yaml") {
39
78
  let raw;
@@ -29,7 +29,11 @@ export async function materializeStageModels(stages, options) {
29
29
  if (!modelOutcome.ok) {
30
30
  return loadFailure(modelOutcome.issues);
31
31
  }
32
- materialized.push({ ...stage, model: modelOutcome.value });
32
+ materialized.push({
33
+ ...stage,
34
+ model: modelOutcome.value.model,
35
+ model_tier: modelOutcome.value.tier,
36
+ });
33
37
  }
34
38
  return loadSuccess(materialized);
35
39
  }
@@ -1,6 +1,7 @@
1
1
  import type { PayloadSchemaMap } from "../envelope/payloadSchema.js";
2
2
  import type { InlinePipelineDefinition } from "../types/pipeline.js";
3
3
  import { type LoadIssue, type LoadOutcome } from "./loadOutcome.js";
4
+ import { type ToolRequirement } from "./toolRequires.js";
4
5
  export type RawMergedEntry = {
5
6
  raw: unknown;
6
7
  declaringPath: string;
@@ -11,6 +12,7 @@ export declare function mergePipelineStages(rootPath: string): Promise<LoadOutco
11
12
  agent?: string;
12
13
  model?: string;
13
14
  schemas?: PayloadSchemaMap;
15
+ requires?: ToolRequirement[];
14
16
  warnings: LoadIssue[];
15
17
  }>>;
16
18
  /** Synthetic `declaringPath` for stage entries with no backing file. */
@@ -21,5 +23,6 @@ export declare function mergeInlinePipelineStages(raw: InlinePipelineDefinition)
21
23
  agent?: string;
22
24
  model?: string;
23
25
  schemas?: PayloadSchemaMap;
26
+ requires?: ToolRequirement[];
24
27
  warnings: LoadIssue[];
25
28
  }>>;
@@ -4,6 +4,7 @@ import { loadFailure, loadSuccess } from "./loadOutcome.js";
4
4
  import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
5
5
  import { parseModelField } from "./modelField.js";
6
6
  import { readYamlObject } from "./readYamlObject.js";
7
+ import { parseToolRequires } from "./toolRequires.js";
7
8
  import { classifyYamlDocument, collectDocumentKeys, mixedDialectIssue, } from "./yamlDialect.js";
8
9
  function isPlainObject(value) {
9
10
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -177,6 +178,14 @@ export async function mergePipelineStages(rootPath) {
177
178
  if (!schemasOutcome.ok)
178
179
  return schemasOutcome;
179
180
  const schemas = schemasOutcome.value;
181
+ const requiresOutcome = parseToolRequires(raw.requires, `pipeline ${absRoot}`, {
182
+ code: "pipeline.invalid_requires",
183
+ category: "pipeline",
184
+ pipelineId,
185
+ });
186
+ if (!requiresOutcome.ok)
187
+ return requiresOutcome;
188
+ const requires = requiresOutcome.value;
180
189
  const idLocations = new Map();
181
190
  const entries = [];
182
191
  const warnings = [];
@@ -198,6 +207,7 @@ export async function mergePipelineStages(rootPath) {
198
207
  ...(agent !== undefined ? { agent } : {}),
199
208
  ...(model !== undefined ? { model } : {}),
200
209
  ...(schemas !== undefined ? { schemas } : {}),
210
+ ...(requires !== undefined ? { requires } : {}),
201
211
  warnings,
202
212
  });
203
213
  }
@@ -252,6 +262,14 @@ export async function mergeInlinePipelineStages(raw) {
252
262
  if (!schemasOutcome.ok)
253
263
  return schemasOutcome;
254
264
  const schemas = schemasOutcome.value;
265
+ const requiresOutcome = parseToolRequires(raw.requires, `inline pipeline ${pipelineId}`, {
266
+ code: "pipeline.invalid_requires",
267
+ category: "pipeline",
268
+ pipelineId,
269
+ });
270
+ if (!requiresOutcome.ok)
271
+ return requiresOutcome;
272
+ const requires = requiresOutcome.value;
255
273
  const entries = [];
256
274
  for (let index = 0; index < raw.stages.length; index++) {
257
275
  const entry = raw.stages[index];
@@ -273,6 +291,7 @@ export async function mergeInlinePipelineStages(raw) {
273
291
  ...(agent !== undefined ? { agent } : {}),
274
292
  ...(model !== undefined ? { model } : {}),
275
293
  ...(schemas !== undefined ? { schemas } : {}),
294
+ ...(requires !== undefined ? { requires } : {}),
276
295
  warnings: [],
277
296
  });
278
297
  }
@@ -1,7 +1,8 @@
1
- import { execFileSync } from "node:child_process";
2
1
  import { randomBytes } from "node:crypto";
3
2
  import { readdir, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
4
3
  import path from "node:path";
4
+ import { runGitSync } from "../git/exec.js";
5
+ import { statusPorcelain } from "../git/operations.js";
5
6
  import { loadPipelineOutcome } from "./loadPipeline.js";
6
7
  import { afterCompletionForStage, loadStageOutcome } from "./loadStage.js";
7
8
  import { withLegacyYamlAllowedAsync } from "./legacyYaml.js";
@@ -104,11 +105,10 @@ function verifyFingerprint(items) {
104
105
  }
105
106
  function gitToplevel(cwd) {
106
107
  try {
107
- return execFileSync("git", ["rev-parse", "--show-toplevel"], {
108
+ return runGitSync({
108
109
  cwd,
109
- encoding: "utf8",
110
- stdio: ["ignore", "pipe", "ignore"],
111
- }).trim();
110
+ args: ["rev-parse", "--show-toplevel"],
111
+ }).stdout.trim();
112
112
  }
113
113
  catch {
114
114
  return null;
@@ -119,12 +119,7 @@ export function fileDirtyVsHead(absPath) {
119
119
  if (top === null)
120
120
  return true;
121
121
  try {
122
- const status = execFileSync("git", ["status", "--porcelain", "--", absPath], {
123
- cwd: top,
124
- encoding: "utf8",
125
- stdio: ["ignore", "pipe", "ignore"],
126
- });
127
- return status.trim().length > 0;
122
+ return statusPorcelain(top, absPath).trim().length > 0;
128
123
  }
129
124
  catch {
130
125
  return true;
@@ -0,0 +1,30 @@
1
+ import { type PipelineListing, type TaskListing } from "./browseCatalog.js";
2
+ import { type CatalogRoot, type ResolveCatalogRootsOptions } from "./resolveCatalogRoots.js";
3
+ export type CatalogRootError = {
4
+ project_root: string;
5
+ code: "catalog_root_unreadable" | "unknown_project_root";
6
+ message: string;
7
+ };
8
+ export type MultiProjectListResult<T> = {
9
+ items: T[];
10
+ root_errors: CatalogRootError[];
11
+ roots: CatalogRoot[];
12
+ };
13
+ export declare function listPipelinesMultiProject(options: ResolveCatalogRootsOptions & {
14
+ projectRootFilter?: string;
15
+ }): Promise<MultiProjectListResult<PipelineListing & {
16
+ project_root: string;
17
+ }>>;
18
+ export declare function listTasksMultiProject(options: ResolveCatalogRootsOptions & {
19
+ projectRootFilter?: string;
20
+ }): Promise<MultiProjectListResult<TaskListing & {
21
+ project_root: string;
22
+ }>>;
23
+ export declare function listModelsMultiProject(options: ResolveCatalogRootsOptions & {
24
+ projectRootFilter?: string;
25
+ }): Promise<MultiProjectListResult<{
26
+ id: string;
27
+ project_root: string;
28
+ }> & {
29
+ models: string[];
30
+ }>;
@@ -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
+ }