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
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { buildValidationResult, loadPipelineValidated, } from "../config/validateCatalog.js";
4
4
  import { loadTaskFromYaml } from "../config/loadTask.js";
5
- import { resolveAndValidateCheckout } from "./stageRoots.js";
5
+ import { resolveAndValidateCheckout, resolveEffectiveGitIdentity, } from "./stageRoots.js";
6
6
  import { buildPipelineDagSnapshotFromLoaded } from "../runstore/pipelineDagSnapshot.js";
7
7
  import { normalizeCatalogPath } from "../runstore/normalizeCatalogPath.js";
8
8
  import { runPipelineDag } from "./pipelineScheduler.js";
@@ -10,7 +10,55 @@ import { readMaxActiveStagesPerRun, readStageExecutionMode, } from "./stageConcu
10
10
  import { StageProcessLauncher } from "./stageProcessLauncher.js";
11
11
  import { PipelineValidationError } from "./pipelineValidationError.js";
12
12
  import { checkTaskEntryInput } from "./taskInput.js";
13
+ import { pipelinePersistenceForStart } from "./startPayload.js";
14
+ import { materializeRunSkills, } from "./runSkills.js";
15
+ import { preflightFailureCode, runPipelinePreflight, } from "../preflight/pipelinePreflight.js";
16
+ import { networkError } from "../errors/codes.js";
17
+ import { newRunId } from "../runstore/paths.js";
18
+ import { bindingFromFields, buildInitialRunManifest, collectDeclaredSecretValues, finaliseStoredRunManifest, } from "../runstore/runManifest.js";
19
+ import { getRequestAuth, } from "../server/requestAuthContext.js";
20
+ import { registerNamedSecrets } from "../logging/namedSecrets.js";
21
+ import { shouldRegisterValue } from "../logging/redact.js";
13
22
  export { PipelineValidationError } from "./pipelineValidationError.js";
23
+ export class PipelinePreflightError extends Error {
24
+ code;
25
+ preflight;
26
+ constructor(code, preflight) {
27
+ super(`Pipeline preflight failed: ${code}`);
28
+ this.name = "PipelinePreflightError";
29
+ this.code = code;
30
+ this.preflight = preflight;
31
+ }
32
+ toNetworkBody() {
33
+ return networkError(this.code, this.message, {
34
+ checks: this.preflight.checks,
35
+ });
36
+ }
37
+ }
38
+ export class InlinePipelineTooLargeError extends Error {
39
+ code = "inline_pipeline_too_large";
40
+ bytes;
41
+ maxBytes;
42
+ constructor(bytes, maxBytes) {
43
+ super(`Inline pipeline body is ${bytes} bytes; max is ${maxBytes} (inline_pipeline_too_large)`);
44
+ this.name = "InlinePipelineTooLargeError";
45
+ this.bytes = bytes;
46
+ this.maxBytes = maxBytes;
47
+ }
48
+ }
49
+ /** Thrown when queued→running CAS fails (e.g. cancel won the race). */
50
+ export class QueuedRunActivationAborted extends Error {
51
+ runId;
52
+ currentStatus;
53
+ constructor(runId, currentStatus) {
54
+ super(currentStatus === undefined
55
+ ? `Queued run ${runId} could not be activated`
56
+ : `Queued run ${runId} could not be activated (status=${currentStatus})`);
57
+ this.name = "QueuedRunActivationAborted";
58
+ this.runId = runId;
59
+ this.currentStatus = currentStatus;
60
+ }
61
+ }
14
62
  let defaultStageProcessLauncher;
15
63
  function resolveStageProcessLauncher(executionMode, override) {
16
64
  if (executionMode !== "process") {
@@ -34,6 +82,14 @@ async function preparePipeline(options) {
34
82
  throw new PipelineValidationError(buildValidationResult("pipeline", loadResult.findings, false));
35
83
  }
36
84
  const loaded = loadResult.loaded;
85
+ const preflight = await runPipelinePreflight(loaded, {
86
+ projectRoot: options.projectRoot ?? options.cwd,
87
+ forStart: true,
88
+ });
89
+ if (!preflight.ok) {
90
+ const code = preflightFailureCode(preflight, { forStart: true }) ?? "missing_tool";
91
+ throw new PipelinePreflightError(code, preflight);
92
+ }
37
93
  const taskYaml = options.taskYaml ??
38
94
  (options.taskPath
39
95
  ? await readFile(options.taskPath, "utf8")
@@ -56,27 +112,122 @@ async function preparePipeline(options) {
56
112
  for (const finding of warningFindings) {
57
113
  console.error(`${finding.code}: ${finding.message}`);
58
114
  }
59
- const checkoutRoot = await resolveAndValidateCheckout(task, options.checkoutOverride, options.cwd);
115
+ // Materialization is owned by RunManager (KTD1). When checkoutRoot is supplied,
116
+ // do not re-resolve or fetch here.
117
+ const checkoutRoot = options.checkoutRoot !== undefined
118
+ ? options.checkoutRoot
119
+ : await resolveAndValidateCheckout(task, options.checkoutOverride, options.cwd);
60
120
  const pipelinePath = typeof options.pipeline === "string"
61
121
  ? normalizeCatalogPath(loaded.pipelinePath)
62
122
  : undefined;
123
+ const persistence = pipelinePersistenceForStart(options.pipeline);
124
+ if (!persistence.ok) {
125
+ throw new InlinePipelineTooLargeError(persistence.bytes, persistence.maxBytes);
126
+ }
63
127
  const taskPath = options.taskPath
64
128
  ? normalizeCatalogPath(path.resolve(options.cwd, options.taskPath))
65
129
  : undefined;
66
130
  const projectRoot = normalizeCatalogPath(options.projectRoot ?? options.cwd);
67
- const run = await options.store.createRun({
68
- pipelineId: loaded.pipeline.id,
69
- taskYaml,
70
- taskId: task.id,
71
- checkoutRoot,
72
- gitSha: options.gitSha,
73
- ciPrUrl: options.ciPrUrl,
74
- ciJobUrl: options.ciJobUrl,
75
- pipelineDag: buildPipelineDagSnapshotFromLoaded(loaded),
76
- pipelinePath,
77
- taskPath,
78
- projectRoot,
79
- });
131
+ const gitIdentity = resolveEffectiveGitIdentity(process.env, task.git_identity);
132
+ let run;
133
+ if (options.reuseExistingRun === true) {
134
+ const runId = options.runId;
135
+ if (runId === undefined || runId.trim() === "") {
136
+ throw new Error("reuseExistingRun requires a preallocated runId");
137
+ }
138
+ await options.store.patchRunWorkspaceBinding(runId, {
139
+ ...(checkoutRoot !== undefined ? { checkoutRoot } : {}),
140
+ ...(options.repository !== undefined
141
+ ? { repository: options.repository }
142
+ : {}),
143
+ ...(options.ref !== undefined ? { ref: options.ref } : {}),
144
+ ...(options.resolvedSha !== undefined
145
+ ? { resolvedSha: options.resolvedSha }
146
+ : {}),
147
+ ...(options.runBranch !== undefined
148
+ ? { runBranch: options.runBranch }
149
+ : {}),
150
+ });
151
+ const activated = await options.store.tryUpdateRunStatus(runId, "running", "queued");
152
+ if (!activated) {
153
+ let currentStatus;
154
+ try {
155
+ currentStatus = (await options.store.readRunMeta(runId)).status;
156
+ }
157
+ catch {
158
+ currentStatus = undefined;
159
+ }
160
+ throw new QueuedRunActivationAborted(runId, currentStatus);
161
+ }
162
+ run = { runId, workspaceDir: options.store.getWorkspaceDir(runId) };
163
+ }
164
+ else {
165
+ const runId = options.runId ?? newRunId();
166
+ const createdAt = new Date().toISOString();
167
+ const auth = getRequestAuth();
168
+ const surface = auth?.surface ?? "cli";
169
+ const callerId = options.callerId !== undefined && options.callerId !== null
170
+ ? options.callerId
171
+ : null;
172
+ const secretNames = loaded.stages.flatMap((s) => (s.secrets ?? []).map((d) => d.name));
173
+ const namedSecrets = collectDeclaredSecretValues(secretNames).filter((s) => shouldRegisterValue(s.value));
174
+ if (namedSecrets.length > 0) {
175
+ registerNamedSecrets(namedSecrets);
176
+ }
177
+ const runManifest = buildInitialRunManifest({
178
+ runId,
179
+ createdAt,
180
+ callerId,
181
+ surface,
182
+ binding: bindingFromFields({
183
+ repository: options.repository,
184
+ ref: options.ref,
185
+ resolvedSha: options.resolvedSha,
186
+ runBranch: options.runBranch,
187
+ checkoutRoot,
188
+ }),
189
+ pipelineSource: persistence.fields.pipelineSource,
190
+ pipelinePath,
191
+ pipelineBody: persistence.fields.pipelineBody ?? null,
192
+ taskYaml,
193
+ taskPath,
194
+ skills: options.skills,
195
+ stages: loaded.stages,
196
+ toolchain: preflight.toolchain.checks,
197
+ namedSecrets,
198
+ });
199
+ run = await options.store.createRun({
200
+ submission: options.submission,
201
+ runId,
202
+ pipelineId: loaded.pipeline.id,
203
+ taskYaml,
204
+ taskId: task.id,
205
+ checkoutRoot,
206
+ gitSha: options.gitSha,
207
+ ciPrUrl: options.ciPrUrl,
208
+ ciJobUrl: options.ciJobUrl,
209
+ pipelineDag: buildPipelineDagSnapshotFromLoaded(loaded),
210
+ pipelinePath,
211
+ taskPath,
212
+ projectRoot,
213
+ repository: options.repository,
214
+ ref: options.ref,
215
+ resolvedSha: options.resolvedSha,
216
+ runBranch: options.runBranch,
217
+ gitAuthorName: gitIdentity.name,
218
+ gitAuthorEmail: gitIdentity.email,
219
+ pipelineSource: persistence.fields.pipelineSource,
220
+ ...(persistence.fields.pipelineBody !== undefined
221
+ ? { pipelineBody: persistence.fields.pipelineBody }
222
+ : {}),
223
+ ...(callerId !== null ? { callerId } : {}),
224
+ runManifest,
225
+ skipGates: options.skipGates,
226
+ });
227
+ }
228
+ if (options.skills !== undefined && Object.keys(options.skills).length > 0) {
229
+ await materializeRunSkills(run.workspaceDir, options.skills);
230
+ }
80
231
  const executionMode = readStageExecutionMode(process.env, options.executionMode);
81
232
  const stageProcessLauncher = resolveStageProcessLauncher(executionMode, options.stageProcessLauncher);
82
233
  return {
@@ -110,6 +261,7 @@ export async function executeStages(prepared, options) {
110
261
  startAtStageIndex: options?.startAtStageIndex,
111
262
  executionMode,
112
263
  stageProcessLauncher,
264
+ schedulingHalt: options?.schedulingHalt,
113
265
  });
114
266
  if (prepared.findings !== undefined && prepared.findings.length > 0) {
115
267
  return { ...result, findings: prepared.findings };
@@ -145,6 +297,7 @@ export async function startPipeline(options) {
145
297
  const cwd = options.cwd ?? process.cwd();
146
298
  const projectRoot = options.projectRoot ?? cwd;
147
299
  const prepared = await preparePipeline({
300
+ submission: options.submission,
148
301
  agent: options.agent,
149
302
  store: options.store,
150
303
  taskPath: options.taskPath,
@@ -153,6 +306,13 @@ export async function startPipeline(options) {
153
306
  cwd,
154
307
  projectRoot,
155
308
  checkoutOverride: options.checkoutOverride,
309
+ runId: options.runId,
310
+ reuseExistingRun: options.reuseExistingRun,
311
+ checkoutRoot: options.checkoutRoot,
312
+ repository: options.repository,
313
+ ref: options.ref,
314
+ resolvedSha: options.resolvedSha,
315
+ runBranch: options.runBranch,
156
316
  gitSha: options.gitSha,
157
317
  ciPrUrl: options.ciPrUrl,
158
318
  ciJobUrl: options.ciJobUrl,
@@ -161,13 +321,17 @@ export async function startPipeline(options) {
161
321
  stageProcessLauncher: options.stageProcessLauncher,
162
322
  operatorCatalog: options.operatorCatalog,
163
323
  skipGates: options.skipGates,
324
+ callerId: options.callerId,
325
+ ...(options.skills !== undefined ? { skills: options.skills } : {}),
164
326
  });
165
327
  const done = executeStages(prepared, {
166
328
  maxActiveStagesPerRun: options.maxActiveStagesPerRun,
167
329
  executionMode: prepared.executionMode,
168
330
  stageProcessLauncher: prepared.stageProcessLauncher,
331
+ schedulingHalt: options.schedulingHalt,
169
332
  }).catch(async (err) => {
170
333
  await prepared.store.updateRunStatus(prepared.run.runId, "failed").catch(() => undefined);
334
+ await finaliseStoredRunManifest(prepared.store, prepared.run.runId).catch(() => undefined);
171
335
  return {
172
336
  ok: false,
173
337
  outcome: "failed",
@@ -61,7 +61,13 @@ export type ResumeRunOptions = {
61
61
  initialPrior?: StageEnvelope | null;
62
62
  executionMode?: StageExecutionMode;
63
63
  stageProcessLauncher?: StageProcessLauncher;
64
+ schedulingHalt?: {
65
+ halted: boolean;
66
+ hostShutdown?: boolean;
67
+ };
64
68
  };
69
+ /** Refuses to overwrite a cancelled run (KTD7). */
70
+ export declare function writeTerminalRunStatus(store: RunStore, runId: string, status: "succeeded" | "failed"): Promise<void>;
65
71
  export declare function resumeRun(options: ResumeRunOptions): Promise<PipelineRunResult>;
66
72
  export type RunPipelineDagOptions = {
67
73
  prepared: SchedulerPreparedPipeline;
@@ -87,6 +93,11 @@ export type RunPipelineDagOptions = {
87
93
  sourceStageId: string;
88
94
  resolve: (decision: FeedbackLoopDecisionInput) => Promise<ResolveFeedbackLoopDecisionResult>;
89
95
  }) => Promise<void>;
96
+ /** Live cancel flag — when set, launchStage/startStage stop. */
97
+ schedulingHalt?: {
98
+ halted: boolean;
99
+ hostShutdown?: boolean;
100
+ };
90
101
  };
91
102
  export type RetryRunOptions = {
92
103
  prepared: SchedulerPreparedPipeline;
@@ -97,6 +108,10 @@ export type RetryRunOptions = {
97
108
  mutationQueue?: RetryMutationQueue;
98
109
  onLoopTick?: () => void | Promise<void>;
99
110
  onRetryRootTerminal?: OnRetryRootTerminal;
111
+ schedulingHalt?: {
112
+ halted: boolean;
113
+ hostShutdown?: boolean;
114
+ };
100
115
  };
101
116
  export declare function retryRun(options: RetryRunOptions): Promise<PipelineRunResult>;
102
117
  export declare function applyForkSkipsFromEnvelopes(dag: ResolvedPipelineDag, states: Map<string, StageScheduleState>, completedEnvelopes: Map<string, StageEnvelope>): void;
@@ -1,4 +1,5 @@
1
1
  import { normalizeForkChoice } from "../envelope/forkChoice.js";
2
+ import { refreshRunDiskUsage } from "../runstore/diskUsage.js";
2
3
  import { buildPipelineDagSnapshotFromLoaded } from "../runstore/pipelineDagSnapshot.js";
3
4
  import { definitionIdForInstance } from "../runstore/stageInstanceId.js";
4
5
  import { cloneFailureContinuesSchedule, cloneRetryDownstream, cloneFailFastSkipIds, cloneScheduleAllowsRun, failureIsAccepted, isCloneInstance, mint, protectedClonableChildIds, sequentialLaterCloneIds, skipRejectedNeedDependents, } from "./cloneSchedule.js";
@@ -8,8 +9,18 @@ import { reopenRunnableSkippedStages, persistReopenedStages } from "./reopenSkip
8
9
  import { forkChoicePreservesReplaySource, forkCohortMapsFromStore, mintCohortForFanout, } from "./forkGeneration.js";
9
10
  import { activeReplayId, activeSourceStageId, applySendBack, createReplaySchedule, hydrateFromStore, isHeld, launchAttemptFor, launchFor, noteActiveCohort, onContinued, onRouteStageFailed, onRouteStageRunning, onRouteStageSucceeded, rebindRouteAttempts, resolveDecision, } from "./replayLifecycle.js";
10
11
  import { WAIT_WITHOUT_WORKER_DISPATCH } from "./answerResume.js";
12
+ import { reclaimWorkspaceOnRunSucceeded } from "./repositoryMaterialize.js";
13
+ import { syncRunStatusFromStages } from "./stageRecovery.js";
11
14
  import { runStage, isRunStageWaiting } from "./stageRunner.js";
12
15
  import { attemptContext, resumeSessionFilePath } from "./stageAttemptContext.js";
16
+ import { stageBindingEnvFromRun } from "./stageRoots.js";
17
+ import { attemptWorkspaceDir } from "../runstore/workspaceLayout.js";
18
+ import { cleanupCredentialsDir, loadSecretRegistry, resolveStageSecrets, SecretUnavailableError, } from "./stageSecrets.js";
19
+ import { mkdir, writeFile } from "node:fs/promises";
20
+ import path from "node:path";
21
+ import { logger as rootLogger, } from "../logging/logger.js";
22
+ import { registerNamedSecrets, REDACTION_SECRETS_FILENAME } from "../logging/namedSecrets.js";
23
+ import { finaliseStoredRunManifest } from "../runstore/runManifest.js";
13
24
  function asDagSnapshot(dag) {
14
25
  const snapshot = dag;
15
26
  if (Array.isArray(snapshot.stage_ids))
@@ -35,6 +46,8 @@ export function snapshotToScheduleState(snap, overrides, stageId, executionMode)
35
46
  return "active";
36
47
  case "waiting_for_input":
37
48
  return executionMode === "process" ? "waiting" : "active";
49
+ case "interrupted":
50
+ return "waiting";
38
51
  case "skipped":
39
52
  return "skipped";
40
53
  default:
@@ -136,6 +149,18 @@ export async function hydrateScheduleForRetryRoots(store, runId, dag, retryStage
136
149
  export async function hydrateScheduleForRetry(store, runId, dag, retryStageId) {
137
150
  return hydrateScheduleForRetryRoots(store, runId, dag, [retryStageId]);
138
151
  }
152
+ /** Refuses to overwrite a cancelled run (KTD7). */
153
+ export async function writeTerminalRunStatus(store, runId, status) {
154
+ const meta = await store.readRunMeta(runId);
155
+ if (meta.status === "cancelled")
156
+ return;
157
+ await store.updateRunStatus(runId, status);
158
+ await finaliseStoredRunManifest(store, runId).catch(() => undefined);
159
+ await refreshRunDiskUsage(store, runId).catch(() => undefined);
160
+ if (status === "succeeded") {
161
+ await reclaimWorkspaceOnRunSucceeded(store, runId);
162
+ }
163
+ }
139
164
  export async function resumeRun(options) {
140
165
  const { prepared, resumeFromStageId, initialPrior } = options;
141
166
  const meta = await prepared.store.readRunMeta(prepared.run.runId);
@@ -165,7 +190,7 @@ export async function resumeRun(options) {
165
190
  });
166
191
  if (allTerminal) {
167
192
  const unhandledFailure = scheduleHasUnhandledFailure(dag, hydrated.states);
168
- await prepared.store.updateRunStatus(prepared.run.runId, unhandledFailure ? "failed" : "succeeded");
193
+ await writeTerminalRunStatus(prepared.store, prepared.run.runId, unhandledFailure ? "failed" : "succeeded");
169
194
  return {
170
195
  ok: !unhandledFailure,
171
196
  outcome: unhandledFailure ? "failed" : "succeeded",
@@ -191,6 +216,7 @@ export async function retryRun(options) {
191
216
  mutationQueue: options.mutationQueue,
192
217
  onLoopTick: options.onLoopTick,
193
218
  onRetryRootTerminal: options.onRetryRootTerminal,
219
+ schedulingHalt: options.schedulingHalt,
194
220
  });
195
221
  }
196
222
  function applyForkChoiceToSchedule(dag, forkStageId, chosen, states, options) {
@@ -220,6 +246,25 @@ export function applyForkSkipsFromEnvelopes(dag, states, completedEnvelopes) {
220
246
  applyForkChoiceToSchedule(dag, node.id, chosen, states);
221
247
  }
222
248
  }
249
+ async function applyEagerRouteIfSkipsFromEnvelopes(dag, states, completedEnvelopes, persistSkip) {
250
+ for (const [parentId, envelope] of completedEnvelopes) {
251
+ if (states.get(parentId) !== "succeeded")
252
+ continue;
253
+ for (const childId of dag.childrenOf[parentId] ?? []) {
254
+ const child = dag.nodes.find((n) => n.id === childId);
255
+ if (!child)
256
+ continue;
257
+ const result = classifyInboundAfterSuccess(child, parentId, envelope.payload);
258
+ if (result === "missing_field") {
259
+ return parentId;
260
+ }
261
+ if (isEagerSingleParentIfSkip(child, parentId, envelope.payload)) {
262
+ await persistSkip(childId);
263
+ }
264
+ }
265
+ }
266
+ return undefined;
267
+ }
223
268
  export function applyRetryRootDelta(dag, states, completedEnvelopes, retryRoots, stageId, attempt, clearSchedulingHalt, alreadyLaunchedIds) {
224
269
  retryRoots.set(stageId, attempt);
225
270
  const downstream = cloneRetryDownstream(dag, [stageId]);
@@ -330,10 +375,16 @@ export async function runPipelineDag(options) {
330
375
  let { states, completedEnvelopes, schedulingHalted, firstFailureReason, dag: hydratedDag, } = options.initialSchedule ??
331
376
  (await hydrateScheduleFromStore(store, run.runId, fallbackDag, executionMode));
332
377
  let dag = hydratedDag ?? fallbackDag;
378
+ const runMeta = await store.readRunMeta(run.runId);
333
379
  if (hydratedDag === undefined) {
334
- const meta = await store.readRunMeta(run.runId);
335
- dag = meta.pipeline_dag ?? fallbackDag;
380
+ dag = runMeta.pipeline_dag ?? fallbackDag;
336
381
  }
382
+ const stageBinding = stageBindingEnvFromRun({
383
+ meta: runMeta,
384
+ task,
385
+ runWorkspaceDir: run.workspaceDir,
386
+ hostEnv: process.env,
387
+ });
337
388
  const stageById = buildStageConfigById(loaded);
338
389
  const retryContext = options.retryContext;
339
390
  const feedbackSchedule = createReplaySchedule();
@@ -472,6 +523,13 @@ export async function runPipelineDag(options) {
472
523
  await persistSkipPending(id);
473
524
  }
474
525
  }
526
+ const missingRouteIfParent = await applyEagerRouteIfSkipsFromEnvelopes(dag, states, completedEnvelopes, persistSkipPending);
527
+ if (missingRouteIfParent !== undefined) {
528
+ schedulingHalted = true;
529
+ if (firstFailureReason === undefined) {
530
+ firstFailureReason = `stage "${missingRouteIfParent}": route if field missing from payload`;
531
+ }
532
+ }
475
533
  const markSkippedPending = () => {
476
534
  for (const node of dag.nodes) {
477
535
  if (states.get(node.id) === "pending") {
@@ -756,22 +814,13 @@ export async function runPipelineDag(options) {
756
814
  await store.appendStageEvent(run.runId, id, { event: "skipped" });
757
815
  }
758
816
  }
759
- const childIds = dag.childrenOf[stageId] ?? [];
760
- for (const childId of childIds) {
761
- const child = dag.nodes.find((node) => node.id === childId);
762
- if (!child)
763
- continue;
764
- const result = classifyInboundAfterSuccess(child, stageId, envelope.payload);
765
- if (result === "missing_field") {
766
- schedulingHalted = true;
767
- if (firstFailureReason === undefined) {
768
- firstFailureReason = `stage "${stageId}": route if field missing from payload`;
769
- }
770
- return;
771
- }
772
- if (isEagerSingleParentIfSkip(child, stageId, envelope.payload)) {
773
- await persistSkipPending(childId);
817
+ const missingParent = await applyEagerRouteIfSkipsFromEnvelopes(dag, states, new Map([[stageId, envelope]]), persistSkipPending);
818
+ if (missingParent !== undefined) {
819
+ schedulingHalted = true;
820
+ if (firstFailureReason === undefined) {
821
+ firstFailureReason = `stage "${missingParent}": route if field missing from payload`;
774
822
  }
823
+ return;
775
824
  }
776
825
  await reopenRunnableSkippedStages(store, run.runId, dag, states, completedEnvelopes);
777
826
  };
@@ -810,32 +859,83 @@ export async function runPipelineDag(options) {
810
859
  stageId,
811
860
  });
812
861
  }
862
+ const attemptDir = attemptWorkspaceDir(run.workspaceDir, stageId, attempt);
863
+ await mkdir(attemptDir, { recursive: true });
864
+ const attemptHome = path.join(attemptDir, "home");
865
+ await mkdir(attemptHome, { recursive: true });
866
+ let grants;
867
+ try {
868
+ const resolved = resolveStageSecrets({
869
+ decls: stage.secrets,
870
+ registry: loadSecretRegistry(process.env),
871
+ hostEnv: process.env,
872
+ attemptDir,
873
+ });
874
+ grants = resolved.grants;
875
+ registerNamedSecrets(resolved.knownValues);
876
+ await writeFile(path.join(attemptDir, REDACTION_SECRETS_FILENAME), `${JSON.stringify(resolved.knownValues)}\n`, { encoding: "utf8", mode: 0o600 });
877
+ for (const warning of resolved.warnings) {
878
+ rootLogger.warn("stage.secrets", warning, {
879
+ run_id: run.runId,
880
+ stage_id: stageId,
881
+ });
882
+ }
883
+ await writeFile(path.join(attemptDir, "declared-secrets.json"), `${JSON.stringify({ names: grants.declaredSecretNames }, null, 2)}\n`, "utf8");
884
+ }
885
+ catch (err) {
886
+ const reason = err instanceof SecretUnavailableError
887
+ ? err.message
888
+ : err instanceof Error
889
+ ? err.message
890
+ : String(err);
891
+ await onStageFailure(stageId, reason);
892
+ return;
893
+ }
894
+ const cleanupAttemptCredentials = () => {
895
+ try {
896
+ cleanupCredentialsDir(attemptDir);
897
+ }
898
+ catch {
899
+ // best-effort Host cleanup
900
+ }
901
+ };
813
902
  if (executionMode === "process") {
814
903
  const launcher = options.stageProcessLauncher;
815
904
  if (!launcher) {
905
+ cleanupAttemptCredentials();
816
906
  await onStageFailure(stageId, "stage process launcher is not configured");
817
907
  return;
818
908
  }
819
- const launchResult = await launcher.launch({
820
- runId: run.runId,
821
- stageId,
822
- rootDir: factoryCwd,
823
- attempt,
824
- ...(sessionMode !== undefined
825
- ? {
826
- mode: sessionMode === "feedback_resume"
827
- ? "feedback_resume"
828
- : sessionMode === "new_session"
829
- ? "new_session"
830
- : "run",
831
- }
832
- : {}),
833
- ...(resumeToken !== undefined ? { sessionFilePath: resumeToken } : {}),
834
- ...(prepared.operatorCatalog !== undefined
835
- ? { operatorCatalog: prepared.operatorCatalog }
836
- : {}),
837
- ...(prepared.skipGates ? { skipGates: true } : {}),
838
- });
909
+ let launchResult;
910
+ try {
911
+ launchResult = await launcher.launch({
912
+ runId: run.runId,
913
+ stageId,
914
+ rootDir: factoryCwd,
915
+ attempt,
916
+ env: stageBinding.env,
917
+ bindingKind: stageBinding.kind,
918
+ grants,
919
+ attemptHome,
920
+ ...(sessionMode !== undefined
921
+ ? {
922
+ mode: sessionMode === "feedback_resume"
923
+ ? "feedback_resume"
924
+ : sessionMode === "new_session"
925
+ ? "new_session"
926
+ : "run",
927
+ }
928
+ : {}),
929
+ ...(resumeToken !== undefined ? { sessionFilePath: resumeToken } : {}),
930
+ ...(prepared.operatorCatalog !== undefined
931
+ ? { operatorCatalog: prepared.operatorCatalog }
932
+ : {}),
933
+ ...(prepared.skipGates ? { skipGates: true } : {}),
934
+ });
935
+ }
936
+ finally {
937
+ cleanupAttemptCredentials();
938
+ }
839
939
  if (launchResult.type === "succeeded") {
840
940
  try {
841
941
  const envelope = await store.readEnvelope(run.runId, stageId);
@@ -851,6 +951,10 @@ export async function runPipelineDag(options) {
851
951
  states.set(stageId, "waiting");
852
952
  return;
853
953
  }
954
+ if (options.schedulingHalt?.hostShutdown) {
955
+ states.set(stageId, "waiting");
956
+ return;
957
+ }
854
958
  await onStageFailure(stageId, launchResult.reason);
855
959
  return;
856
960
  }
@@ -870,15 +974,25 @@ export async function runPipelineDag(options) {
870
974
  operatorCatalog: prepared.operatorCatalog,
871
975
  completedEnvelopes,
872
976
  skipGates: prepared.skipGates,
977
+ stageEnv: {
978
+ ...stageBinding.env,
979
+ ...grants.env,
980
+ HOME: attemptHome,
981
+ },
873
982
  ...(sessionMode !== undefined ? { sessionMode } : {}),
874
983
  ...(feedbackLoopContext !== undefined ? { feedbackLoopContext } : {}),
875
984
  ...(resumeToken !== undefined ? { resumeToken } : {}),
876
985
  });
986
+ cleanupAttemptCredentials();
877
987
  if (isRunStageWaiting(result)) {
878
988
  await onStageFailure(stageId, WAIT_WITHOUT_WORKER_DISPATCH);
879
989
  return;
880
990
  }
881
991
  if (!result.ok) {
992
+ if (options.schedulingHalt?.hostShutdown) {
993
+ states.set(stageId, "waiting");
994
+ return;
995
+ }
882
996
  await onStageFailure(stageId, result.reason ?? "stage failed", result.envelope);
883
997
  return;
884
998
  }
@@ -927,11 +1041,17 @@ export async function runPipelineDag(options) {
927
1041
  return true;
928
1042
  };
929
1043
  while (!allTerminal()) {
1044
+ if (options.schedulingHalt?.halted) {
1045
+ schedulingHalted = true;
1046
+ }
930
1047
  drainRetryMutations();
931
1048
  await applyStalledJoinSkips();
932
1049
  if (options.onLoopTick !== undefined) {
933
1050
  await options.onLoopTick();
934
1051
  }
1052
+ if (options.schedulingHalt?.halted) {
1053
+ schedulingHalted = true;
1054
+ }
935
1055
  if (!schedulingHalted) {
936
1056
  const runnable = pickRunnable();
937
1057
  for (const stageId of runnable) {
@@ -975,11 +1095,16 @@ export async function runPipelineDag(options) {
975
1095
  if (schedulingHalted) {
976
1096
  markSkippedPending();
977
1097
  if (retryContext === undefined) {
978
- await store.updateRunStatus(run.runId, "failed");
1098
+ if (options.schedulingHalt?.hostShutdown) {
1099
+ await syncRunStatusFromStages(store, run.runId);
1100
+ }
1101
+ else {
1102
+ await writeTerminalRunStatus(store, run.runId, "failed");
1103
+ }
979
1104
  }
980
1105
  return {
981
1106
  ok: false,
982
- outcome: "failed",
1107
+ outcome: options.schedulingHalt?.hostShutdown ? "waiting" : "failed",
983
1108
  runDir: run.workspaceDir,
984
1109
  runId: run.runId,
985
1110
  reason: firstFailureReason,
@@ -987,7 +1112,7 @@ export async function runPipelineDag(options) {
987
1112
  }
988
1113
  if (scheduleHasUnhandledFailure(dag, states) || !allTerminal()) {
989
1114
  if (retryContext === undefined) {
990
- await store.updateRunStatus(run.runId, "failed");
1115
+ await writeTerminalRunStatus(store, run.runId, "failed");
991
1116
  }
992
1117
  return {
993
1118
  ok: false,
@@ -997,7 +1122,7 @@ export async function runPipelineDag(options) {
997
1122
  reason: firstFailureReason ?? "pipeline incomplete",
998
1123
  };
999
1124
  }
1000
- await store.updateRunStatus(run.runId, "succeeded");
1125
+ await writeTerminalRunStatus(store, run.runId, "succeeded");
1001
1126
  return {
1002
1127
  ok: true,
1003
1128
  outcome: "succeeded",
@@ -1,5 +1,5 @@
1
1
  import { access } from "node:fs/promises";
2
- import { loadPipeline } from "../config/loadPipeline.js";
2
+ import { loadPipeline, loadPipelineFromObject } from "../config/loadPipeline.js";
3
3
  import { loadTask } from "../config/loadTask.js";
4
4
  import { normalizeCatalogPath } from "../runstore/normalizeCatalogPath.js";
5
5
  function missingLocator(field, runId) {
@@ -32,6 +32,17 @@ async function assertCatalogFileExists(filePath, label) {
32
32
  }
33
33
  }
34
34
  export async function reloadPipelineForRun(meta) {
35
+ // An inline-pipeline run (no pipeline_path — nothing was ever written to a
36
+ // catalog file) carries its own pipeline body in meta.inline_pipeline
37
+ // instead, the same way a task without task_path reloads from task_yaml.
38
+ // Prefer this before requiring path locators; project_root is optional and
39
+ // falls back to cwd (same as loadPipelineFromObject).
40
+ if (meta.inline_pipeline) {
41
+ const projectRoot = meta.project_root
42
+ ? normalizeCatalogPath(meta.project_root)
43
+ : process.cwd();
44
+ return loadPipelineFromObject(meta.inline_pipeline, { projectRoot });
45
+ }
35
46
  const projectRoot = requireProjectRoot(meta);
36
47
  const pipelinePath = requirePipelinePath(meta);
37
48
  await assertCatalogFileExists(pipelinePath, "Pipeline");