stageflow 0.23.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (511) hide show
  1. package/README.md +24 -5
  2. package/dist/a2a/configDiscovery.d.ts +9 -0
  3. package/dist/a2a/configDiscovery.js +18 -0
  4. package/dist/a2a/contracts.d.ts +94 -0
  5. package/dist/a2a/contracts.js +164 -0
  6. package/dist/a2a/limits.d.ts +14 -0
  7. package/dist/a2a/limits.js +29 -0
  8. package/dist/a2a/registry.d.ts +46 -0
  9. package/dist/a2a/registry.js +178 -0
  10. package/dist/a2a/server.d.ts +36 -0
  11. package/dist/a2a/server.js +344 -0
  12. package/dist/a2a/service.d.ts +97 -0
  13. package/dist/a2a/service.js +545 -0
  14. package/dist/a2a/store.d.ts +109 -0
  15. package/dist/a2a/store.js +202 -0
  16. package/dist/agent/activity.d.ts +3 -0
  17. package/dist/agent/bootProviderConfig.d.ts +21 -0
  18. package/dist/agent/bootProviderConfig.js +74 -0
  19. package/dist/agent/piAdapter.d.ts +9 -1
  20. package/dist/agent/piAdapter.js +58 -3
  21. package/dist/agent/piIsolatedMcp.d.ts +2 -0
  22. package/dist/agent/piIsolatedMcp.js +10 -2
  23. package/dist/agent/port.d.ts +6 -0
  24. package/dist/agent/streamLogRedact.d.ts +1 -1
  25. package/dist/agent/streamLogRedact.js +4 -11
  26. package/dist/cli/a2aCommand.d.ts +8 -0
  27. package/dist/cli/a2aCommand.js +131 -0
  28. package/dist/cli/artifactCommand.js +9 -16
  29. package/dist/cli/backupCommand.d.ts +9 -0
  30. package/dist/cli/backupCommand.js +111 -0
  31. package/dist/cli/debugRunCommand.d.ts +10 -0
  32. package/dist/cli/debugRunCommand.js +109 -0
  33. package/dist/cli/doctorCommand.d.ts +32 -0
  34. package/dist/cli/doctorCommand.js +453 -0
  35. package/dist/cli/envelopeCommand.js +9 -2
  36. package/dist/cli/exportAllCommand.d.ts +55 -0
  37. package/dist/cli/exportAllCommand.js +218 -0
  38. package/dist/cli/exportRunCommand.js +23 -21
  39. package/dist/cli/hostClient.d.ts +21 -3
  40. package/dist/cli/hostClient.js +93 -12
  41. package/dist/cli/initTemplates.d.ts +1 -1
  42. package/dist/cli/initTemplates.js +8 -1
  43. package/dist/cli/resolveSafeOutPath.d.ts +2 -0
  44. package/dist/cli/resolveSafeOutPath.js +40 -0
  45. package/dist/cli/restoreCommand.d.ts +10 -0
  46. package/dist/cli/restoreCommand.js +90 -0
  47. package/dist/cli/runCommand.d.ts +3 -2
  48. package/dist/cli/runCommand.js +93 -11
  49. package/dist/cli/runOutput.d.ts +4 -0
  50. package/dist/cli/runOutput.js +33 -7
  51. package/dist/cli/runStageCommand.d.ts +34 -0
  52. package/dist/cli/runStageCommand.js +426 -0
  53. package/dist/cli/runsCommand.d.ts +1 -1
  54. package/dist/cli/runsCommand.js +162 -8
  55. package/dist/cli.js +190 -30
  56. package/dist/config/catalogRelativePath.d.ts +62 -0
  57. package/dist/config/catalogRelativePath.js +118 -0
  58. package/dist/config/configOrigin.d.ts +27 -0
  59. package/dist/config/configOrigin.js +59 -0
  60. package/dist/config/hostConfig.d.ts +55 -0
  61. package/dist/config/hostConfig.js +333 -0
  62. package/dist/config/listSkills.d.ts +26 -0
  63. package/dist/config/listSkills.js +190 -3
  64. package/dist/config/loadOutcome.d.ts +1 -1
  65. package/dist/config/loadPipeline.js +23 -2
  66. package/dist/config/loadStage.js +18 -0
  67. package/dist/config/loadTask.d.ts +2 -0
  68. package/dist/config/loadTask.js +57 -18
  69. package/dist/config/materializeStageModels.js +5 -1
  70. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  71. package/dist/config/mergePipelineIncludes.js +19 -0
  72. package/dist/config/migrateYaml.js +6 -11
  73. package/dist/config/multiProjectCatalog.d.ts +30 -0
  74. package/dist/config/multiProjectCatalog.js +142 -0
  75. package/dist/config/normalizePipelineStageEntry.js +20 -1
  76. package/dist/config/pipelineStageKeys.js +2 -0
  77. package/dist/config/resolveCatalogRoots.d.ts +27 -0
  78. package/dist/config/resolveCatalogRoots.js +76 -0
  79. package/dist/config/resolveModel.d.ts +7 -1
  80. package/dist/config/resolveModel.js +11 -1
  81. package/dist/config/resolveStageMcpServers.d.ts +9 -1
  82. package/dist/config/resolveStageMcpServers.js +36 -9
  83. package/dist/config/secretFromEnvOrFile.d.ts +9 -0
  84. package/dist/config/secretFromEnvOrFile.js +34 -0
  85. package/dist/config/seededCatalog.d.ts +11 -0
  86. package/dist/config/seededCatalog.js +29 -0
  87. package/dist/config/toolRequires.d.ts +24 -0
  88. package/dist/config/toolRequires.js +115 -0
  89. package/dist/config/validateCatalog.d.ts +5 -1
  90. package/dist/config/validateCatalog.js +140 -1
  91. package/dist/diagnostics/checks.d.ts +39 -0
  92. package/dist/diagnostics/checks.js +135 -0
  93. package/dist/errors/codes.d.ts +14 -0
  94. package/dist/errors/codes.js +59 -0
  95. package/dist/git/cache.d.ts +14 -0
  96. package/dist/git/cache.js +150 -0
  97. package/dist/git/credentials.d.ts +9 -0
  98. package/dist/git/credentials.js +88 -0
  99. package/dist/git/errors.d.ts +20 -0
  100. package/dist/git/errors.js +94 -0
  101. package/dist/git/exec.d.ts +16 -0
  102. package/dist/git/exec.js +135 -0
  103. package/dist/git/operations.d.ts +29 -0
  104. package/dist/git/operations.js +153 -0
  105. package/dist/git/version.d.ts +1 -0
  106. package/dist/git/version.js +10 -0
  107. package/dist/logging/audit.d.ts +16 -0
  108. package/dist/logging/audit.js +19 -0
  109. package/dist/logging/commonWords.d.ts +2 -0
  110. package/dist/logging/commonWords.js +13 -0
  111. package/dist/logging/logger.d.ts +49 -0
  112. package/dist/logging/logger.js +193 -0
  113. package/dist/logging/namedSecrets.d.ts +6 -0
  114. package/dist/logging/namedSecrets.js +58 -0
  115. package/dist/logging/redact.d.ts +13 -0
  116. package/dist/logging/redact.js +88 -0
  117. package/dist/mcp/catalogTools.js +591 -76
  118. package/dist/mcp/checkoutTools.d.ts +52 -0
  119. package/dist/mcp/checkoutTools.js +332 -0
  120. package/dist/mcp/controlTools.js +179 -5
  121. package/dist/mcp/deps.d.ts +1 -0
  122. package/dist/mcp/getStartedTool.d.ts +3 -0
  123. package/dist/mcp/getStartedTool.js +62 -0
  124. package/dist/mcp/readArtifact.d.ts +11 -0
  125. package/dist/mcp/readArtifact.js +46 -30
  126. package/dist/mcp/server.js +1 -0
  127. package/dist/mcp/tools.js +4 -0
  128. package/dist/net/proxy.d.ts +14 -0
  129. package/dist/net/proxy.js +78 -0
  130. package/dist/package-meta.d.ts +2 -1
  131. package/dist/package-meta.js +2 -1
  132. package/dist/preflight/bash.d.ts +8 -0
  133. package/dist/preflight/bash.js +34 -0
  134. package/dist/preflight/claudeRoot.d.ts +11 -0
  135. package/dist/preflight/claudeRoot.js +23 -0
  136. package/dist/preflight/mcpCommands.d.ts +8 -0
  137. package/dist/preflight/mcpCommands.js +36 -0
  138. package/dist/preflight/pipelinePreflight.d.ts +40 -0
  139. package/dist/preflight/pipelinePreflight.js +192 -0
  140. package/dist/preflight/tls.d.ts +6 -0
  141. package/dist/preflight/tls.js +18 -0
  142. package/dist/preflight/toolchain.d.ts +45 -0
  143. package/dist/preflight/toolchain.js +219 -0
  144. package/dist/project/findProjectRoot.js +3 -4
  145. package/dist/project/globalHome.d.ts +7 -0
  146. package/dist/project/globalHome.js +63 -2
  147. package/dist/project/resolveProjectContext.js +2 -2
  148. package/dist/project/resolveStageflowContext.js +2 -2
  149. package/dist/projection/projectRun.d.ts +2 -1
  150. package/dist/projection/projectRun.js +1 -0
  151. package/dist/runstore/assertTmpdir.d.ts +1 -0
  152. package/dist/runstore/assertTmpdir.js +21 -0
  153. package/dist/runstore/backup.d.ts +52 -0
  154. package/dist/runstore/backup.js +292 -0
  155. package/dist/runstore/createStore.d.ts +27 -0
  156. package/dist/runstore/createStore.js +75 -7
  157. package/dist/runstore/debugBundle.d.ts +60 -0
  158. package/dist/runstore/debugBundle.js +143 -0
  159. package/dist/runstore/diskUsage.d.ts +50 -0
  160. package/dist/runstore/diskUsage.js +214 -0
  161. package/dist/runstore/exportRunPayload.d.ts +8 -0
  162. package/dist/runstore/exportRunPayload.js +23 -0
  163. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  164. package/dist/runstore/normalizeCatalogPath.js +10 -0
  165. package/dist/runstore/paths.d.ts +5 -0
  166. package/dist/runstore/paths.js +145 -1
  167. package/dist/runstore/port.d.ts +119 -8
  168. package/dist/runstore/port.js +8 -1
  169. package/dist/runstore/restore.d.ts +81 -0
  170. package/dist/runstore/restore.js +355 -0
  171. package/dist/runstore/retention.d.ts +27 -0
  172. package/dist/runstore/retention.js +74 -0
  173. package/dist/runstore/runManifest.d.ts +146 -0
  174. package/dist/runstore/runManifest.js +288 -0
  175. package/dist/runstore/runProjection.d.ts +3 -1
  176. package/dist/runstore/runProjection.js +63 -1
  177. package/dist/runstore/sqlite/SqliteRunStore.d.ts +37 -3
  178. package/dist/runstore/sqlite/SqliteRunStore.js +401 -227
  179. package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
  180. package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
  181. package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
  182. package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
  183. package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
  184. package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
  185. package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
  186. package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
  187. package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
  188. package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
  189. package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
  190. package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
  191. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
  192. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
  193. package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
  194. package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
  195. package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
  196. package/dist/runstore/sqlite/migrations/index.js +72 -0
  197. package/dist/runstore/sqlite/schema.d.ts +20 -1
  198. package/dist/runstore/sqlite/schema.js +283 -1
  199. package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
  200. package/dist/runstore/sqlite/storeOpenError.js +11 -0
  201. package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
  202. package/dist/runstore/sqlite/storeSchemaError.js +8 -0
  203. package/dist/runstore/stageExecution.js +3 -0
  204. package/dist/runstore/storeFilesystem.d.ts +32 -0
  205. package/dist/runstore/storeFilesystem.js +148 -0
  206. package/dist/runstore/submission.d.ts +11 -0
  207. package/dist/runstore/submission.js +7 -0
  208. package/dist/runstore/trackProjection.js +2 -0
  209. package/dist/runstore/workspaceLayout.d.ts +13 -0
  210. package/dist/runstore/workspaceLayout.js +76 -0
  211. package/dist/runtime/completionCheckRunner.d.ts +3 -0
  212. package/dist/runtime/completionCheckRunner.js +45 -7
  213. package/dist/runtime/containerLimits.d.ts +16 -0
  214. package/dist/runtime/containerLimits.js +84 -0
  215. package/dist/runtime/credentialMaterialisation.d.ts +28 -0
  216. package/dist/runtime/credentialMaterialisation.js +128 -0
  217. package/dist/runtime/gitCheckoutCapability.js +7 -13
  218. package/dist/runtime/pipelineRunner.d.ts +38 -1
  219. package/dist/runtime/pipelineRunner.js +179 -15
  220. package/dist/runtime/pipelineScheduler.d.ts +15 -0
  221. package/dist/runtime/pipelineScheduler.js +167 -42
  222. package/dist/runtime/reloadRunCatalog.js +12 -1
  223. package/dist/runtime/repositoryMaterialize.d.ts +47 -0
  224. package/dist/runtime/repositoryMaterialize.js +235 -0
  225. package/dist/runtime/resolveEnvelopeRef.d.ts +30 -0
  226. package/dist/runtime/resolveEnvelopeRef.js +79 -0
  227. package/dist/runtime/resumeTimedOut.d.ts +1 -1
  228. package/dist/runtime/resumeTimedOut.js +5 -2
  229. package/dist/runtime/runChangeBus.js +9 -0
  230. package/dist/runtime/runDeletion.d.ts +7 -0
  231. package/dist/runtime/runDeletion.js +37 -0
  232. package/dist/runtime/runManager.d.ts +179 -4
  233. package/dist/runtime/runManager.js +1644 -83
  234. package/dist/runtime/runRetentionSweep.d.ts +31 -0
  235. package/dist/runtime/runRetentionSweep.js +328 -0
  236. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  237. package/dist/runtime/runRetryCoordinator.js +19 -2
  238. package/dist/runtime/runSkills.d.ts +40 -0
  239. package/dist/runtime/runSkills.js +173 -0
  240. package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
  241. package/dist/runtime/stageAttemptBootstrap.js +195 -24
  242. package/dist/runtime/stageCacheEnv.d.ts +6 -0
  243. package/dist/runtime/stageCacheEnv.js +34 -0
  244. package/dist/runtime/stageConcurrency.d.ts +2 -1
  245. package/dist/runtime/stageConcurrency.js +4 -2
  246. package/dist/runtime/stageEnvironment.d.ts +38 -0
  247. package/dist/runtime/stageEnvironment.js +193 -0
  248. package/dist/runtime/stageProcessLauncher.d.ts +18 -0
  249. package/dist/runtime/stageProcessLauncher.js +194 -38
  250. package/dist/runtime/stageRecovery.d.ts +3 -1
  251. package/dist/runtime/stageRecovery.js +19 -4
  252. package/dist/runtime/stageRoots.d.ts +38 -1
  253. package/dist/runtime/stageRoots.js +118 -0
  254. package/dist/runtime/stageRunner.d.ts +1 -0
  255. package/dist/runtime/stageRunner.js +3 -1
  256. package/dist/runtime/stageSecretDecl.d.ts +9 -0
  257. package/dist/runtime/stageSecretDecl.js +102 -0
  258. package/dist/runtime/stageSecrets.d.ts +40 -0
  259. package/dist/runtime/stageSecrets.js +181 -0
  260. package/dist/runtime/stageWorker.d.ts +3 -2
  261. package/dist/runtime/stageWorker.js +58 -10
  262. package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
  263. package/dist/runtime/stageWorkerProtocol.js +8 -0
  264. package/dist/runtime/startPayload.d.ts +32 -0
  265. package/dist/runtime/startPayload.js +59 -0
  266. package/dist/runtime/taskInput.js +14 -5
  267. package/dist/runtime/verifiedStageExecution.d.ts +1 -0
  268. package/dist/runtime/verifiedStageExecution.js +2 -1
  269. package/dist/runtime/workspaceBinding.d.ts +20 -0
  270. package/dist/runtime/workspaceBinding.js +60 -0
  271. package/dist/server/allowedHosts.d.ts +19 -0
  272. package/dist/server/allowedHosts.js +179 -0
  273. package/dist/server/bootstrap.d.ts +38 -2
  274. package/dist/server/bootstrap.js +219 -4
  275. package/dist/server/controlToken.d.ts +47 -0
  276. package/dist/server/controlToken.js +241 -0
  277. package/dist/server/createHttpHost.d.ts +11 -2
  278. package/dist/server/createHttpHost.js +109 -10
  279. package/dist/server/ensureGlobalService.d.ts +5 -1
  280. package/dist/server/ensureGlobalService.js +35 -1
  281. package/dist/server/healthSurfaces.d.ts +6 -0
  282. package/dist/server/healthSurfaces.js +98 -0
  283. package/dist/server/http.d.ts +12 -1
  284. package/dist/server/http.js +1085 -485
  285. package/dist/server/listenHost.d.ts +5 -0
  286. package/dist/server/listenHost.js +56 -0
  287. package/dist/server/mcpHost.d.ts +10 -1
  288. package/dist/server/mcpHost.js +36 -6
  289. package/dist/server/operatorResults.d.ts +2 -2
  290. package/dist/server/operatorResults.js +40 -29
  291. package/dist/server/requestAuthContext.d.ts +12 -0
  292. package/dist/server/requestAuthContext.js +21 -0
  293. package/dist/server/shutdown.d.ts +69 -0
  294. package/dist/server/shutdown.js +219 -0
  295. package/dist/types/pipeline.d.ts +7 -0
  296. package/dist/types/stage.d.ts +8 -0
  297. package/dist/types/task.d.ts +8 -0
  298. package/dist/ui/assets/index-B6hlSXXn.js +120 -0
  299. package/dist/ui/index.html +1 -1
  300. package/examples/README.md +98 -0
  301. package/examples/archify-on-pr/README.md +213 -0
  302. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
  303. package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
  304. package/examples/archify-on-pr/author-diagrams.yaml +106 -0
  305. package/examples/archify-on-pr/detect-changes.yaml +89 -0
  306. package/examples/ci-validate/README.md +35 -0
  307. package/examples/ci-validate/check.yaml +13 -0
  308. package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
  309. package/examples/ci-validate/validate.sh +5 -0
  310. package/examples/compliance-review-demo/README.md +125 -0
  311. package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
  312. package/examples/compliance-review-demo/connect-account.yaml +47 -0
  313. package/examples/compliance-review-demo/map-to-control.yaml +123 -0
  314. package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
  315. package/examples/compliance-review-demo/publish-report.yaml +79 -0
  316. package/examples/compliance-review-demo/review-verdict.yaml +122 -0
  317. package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
  318. package/examples/compliance-review-demo/store-evidence.yaml +143 -0
  319. package/examples/conditional-fork/README.md +89 -0
  320. package/examples/conditional-fork/branch-a.yaml +13 -0
  321. package/examples/conditional-fork/branch-b.yaml +13 -0
  322. package/examples/conditional-fork/decide.yaml +35 -0
  323. package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
  324. package/examples/conditional-fork/fork-demo.task.yaml +8 -0
  325. package/examples/context7-mcp/README.md +42 -0
  326. package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
  327. package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
  328. package/examples/context7-mcp/fetch-docs.yaml +52 -0
  329. package/examples/context7-mcp/resolve-library.yaml +31 -0
  330. package/examples/context7-mcp/write-brief.yaml +52 -0
  331. package/examples/feature-loop/README.md +104 -0
  332. package/examples/feature-loop/address-feedback.yaml +148 -0
  333. package/examples/feature-loop/align.yaml +116 -0
  334. package/examples/feature-loop/decompose.yaml +86 -0
  335. package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
  336. package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
  337. package/examples/feature-loop/feature-loop.task.yaml +25 -0
  338. package/examples/feature-loop/implement.yaml +128 -0
  339. package/examples/feature-loop/plan.yaml +111 -0
  340. package/examples/feature-loop/publish.yaml +167 -0
  341. package/examples/feature-loop/review.yaml +146 -0
  342. package/examples/feature-loop/verify.yaml +106 -0
  343. package/examples/feedback-loop/README.md +72 -0
  344. package/examples/feedback-loop/VERIFY.md +208 -0
  345. package/examples/feedback-loop/continue-only.task.yaml +4 -0
  346. package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
  347. package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
  348. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
  349. package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
  350. package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
  351. package/examples/feedback-loop/implement.yaml +14 -0
  352. package/examples/feedback-loop/plan.yaml +14 -0
  353. package/examples/feedback-loop/review.yaml +15 -0
  354. package/examples/feedback-loop/send-back-once.task.yaml +6 -0
  355. package/examples/feedback-loop/submit.yaml +12 -0
  356. package/examples/generic-fan-in/README.md +151 -0
  357. package/examples/generic-fan-in/clarify.yaml +18 -0
  358. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
  359. package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
  360. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
  361. package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
  362. package/examples/generic-fan-in/research.yaml +45 -0
  363. package/examples/generic-fan-in/synthesize.yaml +66 -0
  364. package/examples/generic-fan-in/validation.yaml +45 -0
  365. package/examples/github-release/README.md +78 -0
  366. package/examples/github-release/draft-release-notes.yaml +64 -0
  367. package/examples/github-release/github-release.pipeline.yaml +11 -0
  368. package/examples/github-release/github-release.task.yaml +13 -0
  369. package/examples/github-release/publish-github-release.yaml +64 -0
  370. package/examples/hello-world/README.md +28 -0
  371. package/examples/hello-world/hello.pipeline.yaml +4 -0
  372. package/examples/hello-world/my-task.task.yaml +6 -0
  373. package/examples/hello-world/research.yaml +18 -0
  374. package/examples/mcp-hitl-tour/README.md +113 -0
  375. package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
  376. package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
  377. package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
  378. package/examples/mcp-hitl-tour/gather.yaml +31 -0
  379. package/examples/mcp-hitl-tour/intake.yaml +62 -0
  380. package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
  381. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
  382. package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
  383. package/examples/mcp-hitl-tour/polish.yaml +33 -0
  384. package/examples/mcp-hitl-tour/review.yaml +17 -0
  385. package/examples/mcp-hitl-tour/ship.yaml +25 -0
  386. package/examples/oss-issue-contribution/README.md +218 -0
  387. package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
  388. package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
  389. package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
  390. package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
  391. package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
  392. package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
  393. package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
  394. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
  395. package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
  396. package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
  397. package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
  398. package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
  399. package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
  400. package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
  401. package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
  402. package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
  403. package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
  404. package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
  405. package/examples/oss-quick-fix/README.md +65 -0
  406. package/examples/oss-quick-fix/implement-fix.yaml +84 -0
  407. package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
  408. package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
  409. package/examples/oss-quick-fix/ship-fix.yaml +81 -0
  410. package/examples/oss-quick-fix/understand-issue.yaml +67 -0
  411. package/examples/oss-quick-fix/verify-fix.yaml +73 -0
  412. package/examples/plan-review/README.md +37 -0
  413. package/examples/plan-review/plan-review-followup.yaml +13 -0
  414. package/examples/plan-review/plan-review.pipeline.yaml +9 -0
  415. package/examples/plan-review/plan-review.task.yaml +9 -0
  416. package/examples/plan-review/plan-review.yaml +25 -0
  417. package/examples/playwright-mcp/README.md +39 -0
  418. package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
  419. package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
  420. package/examples/playwright-mcp/screenshot.yaml +40 -0
  421. package/examples/retry-tour/README.md +75 -0
  422. package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
  423. package/examples/retry-tour/retry-tour.task.yaml +9 -0
  424. package/examples/route-if-tour/README.md +202 -0
  425. package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
  426. package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
  427. package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
  428. package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
  429. package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
  430. package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
  431. package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
  432. package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
  433. package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
  434. package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
  435. package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
  436. package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
  437. package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
  438. package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
  439. package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
  440. package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
  441. package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
  442. package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
  443. package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
  444. package/examples/route-wiring-smoke-test/README.md +377 -0
  445. package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
  446. package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
  447. package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
  448. package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
  449. package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
  450. package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
  451. package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
  452. package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
  453. package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
  454. package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
  455. package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
  456. package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
  457. package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
  458. package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
  459. package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
  460. package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
  461. package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
  462. package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
  463. package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
  464. package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
  465. package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
  466. package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
  467. package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
  468. package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
  469. package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
  470. package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
  471. package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
  472. package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
  473. package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
  474. package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
  475. package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
  476. package/examples/ship-feature/README.md +190 -0
  477. package/examples/ship-feature/feat-address-feedback.yaml +119 -0
  478. package/examples/ship-feature/feat-implement.yaml +180 -0
  479. package/examples/ship-feature/feat-plan.yaml +120 -0
  480. package/examples/ship-feature/feat-review.yaml +109 -0
  481. package/examples/ship-feature/feat-ship.yaml +203 -0
  482. package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
  483. package/examples/ship-feature/ship-feature.task.yaml +78 -0
  484. package/examples/stage-mcp/README.md +144 -0
  485. package/examples/stage-mcp/echo-mcp.mjs +20 -0
  486. package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
  487. package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
  488. package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
  489. package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
  490. package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
  491. package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
  492. package/examples/stage-mcp/use-echo.yaml +20 -0
  493. package/examples/verify-tour/README.md +80 -0
  494. package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
  495. package/examples/verify-tour/verify-tour.task.yaml +11 -0
  496. package/package.json +6 -1
  497. package/skills/stageflow/SKILL.md +6 -6
  498. package/skills/stageflow/references/control-surface.md +11 -5
  499. package/skills/stageflow/scripts/detect-host.mjs +14 -1
  500. package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
  501. package/skills/stageflow-author/SKILL.md +4 -3
  502. package/skills/stageflow-author/references/catalog-mapping.md +16 -0
  503. package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
  504. package/skills/stageflow-run/SKILL.md +20 -12
  505. package/skills/stageflow-run/references/mcp-call.md +9 -1
  506. package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
  507. package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
  508. package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
  509. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
  510. package/skills/stageflow-setup/SKILL.md +40 -8
  511. package/dist/ui/assets/index-Da5EHU6M.js +0 -119
@@ -0,0 +1,115 @@
1
+ import semver from "semver";
2
+ import { loadFailure, loadSuccess } from "./loadOutcome.js";
3
+ const ALLOWED_KEYS = new Set(["tool", "version"]);
4
+ function isPlainObject(value) {
5
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6
+ }
7
+ function requiresIssue(options, message) {
8
+ if (options.category === "pipeline") {
9
+ return {
10
+ code: options.code,
11
+ message,
12
+ category: "pipeline",
13
+ ...(options.pipelineId !== undefined
14
+ ? { pipelineId: options.pipelineId }
15
+ : {}),
16
+ ...(options.stageId !== undefined ? { stageId: options.stageId } : {}),
17
+ };
18
+ }
19
+ return {
20
+ code: options.code,
21
+ message,
22
+ category: "stage",
23
+ ...(options.stageId !== undefined ? { stageId: options.stageId } : {}),
24
+ };
25
+ }
26
+ export function parseToolRequires(raw, label, options) {
27
+ if (raw === undefined)
28
+ return loadSuccess(undefined);
29
+ if (!Array.isArray(raw)) {
30
+ return loadFailure([
31
+ requiresIssue(options, `Invalid ${label}: requires must be an array of { tool, version? }`),
32
+ ]);
33
+ }
34
+ const out = [];
35
+ for (let i = 0; i < raw.length; i++) {
36
+ const item = raw[i];
37
+ if (!isPlainObject(item)) {
38
+ return loadFailure([
39
+ requiresIssue(options, `Invalid ${label}: requires[${i}] must be an object`),
40
+ ]);
41
+ }
42
+ for (const key of Object.keys(item)) {
43
+ if (!ALLOWED_KEYS.has(key)) {
44
+ return loadFailure([
45
+ requiresIssue(options, `Invalid ${label}: requires[${i}] unknown key "${key}" (allowed: tool, version)`),
46
+ ]);
47
+ }
48
+ }
49
+ if (typeof item.tool !== "string" || item.tool.trim() === "") {
50
+ return loadFailure([
51
+ requiresIssue(options, `Invalid ${label}: requires[${i}].tool must be a non-empty string`),
52
+ ]);
53
+ }
54
+ const tool = item.tool.trim();
55
+ if (item.version !== undefined) {
56
+ if (typeof item.version !== "string" || item.version.trim() === "") {
57
+ return loadFailure([
58
+ requiresIssue(options, `Invalid ${label}: requires[${i}].version must be a non-empty semver range string`),
59
+ ]);
60
+ }
61
+ const range = item.version.trim();
62
+ if (!semver.validRange(range)) {
63
+ return loadFailure([
64
+ requiresIssue(options, `Invalid ${label}: requires[${i}].version "${range}" is not a valid semver range`),
65
+ ]);
66
+ }
67
+ out.push({ tool, version: range });
68
+ }
69
+ else {
70
+ out.push({ tool });
71
+ }
72
+ }
73
+ return loadSuccess(out);
74
+ }
75
+ /**
76
+ * Merge requirement lists: same tool → intersect version ranges (stricter).
77
+ * Non-intersecting ranges fail with pipeline.requires_conflict.
78
+ */
79
+ export function mergeToolRequires(lists, ctx) {
80
+ const byTool = new Map();
81
+ for (const list of lists) {
82
+ if (!list)
83
+ continue;
84
+ for (const req of list) {
85
+ const prior = byTool.get(req.tool);
86
+ if (!byTool.has(req.tool)) {
87
+ byTool.set(req.tool, req.version);
88
+ continue;
89
+ }
90
+ if (prior === undefined && req.version === undefined)
91
+ continue;
92
+ if (prior === undefined) {
93
+ byTool.set(req.tool, req.version);
94
+ continue;
95
+ }
96
+ if (req.version === undefined)
97
+ continue;
98
+ if (!semver.intersects(prior, req.version)) {
99
+ return loadFailure([
100
+ {
101
+ code: "pipeline.requires_conflict",
102
+ message: `Pipeline ${ctx.pipelineId}${ctx.label ? ` (${ctx.label})` : ""}: tool "${req.tool}" has non-intersecting version ranges "${prior}" and "${req.version}"`,
103
+ category: "pipeline",
104
+ pipelineId: ctx.pipelineId,
105
+ },
106
+ ]);
107
+ }
108
+ byTool.set(req.tool, `${prior} ${req.version}`);
109
+ }
110
+ }
111
+ return loadSuccess([...byTool.entries()].map(([tool, version]) => version !== undefined ? { tool, version } : { tool }));
112
+ }
113
+ export function collectEffectiveRequires(options) {
114
+ return mergeToolRequires([options.pipelineRequires, ...options.stageRequires], { pipelineId: options.pipelineId });
115
+ }
@@ -2,7 +2,7 @@ import type { InlinePipelineDefinition, LoadedPipeline } from "../types/pipeline
2
2
  import type { LoadIssue } from "./loadOutcome.js";
3
3
  export type ValidationSeverity = "error" | "warning";
4
4
  export type ValidationCategory = "pipeline" | "stage" | "catalog" | "task";
5
- export type ValidationFindingCode = "pipeline.invalid_shape" | "pipeline.dag_error" | "pipeline.missing_stage" | "pipeline.load_error" | "pipeline.string_stage_ref" | "pipeline.stage_uses_inline_conflict" | "pipeline.stage_missing_body" | "pipeline.stage_id_mismatch" | "pipeline.invalid_completion" | "pipeline.invalid_recovery" | "pipeline.include_cycle" | "pipeline.include_invalid" | "pipeline.include_duplicate_stage" | "pipeline.invalid_agent" | "pipeline.invalid_model" | "pipeline.invalid_verify" | "pipeline.io_incompatible" | "pipeline.model_applies" | "pipeline.route_if_invalid" | "pipeline.route_all_gated" | "stage.invalid_shape" | "stage.invalid_model" | "stage.missing_model" | "stage.invalid_payload_schema" | "stage.invalid_clone_input_schema" | "stage.unresolved_schema_ref" | "stage.invalid_clone_actions" | "stage.invalid_gate_kinds" | "stage.invalid_pre_emit_checks" | "stage.invalid_timeout_ms" | "stage.invalid_skill" | "stage.invalid_mcp" | "stage.invalid_agent" | "stage.invalid_io" | "stage.load_error" | "stage.id_filename_mismatch" | "task.invalid_shape" | "task.load_error" | "task.entry_input_unmet" | "catalog.duplicate_pipeline_id" | "catalog.manifest_missing" | "catalog.manifest_invalid" | "catalog.empty_catalog" | "catalog.manifest_load_error" | "catalog.invalid_mcp" | "catalog.mixed_yaml_dialect" | "catalog.legacy_yaml";
5
+ export type ValidationFindingCode = "pipeline.invalid_shape" | "pipeline.dag_error" | "pipeline.missing_stage" | "pipeline.load_error" | "pipeline.string_stage_ref" | "pipeline.stage_uses_inline_conflict" | "pipeline.stage_missing_body" | "pipeline.stage_id_mismatch" | "pipeline.invalid_completion" | "catalog.path_case_mismatch" | "pipeline.invalid_recovery" | "pipeline.include_cycle" | "pipeline.include_invalid" | "pipeline.include_duplicate_stage" | "pipeline.invalid_agent" | "pipeline.invalid_model" | "pipeline.invalid_verify" | "pipeline.io_incompatible" | "pipeline.model_applies" | "pipeline.route_if_invalid" | "pipeline.route_all_gated" | "pipeline.invalid_requires" | "pipeline.requires_conflict" | "stage.invalid_shape" | "stage.invalid_model" | "stage.missing_model" | "stage.invalid_payload_schema" | "stage.invalid_clone_input_schema" | "stage.unresolved_schema_ref" | "stage.invalid_clone_actions" | "stage.invalid_gate_kinds" | "stage.invalid_pre_emit_checks" | "stage.invalid_timeout_ms" | "stage.invalid_skill" | "stage.invalid_mcp" | "stage.invalid_secrets" | "stage.unknown_secret" | "stage.denied_secret" | "stage.invalid_requires" | "stage.invalid_agent" | "stage.invalid_io" | "stage.load_error" | "stage.id_filename_mismatch" | "task.invalid_shape" | "task.load_error" | "task.entry_input_unmet" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid" | "catalog.duplicate_pipeline_id" | "catalog.manifest_missing" | "catalog.manifest_invalid" | "catalog.empty_catalog" | "catalog.manifest_load_error" | "catalog.invalid_mcp" | "catalog.mcp_command_missing" | "catalog.mixed_yaml_dialect" | "catalog.legacy_yaml" | "catalog.stageflow_home_absolute_path";
6
6
  export type ValidationFinding = {
7
7
  severity: ValidationSeverity;
8
8
  code: ValidationFindingCode | string;
@@ -35,6 +35,10 @@ export declare function effectiveSeverity(finding: ValidationFinding, strict: bo
35
35
  export declare function buildValidationResult(scope: ValidationScope, findings: ValidationFinding[], strict: boolean): ValidationResult;
36
36
  export declare function findingsFromLoadIssues(cwd: string, absPath: string, issues: LoadIssue[]): ValidationFinding[];
37
37
  export declare function findingStageIdFilenameMismatch(cwd: string, absPath: string, fileStem: string, declaredId: string): ValidationFinding;
38
+ /** Parent readdir case check — warn by default; error under --strict. */
39
+ export declare function findingPathCaseMismatch(cwd: string, referencedPath: string): Promise<ValidationFinding | null>;
40
+ export declare function collectAbsolutePathCandidates(text: string): string[];
41
+ export declare function isPathUnderStageflowHome(candidate: string, home: string): boolean;
38
42
  export type ValidatePipelineOptions = {
39
43
  cwd?: string;
40
44
  projectRoot?: string;
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import { globalStageflowHome } from "../project/globalHome.js";
2
3
  import { INLINE_PIPELINE_PATH, loadPipelineFromObjectOutcome, loadPipelineOutcome, resolvePipelinePath, } from "./loadPipeline.js";
3
4
  import { loadStageOutcome } from "./loadStage.js";
4
5
  import { loadTaskOutcome } from "./loadTask.js";
@@ -7,6 +8,9 @@ import { resolveCatalogContext } from "./resolveCatalogContext.js";
7
8
  import { getCatalogScanPaths } from "./browseCatalog.js";
8
9
  import { manifestPathForProject } from "./loadStageflowManifest.js";
9
10
  import { MCP_CATALOG_FILENAME, StageMcpError, assertMcpAllowlistKnown, loadMcpCatalog, mcpCatalogPath, } from "./resolveStageMcpServers.js";
11
+ import { loadSecretRegistry } from "../runtime/stageSecrets.js";
12
+ import { isForeverDeniedSecret } from "../runtime/stageEnvironment.js";
13
+ import { findMissingMcpCommands } from "../preflight/mcpCommands.js";
10
14
  export function relPath(cwd, absPath) {
11
15
  return path.relative(cwd, absPath).replace(/\\/g, "/");
12
16
  }
@@ -160,6 +164,35 @@ export function findingStageIdFilenameMismatch(cwd, absPath, fileStem, declaredI
160
164
  stageId: declaredId,
161
165
  }, "error");
162
166
  }
167
+ /** Parent readdir case check — warn by default; error under --strict. */
168
+ export async function findingPathCaseMismatch(cwd, referencedPath) {
169
+ const { readdir } = await import("node:fs/promises");
170
+ const abs = path.isAbsolute(referencedPath)
171
+ ? referencedPath
172
+ : path.resolve(cwd, referencedPath);
173
+ const parent = path.dirname(abs);
174
+ const base = path.basename(abs);
175
+ let entries;
176
+ try {
177
+ entries = await readdir(parent);
178
+ }
179
+ catch {
180
+ return null;
181
+ }
182
+ const exact = entries.includes(base);
183
+ if (exact)
184
+ return null;
185
+ const match = entries.find((e) => e.toLowerCase() === base.toLowerCase());
186
+ if (match === undefined)
187
+ return null;
188
+ return baseFinding({
189
+ cwd,
190
+ absPath: abs,
191
+ message: `Path casing differs on disk: referenced "${base}" but found "${match}"`,
192
+ code: "catalog.path_case_mismatch",
193
+ category: "catalog",
194
+ }, "warning");
195
+ }
163
196
  async function checkStageIdFilename(cwd, stagePath) {
164
197
  const fileStem = path.basename(stagePath, ".yaml");
165
198
  try {
@@ -197,6 +230,100 @@ function collectMcpAllowlistNames(loaded) {
197
230
  }
198
231
  return [...names];
199
232
  }
233
+ function findingsForStageSecrets(cwd, pipelinePath, loaded) {
234
+ const registry = loadSecretRegistry(process.env);
235
+ const findings = [];
236
+ for (const stage of loaded.stages) {
237
+ for (const decl of stage.secrets ?? []) {
238
+ if (isForeverDeniedSecret(decl.name)) {
239
+ findings.push(findingStageError(cwd, pipelinePath, `secret "${decl.name}" is permanently denied and cannot be granted`, "stage.denied_secret", stage.id));
240
+ continue;
241
+ }
242
+ if (!registry.has(decl.name)) {
243
+ findings.push(findingStageError(cwd, pipelinePath, `unknown secret "${decl.name}" is not in the Host secret registry`, "stage.unknown_secret", stage.id));
244
+ }
245
+ }
246
+ }
247
+ return findings;
248
+ }
249
+ const ABSOLUTE_PATH_IN_TEXT_RE = /(?:^|[\s"'`=:(])(\/(?:[^\s"'`;|&<>()]+))/g;
250
+ const TRAILING_PATH_PUNCT_RE = /[.,:;!?)\]]+$/;
251
+ export function collectAbsolutePathCandidates(text) {
252
+ const found = [];
253
+ const seen = new Set();
254
+ ABSOLUTE_PATH_IN_TEXT_RE.lastIndex = 0;
255
+ let match;
256
+ while ((match = ABSOLUTE_PATH_IN_TEXT_RE.exec(text)) !== null) {
257
+ const raw = match[1]?.replace(TRAILING_PATH_PUNCT_RE, "") ?? "";
258
+ if (!raw || !path.isAbsolute(raw) || seen.has(raw))
259
+ continue;
260
+ seen.add(raw);
261
+ found.push(raw);
262
+ }
263
+ return found;
264
+ }
265
+ export function isPathUnderStageflowHome(candidate, home) {
266
+ if (!path.isAbsolute(candidate))
267
+ return false;
268
+ const resolved = path.resolve(candidate);
269
+ const homeResolved = path.resolve(home);
270
+ return (resolved === homeResolved || resolved.startsWith(`${homeResolved}${path.sep}`));
271
+ }
272
+ function stageSourcePath(loaded, stageId) {
273
+ const source = loaded.stageSources?.[stageId];
274
+ if (source?.kind === "file")
275
+ return source.path;
276
+ return loaded.pipelinePath;
277
+ }
278
+ function stageflowHomeAbsolutePathMessage(stageId, location, absolutePath) {
279
+ return (`Stage "${stageId}" ${location} contains absolute path under STAGEFLOW_HOME ` +
280
+ `("${absolutePath}"). Use STAGEFLOW_CHECKOUT / STAGEFLOW_RUN_WORKSPACE ` +
281
+ `(and related binding env vars) instead of durable-home paths`);
282
+ }
283
+ function findingsForStageflowHomeAbsolutePaths(cwd, loaded) {
284
+ const home = globalStageflowHome();
285
+ const findings = [];
286
+ const seen = new Set();
287
+ const pushFinding = (stageId, absPath, location, absolutePath) => {
288
+ const key = `${stageId}\0${location}\0${absolutePath}`;
289
+ if (seen.has(key))
290
+ return;
291
+ seen.add(key);
292
+ findings.push(baseFinding({
293
+ cwd,
294
+ absPath,
295
+ message: stageflowHomeAbsolutePathMessage(stageId, location, absolutePath),
296
+ code: "catalog.stageflow_home_absolute_path",
297
+ category: "catalog",
298
+ pipelineId: loaded.pipeline.id,
299
+ stageId,
300
+ }, "error"));
301
+ };
302
+ const scanText = (stageId, absPath, location, text) => {
303
+ for (const candidate of collectAbsolutePathCandidates(text)) {
304
+ if (isPathUnderStageflowHome(candidate, home)) {
305
+ pushFinding(stageId, absPath, location, candidate);
306
+ }
307
+ }
308
+ };
309
+ for (const stage of loaded.stages) {
310
+ const absPath = stageSourcePath(loaded, stage.id);
311
+ scanText(stage.id, absPath, "system_prompt", stage.system_prompt);
312
+ }
313
+ for (const node of loaded.dag.nodes) {
314
+ const checks = node.completion?.checks ?? [];
315
+ for (const check of checks) {
316
+ if (check.type !== "command")
317
+ continue;
318
+ const absPath = stageSourcePath(loaded, node.id);
319
+ scanText(node.id, absPath, `verify command "${check.id}" run`, check.run);
320
+ if (typeof check.cwd === "string") {
321
+ scanText(node.id, absPath, `verify command "${check.id}" cwd`, check.cwd);
322
+ }
323
+ }
324
+ }
325
+ return findings;
326
+ }
200
327
  async function findingsForStageMcpCatalog(cwd, loaded) {
201
328
  const allowlist = collectMcpAllowlistNames(loaded);
202
329
  const ctx = await resolveCatalogContext(cwd);
@@ -235,7 +362,17 @@ async function findingsForStageMcpCatalog(cwd, loaded) {
235
362
  }
236
363
  throw err;
237
364
  }
238
- return [];
365
+ const findings = [];
366
+ const serversForPath = {};
367
+ for (const name of allowlist) {
368
+ const entry = catalog.servers[name];
369
+ if (entry)
370
+ serversForPath[name] = entry;
371
+ }
372
+ for (const missing of findMissingMcpCommands(serversForPath, process.env)) {
373
+ findings.push(findingCatalog(cwd, catalogAbsPath, `MCP server "${missing.serverName}" command "${missing.command}" was not found on PATH`, "catalog.mcp_command_missing", "error"));
374
+ }
375
+ return findings;
239
376
  }
240
377
  async function runPipelineValidation(nameOrPath, options) {
241
378
  const { cwd, validateStages } = options;
@@ -274,6 +411,8 @@ async function runPipelineValidation(nameOrPath, options) {
274
411
  findings.push(...findingsFromLoadIssues(cwd, pipelinePath, outcome.issues));
275
412
  }
276
413
  findings.push(...(await findingsForStageMcpCatalog(cwd, outcome.value)));
414
+ findings.push(...findingsForStageSecrets(cwd, pipelinePath, outcome.value));
415
+ findings.push(...findingsForStageflowHomeAbsolutePaths(cwd, outcome.value));
277
416
  if (validateStages && outcome.value.stageSources) {
278
417
  for (const source of Object.values(outcome.value.stageSources)) {
279
418
  if (source.kind === "file") {
@@ -0,0 +1,39 @@
1
+ import type { RunStore } from "../runstore/port.js";
2
+ export type DiagnosticSeverity = "error" | "warn" | "skipped";
3
+ export type DiagnosticCheckResult = {
4
+ id: string;
5
+ ok: boolean;
6
+ severity: DiagnosticSeverity;
7
+ message: string;
8
+ code?: string;
9
+ detail?: Record<string, unknown>;
10
+ };
11
+ export type ReadyzChecks = {
12
+ store_openable: boolean;
13
+ home_writable: boolean;
14
+ migrations_complete: boolean;
15
+ git_present: boolean;
16
+ };
17
+ export type ReadyzResult = {
18
+ ready: boolean;
19
+ checks: ReadyzChecks;
20
+ code?: string;
21
+ };
22
+ export declare function resetReadyzCacheForTests(): void;
23
+ export declare function livezBody(): {
24
+ ok: true;
25
+ status: "live";
26
+ };
27
+ export declare function probeGitVersion(): Promise<string | undefined>;
28
+ export declare function runReadyzChecks(options: {
29
+ store: RunStore;
30
+ homeDir?: string;
31
+ now?: number;
32
+ bypassCache?: boolean;
33
+ }): Promise<ReadyzResult>;
34
+ export type SchemaHealthStub = {
35
+ user_version: number | null;
36
+ schema_migrations: "present" | "absent" | "unknown";
37
+ note?: string;
38
+ };
39
+ export declare function readSchemaHealth(store: RunStore): SchemaHealthStub;
@@ -0,0 +1,135 @@
1
+ import { accessSync, constants, writeFileSync, unlinkSync } from "node:fs";
2
+ import { execFile } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ import { globalStageflowHome } from "../project/globalHome.js";
5
+ const execFileAsync = promisify(execFile);
6
+ const READYZ_TTL_MS = 4_000;
7
+ let readyzCache;
8
+ export function resetReadyzCacheForTests() {
9
+ readyzCache = undefined;
10
+ }
11
+ export function livezBody() {
12
+ return { ok: true, status: "live" };
13
+ }
14
+ async function checkGitPresent() {
15
+ try {
16
+ await execFileAsync("git", ["--version"], {
17
+ timeout: 5_000,
18
+ windowsHide: true,
19
+ });
20
+ return true;
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ export async function probeGitVersion() {
27
+ try {
28
+ const { stdout } = await execFileAsync("git", ["--version"], {
29
+ timeout: 5_000,
30
+ windowsHide: true,
31
+ });
32
+ return stdout.trim();
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ }
38
+ function checkHomeWritable(home) {
39
+ try {
40
+ accessSync(home, constants.W_OK);
41
+ const probe = `${home}/.stageflow-write-probe-${process.pid}`;
42
+ writeFileSync(probe, "ok");
43
+ unlinkSync(probe);
44
+ return true;
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ async function checkStoreOpenable(store) {
51
+ try {
52
+ await store.listRuns();
53
+ return true;
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ function checkMigrationsComplete(store) {
60
+ const connection = store.connection;
61
+ if (connection === undefined || typeof connection.pragma !== "function") {
62
+ return true;
63
+ }
64
+ try {
65
+ const version = connection.pragma("user_version", { simple: true });
66
+ return typeof version === "number" && version >= 0;
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ export async function runReadyzChecks(options) {
73
+ const now = options.now ?? Date.now();
74
+ if (!options.bypassCache &&
75
+ readyzCache !== undefined &&
76
+ readyzCache.expiresAt > now) {
77
+ return readyzCache.result;
78
+ }
79
+ const home = options.homeDir ?? globalStageflowHome();
80
+ const checks = {
81
+ store_openable: await checkStoreOpenable(options.store),
82
+ home_writable: checkHomeWritable(home),
83
+ migrations_complete: checkMigrationsComplete(options.store),
84
+ git_present: await checkGitPresent(),
85
+ };
86
+ let code;
87
+ if (!checks.store_openable)
88
+ code = "store_not_openable";
89
+ else if (!checks.home_writable)
90
+ code = "home_not_writable";
91
+ else if (!checks.migrations_complete)
92
+ code = "migrations_incomplete";
93
+ else if (!checks.git_present)
94
+ code = "git_not_present";
95
+ const result = {
96
+ ready: code === undefined,
97
+ checks,
98
+ ...(code !== undefined ? { code } : {}),
99
+ };
100
+ readyzCache = { expiresAt: now + READYZ_TTL_MS, result };
101
+ return result;
102
+ }
103
+ export function readSchemaHealth(store) {
104
+ const connection = store.connection;
105
+ if (connection === undefined || typeof connection.pragma !== "function") {
106
+ return {
107
+ user_version: null,
108
+ schema_migrations: "unknown",
109
+ note: "Slot 1 schema reporting stub — store has no sqlite connection",
110
+ };
111
+ }
112
+ try {
113
+ const user_version = connection.pragma("user_version", {
114
+ simple: true,
115
+ });
116
+ let schema_migrations = "unknown";
117
+ if (typeof connection.prepare === "function") {
118
+ try {
119
+ connection.prepare(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'schema_migrations'`).get();
120
+ schema_migrations = "present";
121
+ }
122
+ catch {
123
+ schema_migrations = "absent";
124
+ }
125
+ }
126
+ return { user_version, schema_migrations };
127
+ }
128
+ catch {
129
+ return {
130
+ user_version: null,
131
+ schema_migrations: "unknown",
132
+ note: "Slot 1 schema reporting stub — pragma failed",
133
+ };
134
+ }
135
+ }
@@ -0,0 +1,14 @@
1
+ /** Stable network-facing error codes (snake_case). Keep strings unchanged once shipped. */
2
+ export declare const BUSY_CAPACITY: "busy_capacity";
3
+ export declare const BUSY_CHECKOUT: "busy_checkout";
4
+ /** Per-caller concurrency quota: queued when under global capacity; reject when queue full. */
5
+ export declare const BUSY_CALLER_QUOTA: "busy_caller_quota";
6
+ export declare const ABORTED: "aborted";
7
+ export declare const NETWORK_ERROR_CODES: readonly ["busy_capacity", "busy_checkout", "busy_caller_quota", "aborted", "unknown_project_root", "absolute_path_not_allowed", "path_outside_project_root", "catalog_root_unreadable", "ensure_project_not_allowed", "config_invalid", "config_unknown_key", "provider_not_configured", "a2a_configuration_error", "untrusted_config_origin", "command_not_on_path", "missing_tool", "tool_version_mismatch", "unknown_version", "secret_unavailable", "not_ready", "internal_error", "retry_in_progress", "hitl_not_retriable", "run_not_retryable", "stage_not_failed", "manual_recovery_required", "run_not_found", "stage_not_found", "artifact_not_found", "artifact_path_denied", "envelope_not_found", "insufficient_disk", "disk_check_failed", "shutting_down", "start.token_rejected", "inline_pipeline_too_large", "skills_invalid_name", "skills_invalid_path", "skills_missing_skill_md", "skills_payload_too_large", "pinned_sha_unavailable", "store_integrity_failed", "store_unsupported_filesystem", "tmpdir_unusable", "backup_insufficient_disk"];
8
+ export type NetworkErrorCode = (typeof NETWORK_ERROR_CODES)[number] | string;
9
+ export type NetworkErrorBody = {
10
+ code: NetworkErrorCode;
11
+ error: string;
12
+ } & Record<string, unknown>;
13
+ export declare function networkError(code: NetworkErrorCode, error: string, detail?: Record<string, unknown>): NetworkErrorBody;
14
+ export declare function codeOrInternal(code: string | undefined): NetworkErrorCode;
@@ -0,0 +1,59 @@
1
+ /** Stable network-facing error codes (snake_case). Keep strings unchanged once shipped. */
2
+ export const BUSY_CAPACITY = "busy_capacity";
3
+ export const BUSY_CHECKOUT = "busy_checkout";
4
+ /** Per-caller concurrency quota: queued when under global capacity; reject when queue full. */
5
+ export const BUSY_CALLER_QUOTA = "busy_caller_quota";
6
+ export const ABORTED = "aborted";
7
+ export const NETWORK_ERROR_CODES = [
8
+ BUSY_CAPACITY,
9
+ BUSY_CHECKOUT,
10
+ BUSY_CALLER_QUOTA,
11
+ ABORTED,
12
+ "unknown_project_root",
13
+ "absolute_path_not_allowed",
14
+ "path_outside_project_root",
15
+ "catalog_root_unreadable",
16
+ "ensure_project_not_allowed",
17
+ "config_invalid",
18
+ "config_unknown_key",
19
+ "provider_not_configured",
20
+ "a2a_configuration_error",
21
+ "untrusted_config_origin",
22
+ "command_not_on_path",
23
+ "missing_tool",
24
+ "tool_version_mismatch",
25
+ "unknown_version",
26
+ "secret_unavailable",
27
+ "not_ready",
28
+ "internal_error",
29
+ "retry_in_progress",
30
+ "hitl_not_retriable",
31
+ "run_not_retryable",
32
+ "stage_not_failed",
33
+ "manual_recovery_required",
34
+ "run_not_found",
35
+ "stage_not_found",
36
+ "artifact_not_found",
37
+ "artifact_path_denied",
38
+ "envelope_not_found",
39
+ "insufficient_disk",
40
+ "disk_check_failed",
41
+ "shutting_down",
42
+ "start.token_rejected",
43
+ "inline_pipeline_too_large",
44
+ "skills_invalid_name",
45
+ "skills_invalid_path",
46
+ "skills_missing_skill_md",
47
+ "skills_payload_too_large",
48
+ "pinned_sha_unavailable",
49
+ "store_integrity_failed",
50
+ "store_unsupported_filesystem",
51
+ "tmpdir_unusable",
52
+ "backup_insufficient_disk",
53
+ ];
54
+ export function networkError(code, error, detail) {
55
+ return { code, error, ...detail };
56
+ }
57
+ export function codeOrInternal(code) {
58
+ return code && code.length > 0 ? code : "internal_error";
59
+ }
@@ -0,0 +1,14 @@
1
+ export declare function setBareCacheRemoteUrlOverrideForTests(override: ((repository: string) => string | undefined) | null): void;
2
+ export declare function resetBareCacheStateForTests(): void;
3
+ export declare function githubHttpsRemoteUrl(repository: string): string;
4
+ export declare function bareCachePath(repository: string): string;
5
+ export declare function remoteUrlForRepository(repository: string): string;
6
+ export type EnsureBareCacheResult = {
7
+ cachePath: string;
8
+ fetched: boolean;
9
+ };
10
+ export type EnsureBareCacheOptions = {
11
+ env?: NodeJS.ProcessEnv;
12
+ signal?: AbortSignal;
13
+ };
14
+ export declare function ensureBareCache(repository: string, ref: string, options?: EnsureBareCacheOptions): Promise<EnsureBareCacheResult>;