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
@@ -1,39 +1,49 @@
1
- import path from "node:path";
2
1
  import { z } from "zod";
3
- import { browseCatalog, } from "../config/browseCatalog.js";
2
+ import { catalogPathErrorBody, CatalogPathError, resolveCatalogRelativePath, resolveCatalogStartInput, selectCatalogRootForStart, } from "../config/catalogRelativePath.js";
3
+ import { listModelsMultiProject, listPipelinesMultiProject, listTasksMultiProject, } from "../config/multiProjectCatalog.js";
4
+ import { resolveCatalogRoots } from "../config/resolveCatalogRoots.js";
4
5
  import { describePipeline } from "../config/describePipeline.js";
5
6
  import { loadPipeline } from "../config/loadPipeline.js";
6
7
  import { readYamlObject } from "../config/readYamlObject.js";
7
8
  import { validateCatalog } from "../config/validateCatalog.js";
8
- import { PACKAGE_VERSION } from "../package-meta.js";
9
- import { findProjectRoot } from "../project/findProjectRoot.js";
9
+ import { writeAudit } from "../logging/audit.js";
10
+ import { logger as rootLogger } from "../logging/logger.js";
11
+ import { PACKAGE_VERSION, BUILD_SHA } from "../package-meta.js";
10
12
  import { PipelineValidationError } from "../runtime/pipelineValidationError.js";
13
+ import { PipelinePreflightError } from "../runtime/pipelineRunner.js";
11
14
  import { EnvelopeRefError, resolveEnvelopeRefsToTask, } from "../runtime/resolveEnvelopeRef.js";
12
15
  import { isTerminalProjection, isWaitingProjection, waitRun } from "./waitRun.js";
13
16
  import { mapStoreLookupError } from "../server/operatorResults.js";
17
+ import { callerIdFromRequestAuth, getRequestAuth, } from "../server/requestAuthContext.js";
14
18
  import { projectRunForMcp } from "./projectRun.js";
15
19
  import { classifyArtifactContent, readRunArtifactBytes } from "./readArtifact.js";
16
20
  import { imageResult, textResult } from "./toolResults.js";
17
- /**
18
- * Every project a host serving a global store has ever recorded a run for,
19
- * plus this host's own launch directory (always included so a project with
20
- * zero runs yet still sees its own catalog).
21
- */
22
- async function catalogRootsFor(deps) {
23
- const known = await deps.store.listProjectRoots();
24
- return [...new Set([...known, deps.cwd])];
25
- }
26
- /** Resolve which project a given catalog path (pipeline/task) belongs to. */
27
- function projectRootForPath(deps, catalogPath) {
28
- const absDir = path.dirname(path.resolve(deps.cwd, catalogPath));
29
- return findProjectRoot(absDir) ?? deps.cwd;
30
- }
21
+ import { buildRunExportPayload } from "../runstore/exportRunPayload.js";
22
+ import { redactRunManifestForRead } from "../runstore/runManifest.js";
23
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
24
+ import { runSkillsDir } from "../runtime/runSkills.js";
25
+ import { listSkillsWithOrigin } from "../config/listSkills.js";
26
+ import { findTokenShapedField, pickCheckoutOverride, tokenRejectedPayload, } from "../runtime/startPayload.js";
27
+ import { loadPipelineFromObjectOutcome, loadPipelineOutcome, } from "../config/loadPipeline.js";
28
+ import { preflightFailureCode, runPipelinePreflight, } from "../preflight/pipelinePreflight.js";
29
+ import { toolchainHealthMap } from "../preflight/toolchain.js";
30
+ const auditLog = rootLogger.child({ component: "audit" });
31
+ const gitIdentitySchema = z
32
+ .object({
33
+ name: z.string().optional(),
34
+ email: z.string().optional(),
35
+ })
36
+ .strict();
31
37
  const taskFileSchema = z.object({
32
38
  id: z.string(),
33
39
  goal: z.string(),
34
40
  context: z.string().optional(),
35
41
  constraints: z.string().optional(),
36
42
  checkout: z.string().optional(),
43
+ repository: z.string().optional(),
44
+ ref: z.string().optional(),
45
+ run_branch_template: z.string().optional(),
46
+ git_identity: gitIdentitySchema.optional(),
37
47
  input: z.record(z.string(), z.unknown()).optional(),
38
48
  });
39
49
  /**
@@ -50,16 +60,35 @@ const inlinePipelineSchema = z
50
60
  agent: z.unknown().optional(),
51
61
  model: z.unknown().optional(),
52
62
  schemas: z.unknown().optional(),
63
+ requires: z.unknown().optional(),
53
64
  })
54
65
  .strict();
55
66
  const startRunSchema = z
56
67
  .object({
57
68
  pipeline: z
58
69
  .union([z.string(), inlinePipelineSchema])
59
- .describe("Filesystem path to a pipeline YAML file, or an inline pipeline definition object ({ id, stages: [...] }) authored directly in this call"),
70
+ .describe("Catalog-relative pipeline path, or an inline pipeline definition object ({ id, stages: [...] }) authored directly in this call"),
60
71
  task_path: z.string().optional(),
61
72
  task: taskFileSchema.optional(),
73
+ project_root: z.string().optional(),
74
+ checkout: z
75
+ .string()
76
+ .optional()
77
+ .describe("Catalog-relative checkout path (maps to RunManager checkoutOverride); absolute paths are rejected with absolute_path_not_allowed"),
78
+ checkout_override: z
79
+ .string()
80
+ .optional()
81
+ .describe("Alias of checkout; prefer checkout"),
82
+ skip_gates: z.boolean().optional(),
83
+ git_sha: z.string().optional(),
84
+ ci_pr_url: z.string().optional(),
85
+ ci_job_url: z.string().optional(),
86
+ skills: z
87
+ .record(z.string(), z.record(z.string(), z.string()))
88
+ .optional()
89
+ .describe("Run-scoped skills: name → { relativePath: utf-8 contents }. Requires SKILL.md per name; materialised under the run workspace skills dir (never the worktree)"),
62
90
  })
91
+ .passthrough()
63
92
  .refine((data) => Boolean(data.task_path) !== Boolean(data.task), {
64
93
  message: "Exactly one of task_path or task is required",
65
94
  });
@@ -77,7 +106,11 @@ const runStageSchema = z
77
106
  .object({
78
107
  stage: z
79
108
  .union([z.string(), z.record(z.string(), z.unknown())])
80
- .describe("Filesystem path to a stage YAML file, or a bare inline stage body object ({ id, system_prompt, io, model?, gate_kinds?, mcp?, verify?, timeout_ms? } — no uses:/route/pipeline wrapper) authored directly in this call"),
109
+ .describe("Catalog-relative path to a stage YAML file (same path contract as start_run — absolute paths rejected, must be inside a registered project_root), or a bare inline stage body object ({ id, system_prompt, io, model?, gate_kinds?, mcp?, verify?, timeout_ms? } — no uses:/route/pipeline wrapper) authored directly in this call"),
110
+ project_root: z
111
+ .string()
112
+ .optional()
113
+ .describe("Catalog project root to resolve a string stage path against; required when multiple catalog roots are configured and no sole non-seeded root exists"),
81
114
  task_path: z.string().optional(),
82
115
  task: taskFileSchema.optional(),
83
116
  envelope_ref: z
@@ -102,62 +135,132 @@ const runStageSchema = z
102
135
  .describe("Wait budget in ms when blocking is true (same bounds as wait_run)"),
103
136
  })
104
137
  .refine((data) => [data.task_path, data.task, data.envelope_ref].filter(Boolean).length === 1, { message: "Exactly one of task_path, task, or envelope_ref is required" });
105
- const runStatusSchema = z.enum(["created", "running", "succeeded", "failed"]);
138
+ const runStatusSchema = z.enum([
139
+ "created",
140
+ "queued",
141
+ "running",
142
+ "succeeded",
143
+ "failed",
144
+ "cancelled",
145
+ ]);
106
146
  export function registerCatalogTools(server, deps) {
107
147
  const { manager, store, cwd } = deps;
108
- server.registerTool("list_pipelines", {
109
- description: "List manifest-declared pipeline paths across every project this host knows about (this host's own project plus any project a run has ever been recorded for). Each entry is tagged with project_root. A project with no runs yet won't appear until its first run exists.",
110
- inputSchema: z.object({}),
111
- }, async () => {
112
- const roots = await catalogRootsFor(deps);
113
- const pipelines = [];
114
- for (const root of roots) {
115
- try {
116
- const catalog = await browseCatalog(root);
117
- for (const p of catalog.pipelines) {
118
- pipelines.push({ ...p, project_root: root });
119
- }
148
+ const agentDir = deps.agentDir ?? getAgentDir();
149
+ server.registerTool("list_skills", {
150
+ description: "List skills with name, description, and origin (run|checkout|host). Optional runId scopes to that run's resolution view (run-tier skills first, then checkout .pi/skills, then host).",
151
+ inputSchema: z.object({
152
+ runId: z.string().optional(),
153
+ }),
154
+ }, async ({ runId }) => {
155
+ try {
156
+ let runSkills;
157
+ let checkoutRoot;
158
+ if (runId !== undefined) {
159
+ const meta = await store.readRunMeta(runId);
160
+ runSkills = runSkillsDir(store.getWorkspaceDir(runId));
161
+ checkoutRoot = meta.checkout_root;
120
162
  }
121
- catch {
122
- // stale/unreadable project root recorded on an old run; skip it
163
+ const catalog = await listSkillsWithOrigin({
164
+ cwd,
165
+ agentDir,
166
+ ...(runSkills !== undefined ? { runSkillsDir: runSkills } : {}),
167
+ ...(checkoutRoot !== undefined ? { checkoutRoot } : {}),
168
+ });
169
+ return textResult({
170
+ skills: catalog.skills,
171
+ diagnostics: catalog.diagnostics,
172
+ });
173
+ }
174
+ catch (err) {
175
+ if (runId !== undefined) {
176
+ const mapped = mapStoreLookupError(err, { policy: "run" });
177
+ return textResult({ error: mapped.error, status: mapped.status }, true);
123
178
  }
179
+ throw err;
180
+ }
181
+ });
182
+ server.registerTool("list_pipelines", {
183
+ description: "List manifest-declared pipeline paths across every project this host knows about (registered store roots and seeded roots). Each entry is tagged with project_root. Optional project_root filter narrows; unknown value returns unknown_project_root.",
184
+ inputSchema: z.object({
185
+ project_root: z.string().optional(),
186
+ }),
187
+ }, async ({ project_root }) => {
188
+ const result = await listPipelinesMultiProject({
189
+ store,
190
+ bootCwd: cwd,
191
+ projectRootFilter: project_root,
192
+ });
193
+ if (result.root_errors.some((e) => e.code === "unknown_project_root") &&
194
+ result.items.length === 0) {
195
+ return textResult({
196
+ error: result.root_errors[0].message,
197
+ code: "unknown_project_root",
198
+ root_errors: result.root_errors,
199
+ }, true);
124
200
  }
125
- return textResult({ pipelines });
201
+ return textResult({
202
+ pipelines: result.items,
203
+ root_errors: result.root_errors,
204
+ });
126
205
  });
127
206
  server.registerTool("list_tasks", {
128
- description: "List manifest-declared task paths across every project this host knows about (this host's own project plus any project a run has ever been recorded for). Each entry is tagged with project_root. A project with no runs yet won't appear until its first run exists.",
129
- inputSchema: z.object({}),
130
- }, async () => {
131
- const roots = await catalogRootsFor(deps);
132
- const tasks = [];
133
- for (const root of roots) {
134
- try {
135
- const catalog = await browseCatalog(root);
136
- for (const t of catalog.tasks) {
137
- tasks.push({ ...t, project_root: root });
138
- }
139
- }
140
- catch {
141
- // stale/unreadable project root recorded on an old run; skip it
142
- }
207
+ description: "List manifest-declared task paths across every project this host knows about (registered store roots and seeded roots). Each entry is tagged with project_root. Optional project_root filter narrows; unknown value returns unknown_project_root.",
208
+ inputSchema: z.object({
209
+ project_root: z.string().optional(),
210
+ }),
211
+ }, async ({ project_root }) => {
212
+ const result = await listTasksMultiProject({
213
+ store,
214
+ bootCwd: cwd,
215
+ projectRootFilter: project_root,
216
+ });
217
+ if (result.root_errors.some((e) => e.code === "unknown_project_root") &&
218
+ result.items.length === 0) {
219
+ return textResult({
220
+ error: result.root_errors[0].message,
221
+ code: "unknown_project_root",
222
+ root_errors: result.root_errors,
223
+ }, true);
143
224
  }
144
- return textResult({ tasks });
225
+ return textResult({
226
+ tasks: result.items,
227
+ root_errors: result.root_errors,
228
+ });
145
229
  });
146
230
  server.registerTool("list_models", {
147
- description: "List catalog model ids from the project catalog (same source as GET /api/models)",
148
- inputSchema: z.object({}),
149
- }, async () => {
150
- const catalog = await browseCatalog(cwd);
151
- return textResult({ models: catalog.models });
231
+ description: "List catalog model ids across every project this host knows about (same multi-root source as GET /api/models). Optional project_root filter narrows.",
232
+ inputSchema: z.object({
233
+ project_root: z.string().optional(),
234
+ }),
235
+ }, async ({ project_root }) => {
236
+ const result = await listModelsMultiProject({
237
+ store,
238
+ bootCwd: cwd,
239
+ projectRootFilter: project_root,
240
+ });
241
+ if (result.root_errors.some((e) => e.code === "unknown_project_root") &&
242
+ result.items.length === 0) {
243
+ return textResult({
244
+ error: result.root_errors[0].message,
245
+ code: "unknown_project_root",
246
+ root_errors: result.root_errors,
247
+ }, true);
248
+ }
249
+ return textResult({
250
+ models: result.models,
251
+ entries: result.items,
252
+ root_errors: result.root_errors,
253
+ });
152
254
  });
153
255
  server.registerTool("list_runs", {
154
- description: "List known pipeline runs. Optional filters: status, since (ISO created_at lower bound), pipeline (id or path).",
256
+ description: "List known pipeline runs. Optional filters: status, since (ISO created_at lower bound), pipeline (id or path), caller_id.",
155
257
  inputSchema: z.object({
156
258
  status: runStatusSchema.optional(),
157
259
  since: z.string().optional(),
158
260
  pipeline: z.string().optional(),
261
+ caller_id: z.string().optional(),
159
262
  }),
160
- }, async ({ status, since, pipeline }) => {
263
+ }, async ({ status, since, pipeline, caller_id }) => {
161
264
  const filter = {};
162
265
  if (status !== undefined)
163
266
  filter.status = status;
@@ -169,17 +272,106 @@ export function registerCatalogTools(server, deps) {
169
272
  }
170
273
  if (pipeline !== undefined)
171
274
  filter.pipeline = pipeline;
275
+ if (caller_id !== undefined)
276
+ filter.caller_id = caller_id;
172
277
  const runs = await store.listRuns(Object.keys(filter).length > 0 ? filter : undefined);
173
278
  return textResult({ runs });
174
279
  });
175
280
  server.registerTool("get_health", {
176
- description: "Server health and soft-max run capacity: activeRunIds, activeCount, maxConcurrent, slotsAvailable, version. Start until slotsAvailable is 0; then wait for a run to finish or raise STAGEFLOW_MAX_CONCURRENT_RUNS.",
281
+ description: "Server health and soft-max run capacity: activeRunIds, activeCount, maxConcurrent, slotsAvailable, activeStageProcesses, version, plus disk breakdown (disk.runs_bytes, worktrees_bytes, repos_bytes, state_db_bytes, a2a_artifacts_bytes, free_bytes) for the durable root. Start until slotsAvailable is 0; then wait for a run to finish or raise STAGEFLOW_MAX_CONCURRENT_RUNS.",
177
282
  inputSchema: z.object({}),
178
- }, async () => textResult({ ...manager.getHealth(), version: PACKAGE_VERSION }));
283
+ }, async () => textResult({
284
+ ...(await manager.getHealthWithDisk()),
285
+ version: PACKAGE_VERSION,
286
+ build_sha: BUILD_SHA,
287
+ toolchain: toolchainHealthMap(),
288
+ }));
289
+ server.registerTool("preflight", {
290
+ description: "Check pipeline requires:/secrets:/mcp against the Host toolchain manifest and curated stage env before start_run. Accepts pipeline path or inline definition (same union as start_run). Returns { ok, checks } with status ok|missing_tool|tool_version_mismatch|unknown_version|secret_unavailable|unresolved_var. Does not create a Run. unknown_version is ok unless strict:true.",
291
+ inputSchema: z.object({
292
+ pipeline: z
293
+ .union([z.string(), inlinePipelineSchema])
294
+ .describe("Catalog-relative pipeline path, or an inline pipeline definition object"),
295
+ project_root: z.string().optional(),
296
+ strict: z
297
+ .boolean()
298
+ .optional()
299
+ .describe("When true, unknown_version fails (default false)"),
300
+ }),
301
+ }, async ({ pipeline, project_root, strict }) => {
302
+ const roots = await resolveCatalogRoots({
303
+ store: deps.store,
304
+ bootCwd: deps.cwd,
305
+ });
306
+ let loaded;
307
+ let projectRoot;
308
+ try {
309
+ const wireRoot = selectCatalogRootForStart(roots, project_root);
310
+ projectRoot = wireRoot.project_root;
311
+ if (typeof pipeline === "string") {
312
+ const resolved = resolveCatalogRelativePath({
313
+ inputPath: pipeline,
314
+ projectRoot: project_root,
315
+ roots,
316
+ fieldName: "pipeline",
317
+ });
318
+ projectRoot = resolved.root.project_root;
319
+ const outcome = await loadPipelineOutcome(resolved.absolutePath, {
320
+ cwd: deps.cwd,
321
+ projectRoot,
322
+ });
323
+ if (!outcome.ok) {
324
+ return textResult({
325
+ ok: false,
326
+ error: outcome.issues[0]?.message ?? "pipeline load failed",
327
+ code: outcome.issues[0]?.code ?? "config_invalid",
328
+ issues: outcome.issues,
329
+ }, true);
330
+ }
331
+ loaded = outcome.value;
332
+ }
333
+ else {
334
+ const outcome = await loadPipelineFromObjectOutcome(pipeline, {
335
+ cwd: deps.cwd,
336
+ projectRoot,
337
+ });
338
+ if (!outcome.ok) {
339
+ return textResult({
340
+ ok: false,
341
+ error: outcome.issues[0]?.message ?? "pipeline load failed",
342
+ code: outcome.issues[0]?.code ?? "config_invalid",
343
+ issues: outcome.issues,
344
+ }, true);
345
+ }
346
+ loaded = outcome.value;
347
+ }
348
+ }
349
+ catch (err) {
350
+ if (err instanceof CatalogPathError) {
351
+ return textResult(catalogPathErrorBody(err), true);
352
+ }
353
+ throw err;
354
+ }
355
+ const result = await runPipelinePreflight(loaded, {
356
+ projectRoot,
357
+ strict: strict === true,
358
+ });
359
+ const code = preflightFailureCode(result, { strict: strict === true });
360
+ return textResult({
361
+ ok: result.ok,
362
+ checks: result.checks,
363
+ ...(code !== undefined ? { code } : {}),
364
+ });
365
+ });
179
366
  server.registerTool("start_run", {
180
- description: "Start a pipeline run using a filesystem pipeline path or an inline pipeline definition ({ id, stages: [...] }, each stage the same shape as a YAML stage body — no uses: refs), and either task_path (catalog task file) or an inline task object. Returns { runId }. On conflict returns isError with code busy_capacity (soft max full) or busy_checkout (same checkout leased), plus activeCount/maxConcurrent/activeRunIds and optional conflictingRunId/conflictingCheckout.",
367
+ description: "Start a pipeline run. Accepted params: pipeline (catalog-relative path or inline { id, stages: [...] } — stages are YAML stage bodies, no uses: refs), task_path XOR task (inline task may include repository/ref or checkout; repository XOR checkout with code task.binding_conflict), project_root, checkout (catalog-relative; prefer this name; absolute → absolute_path_not_allowed), checkout_override (alias of checkout), skip_gates, git_sha, ci_pr_url, ci_job_url, skills (name → { relativePath: utf-8 contents }; requires SKILL.md; materialised under runs/<runId>/skills/, never the worktree). REST POST /api/runs accepts path pipelines only (no inline pipeline). Returns { runId } or { runId, queued: true, queuePosition }. Errors: busy_capacity, busy_checkout, insufficient_disk, start.token_rejected, skills_*, inline_pipeline_too_large, catalog path-contract codes.",
181
368
  inputSchema: startRunSchema,
182
- }, async ({ pipeline, task_path, task }) => {
369
+ }, async (args) => {
370
+ const tokenField = findTokenShapedField(args);
371
+ if (tokenField !== undefined) {
372
+ return textResult(tokenRejectedPayload(tokenField), true);
373
+ }
374
+ const { pipeline, task_path, task, project_root, checkout, checkout_override, skip_gates, git_sha, ci_pr_url, ci_job_url, skills, } = args;
183
375
  if (typeof pipeline === "string" && !pipeline.trim()) {
184
376
  return textResult({ error: "pipeline is required" }, true);
185
377
  }
@@ -187,26 +379,130 @@ export function registerCatalogTools(server, deps) {
187
379
  if (taskInput === undefined) {
188
380
  return textResult({ error: "Exactly one of task_path or task is required" }, true);
189
381
  }
382
+ let wireRoot;
383
+ let roots;
384
+ try {
385
+ ({ wireRoot, roots } = await resolveCatalogStartInput({ store: deps.store, bootCwd: deps.cwd }, project_root));
386
+ }
387
+ catch (err) {
388
+ if (err instanceof CatalogPathError) {
389
+ return textResult(catalogPathErrorBody(err), true);
390
+ }
391
+ throw err;
392
+ }
393
+ const wireProjectRoot = wireRoot.project_root;
394
+ let resolvedPipeline = pipeline;
395
+ let resolvedTask = taskInput;
396
+ let resolvedCheckout;
397
+ try {
398
+ if (typeof pipeline === "string") {
399
+ resolvedPipeline = resolveCatalogRelativePath({
400
+ inputPath: pipeline,
401
+ projectRoot: wireProjectRoot,
402
+ roots,
403
+ fieldName: "pipeline",
404
+ }).absolutePath;
405
+ }
406
+ if (typeof task_path === "string") {
407
+ resolvedTask = resolveCatalogRelativePath({
408
+ inputPath: task_path,
409
+ projectRoot: wireProjectRoot,
410
+ roots,
411
+ fieldName: "task_path",
412
+ }).absolutePath;
413
+ }
414
+ const rawCheckout = pickCheckoutOverride({ checkout, checkout_override });
415
+ if (rawCheckout !== undefined) {
416
+ resolvedCheckout = resolveCatalogRelativePath({
417
+ inputPath: rawCheckout,
418
+ projectRoot: wireProjectRoot,
419
+ roots,
420
+ fieldName: "checkout",
421
+ }).absolutePath;
422
+ }
423
+ }
424
+ catch (err) {
425
+ if (err instanceof CatalogPathError) {
426
+ return textResult(catalogPathErrorBody(err), true);
427
+ }
428
+ throw err;
429
+ }
430
+ const callerId = callerIdFromRequestAuth();
190
431
  let result;
191
432
  try {
192
- result = await manager.startRun({ pipeline, task: taskInput });
433
+ result = await manager.startRun({
434
+ pipeline: resolvedPipeline,
435
+ task: resolvedTask,
436
+ projectRoot: wireRoot.path,
437
+ ...(resolvedCheckout !== undefined
438
+ ? { checkoutOverride: resolvedCheckout }
439
+ : {}),
440
+ ...(skip_gates !== undefined ? { skipGates: skip_gates } : {}),
441
+ ...(git_sha !== undefined ? { gitSha: git_sha } : {}),
442
+ ...(ci_pr_url !== undefined ? { ciPrUrl: ci_pr_url } : {}),
443
+ ...(ci_job_url !== undefined ? { ciJobUrl: ci_job_url } : {}),
444
+ ...(skills !== undefined ? { skills } : {}),
445
+ callerId,
446
+ });
193
447
  }
194
448
  catch (err) {
195
449
  if (err instanceof PipelineValidationError) {
450
+ writeAudit(auditLog, {
451
+ caller_id: callerId,
452
+ surface: getRequestAuth()?.surface ?? "mcp",
453
+ action: "start_run",
454
+ outcome: "error",
455
+ error_code: "pipeline_validation",
456
+ });
196
457
  return textResult({ error: "Pipeline validation failed", validation: err.result }, true);
197
458
  }
459
+ if (err instanceof PipelinePreflightError) {
460
+ writeAudit(auditLog, {
461
+ caller_id: callerId,
462
+ surface: getRequestAuth()?.surface ?? "mcp",
463
+ action: "start_run",
464
+ outcome: "error",
465
+ error_code: err.code,
466
+ });
467
+ return textResult(err.toNetworkBody(), true);
468
+ }
198
469
  throw err;
199
470
  }
200
471
  if (!result.ok) {
472
+ writeAudit(auditLog, {
473
+ caller_id: callerId,
474
+ surface: getRequestAuth()?.surface ?? "mcp",
475
+ action: "start_run",
476
+ outcome: "error",
477
+ error_code: result.code,
478
+ });
201
479
  const { ok: _ok, reason, ...rest } = result;
202
480
  return textResult({ error: reason, ...rest }, true);
203
481
  }
204
- return textResult({ runId: result.runId });
482
+ writeAudit(auditLog, {
483
+ caller_id: callerId,
484
+ surface: getRequestAuth()?.surface ?? "mcp",
485
+ action: "start_run",
486
+ target_run_id: result.runId,
487
+ outcome: "ok",
488
+ });
489
+ return textResult({
490
+ runId: result.runId,
491
+ ...(result.queued === true
492
+ ? {
493
+ queued: true,
494
+ queuePosition: result.queuePosition,
495
+ ...(result.queuedCode !== undefined
496
+ ? { queuedCode: result.queuedCode }
497
+ : {}),
498
+ }
499
+ : {}),
500
+ });
205
501
  });
206
502
  server.registerTool("run_stage", {
207
503
  description: "Run a single stage directly, without authoring a pipeline. `stage` is a filesystem path to a stage YAML file, or a bare inline stage body ({ id, system_prompt, io, model?, gate_kinds?, mcp?, verify?, timeout_ms? } — no uses:/route/pipeline wrapper), and exactly one of task_path, an inline task, or envelope_ref ({ runId, stageId, attempt? }) to resolve a previously stored envelope — from another run_stage call or any stage in a full pipeline run — as this stage's input. Internally this synthesizes a one-stage pipeline and executes it through the normal run path, so it shows up in list_runs/get_run and is polled with wait_run / get_envelope exactly like any other run. By default returns { runId, stageId } immediately (async); pass blocking:true to wait in this same call and get back { runId, stageId, status: \"completed\"|\"needs_input\"|\"timeout\", envelope? , pending_prompt? }.",
208
504
  inputSchema: runStageSchema,
209
- }, async ({ stage, task_path, task, envelope_ref, checkout, model, blocking, timeout_ms }) => {
505
+ }, async ({ stage, project_root, task_path, task, envelope_ref, checkout, model, blocking, timeout_ms }) => {
210
506
  let taskInput = task_path ?? task;
211
507
  if (envelope_ref) {
212
508
  try {
@@ -223,11 +519,28 @@ export function registerCatalogTools(server, deps) {
223
519
  return textResult({ error: "Exactly one of task_path, task, or envelope_ref is required" }, true);
224
520
  }
225
521
  let stageBody;
522
+ let stageProjectRoot;
226
523
  if (typeof stage === "string") {
227
524
  if (!stage.trim()) {
228
525
  return textResult({ error: "stage is required" }, true);
229
526
  }
230
- const absPath = path.resolve(cwd, stage);
527
+ let absPath = "";
528
+ try {
529
+ const { wireRoot, roots } = await resolveCatalogStartInput({ store: deps.store, bootCwd: deps.cwd }, project_root);
530
+ stageProjectRoot = wireRoot.path;
531
+ absPath = resolveCatalogRelativePath({
532
+ inputPath: stage,
533
+ projectRoot: wireRoot.project_root,
534
+ roots,
535
+ fieldName: "stage",
536
+ }).absolutePath;
537
+ }
538
+ catch (err) {
539
+ if (err instanceof CatalogPathError) {
540
+ return textResult(catalogPathErrorBody(err), true);
541
+ }
542
+ throw err;
543
+ }
231
544
  try {
232
545
  stageBody = await readYamlObject(absPath);
233
546
  }
@@ -254,7 +567,11 @@ export function registerCatalogTools(server, deps) {
254
567
  };
255
568
  let result;
256
569
  try {
257
- result = await manager.startRun({ pipeline, task: taskInput });
570
+ result = await manager.startRun({
571
+ pipeline,
572
+ task: taskInput,
573
+ ...(stageProjectRoot !== undefined ? { projectRoot: stageProjectRoot } : {}),
574
+ });
258
575
  }
259
576
  catch (err) {
260
577
  if (err instanceof PipelineValidationError) {
@@ -308,7 +625,25 @@ export function registerCatalogTools(server, deps) {
308
625
  }, async ({ runId }) => {
309
626
  try {
310
627
  const detail = await store.readRun(runId);
311
- return textResult(projectRunForMcp(detail));
628
+ return textResult({
629
+ ...projectRunForMcp(detail),
630
+ run_manifest: redactRunManifestForRead(detail.run_manifest),
631
+ });
632
+ }
633
+ catch (err) {
634
+ const mapped = mapStoreLookupError(err, { policy: "run" });
635
+ return textResult({ error: mapped.error, status: mapped.status }, true);
636
+ }
637
+ });
638
+ server.registerTool("export_run", {
639
+ description: "Export a single run as projectRun projection plus run_manifest. Works for running, cancelled, and terminal runs. Prefer over CLI sf export-run when the Host is reachable.",
640
+ inputSchema: z.object({
641
+ runId: z.string(),
642
+ }),
643
+ }, async ({ runId }) => {
644
+ try {
645
+ const detail = await store.readRun(runId);
646
+ return textResult(buildRunExportPayload(detail));
312
647
  }
313
648
  catch (err) {
314
649
  const mapped = mapStoreLookupError(err, { policy: "run" });
@@ -361,14 +696,21 @@ export function registerCatalogTools(server, deps) {
361
696
  else if (task !== undefined && task.trim())
362
697
  scope = "task";
363
698
  if (scope === "full") {
364
- const roots = await catalogRootsFor(deps);
699
+ const roots = await resolveCatalogRoots({
700
+ store: deps.store,
701
+ bootCwd: deps.cwd,
702
+ });
365
703
  const results = [];
366
704
  for (const root of roots) {
367
705
  try {
368
- results.push(await validateCatalog({ cwd: root, scope: "full", strict: strict ?? false }));
706
+ results.push(await validateCatalog({
707
+ cwd: root.path,
708
+ scope: "full",
709
+ strict: strict ?? false,
710
+ }));
369
711
  }
370
712
  catch {
371
- // stale/unreadable project root recorded on an old run; skip it
713
+ // unreadable root; skip
372
714
  }
373
715
  }
374
716
  const merged = {
@@ -383,13 +725,33 @@ export function registerCatalogTools(server, deps) {
383
725
  return textResult(merged);
384
726
  }
385
727
  const target = scope === "pipeline" ? pipeline.trim() : task.trim();
386
- const projectRoot = projectRootForPath(deps, target);
728
+ const roots = await resolveCatalogRoots({
729
+ store: deps.store,
730
+ bootCwd: deps.cwd,
731
+ });
732
+ let resolvedTarget = target;
733
+ let projectRoot = deps.cwd;
734
+ try {
735
+ const resolved = resolveCatalogRelativePath({
736
+ inputPath: target,
737
+ roots,
738
+ fieldName: scope === "pipeline" ? "pipeline" : "task",
739
+ });
740
+ resolvedTarget = resolved.absolutePath;
741
+ projectRoot = resolved.root.path;
742
+ }
743
+ catch (err) {
744
+ if (err instanceof CatalogPathError) {
745
+ return textResult(catalogPathErrorBody(err), true);
746
+ }
747
+ throw err;
748
+ }
387
749
  const result = await validateCatalog({
388
750
  cwd: projectRoot,
389
751
  scope,
390
752
  projectRoot,
391
- ...(scope === "pipeline" ? { pipeline: target } : {}),
392
- ...(scope === "task" ? { task: target } : {}),
753
+ ...(scope === "pipeline" ? { pipeline: resolvedTarget } : {}),
754
+ ...(scope === "task" ? { task: resolvedTarget } : {}),
393
755
  strict: strict ?? false,
394
756
  });
395
757
  return textResult(result);
@@ -400,23 +762,37 @@ export function registerCatalogTools(server, deps) {
400
762
  }
401
763
  });
402
764
  server.registerTool("describe_pipeline", {
403
- description: "Describe a pipeline DAG from a filesystem path (same as start_run): stages with inbound needs (id, on, optional if), fork, gate_kinds, Clone Chain clone_cap and clone_mode, and feedback_loop, entry, and replay_safe when set.",
765
+ description: "Describe a pipeline DAG from a catalog-relative path (same path contract as start_run): stages with inbound needs (id, on, optional if), fork, gate_kinds, Clone Chain clone_cap and clone_mode, and feedback_loop, entry, and replay_safe when set.",
404
766
  inputSchema: z.object({
405
767
  pipeline: z.string(),
768
+ project_root: z.string().optional(),
406
769
  }),
407
- }, async ({ pipeline }) => {
770
+ }, async ({ pipeline, project_root }) => {
408
771
  if (!pipeline.trim()) {
409
772
  return textResult({ error: "pipeline is required", status: 400 }, true);
410
773
  }
411
774
  try {
412
- const loaded = await loadPipeline(pipeline.trim(), {
413
- cwd: projectRootForPath(deps, pipeline.trim()),
775
+ const roots = await resolveCatalogRoots({
776
+ store: deps.store,
777
+ bootCwd: deps.cwd,
778
+ });
779
+ const resolved = resolveCatalogRelativePath({
780
+ inputPath: pipeline.trim(),
781
+ projectRoot: project_root,
782
+ roots,
783
+ fieldName: "pipeline",
784
+ });
785
+ const loaded = await loadPipeline(resolved.absolutePath, {
786
+ projectRoot: resolved.root.path,
414
787
  });
415
788
  return textResult(describePipeline(loaded));
416
789
  }
417
790
  catch (err) {
791
+ if (err instanceof CatalogPathError) {
792
+ return textResult(catalogPathErrorBody(err), true);
793
+ }
418
794
  const message = err instanceof Error ? err.message : String(err);
419
- return textResult({ error: message, status: 404 }, true);
795
+ return textResult({ error: message, status: 400 }, true);
420
796
  }
421
797
  });
422
798
  }