stageflow 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (501) hide show
  1. package/README.md +10 -3
  2. package/dist/a2a/contracts.d.ts +1 -0
  3. package/dist/a2a/contracts.js +1 -0
  4. package/dist/a2a/registry.d.ts +2 -0
  5. package/dist/a2a/registry.js +20 -1
  6. package/dist/a2a/server.d.ts +7 -0
  7. package/dist/a2a/server.js +5 -2
  8. package/dist/a2a/service.d.ts +1 -1
  9. package/dist/a2a/service.js +57 -8
  10. package/dist/a2a/store.d.ts +8 -5
  11. package/dist/a2a/store.js +24 -67
  12. package/dist/agent/activity.d.ts +3 -0
  13. package/dist/agent/bootProviderConfig.d.ts +21 -0
  14. package/dist/agent/bootProviderConfig.js +74 -0
  15. package/dist/agent/piAdapter.d.ts +9 -1
  16. package/dist/agent/piAdapter.js +58 -3
  17. package/dist/agent/piIsolatedMcp.d.ts +2 -0
  18. package/dist/agent/piIsolatedMcp.js +10 -2
  19. package/dist/agent/port.d.ts +6 -0
  20. package/dist/agent/streamLogRedact.d.ts +1 -1
  21. package/dist/agent/streamLogRedact.js +4 -11
  22. package/dist/cli/artifactCommand.js +9 -16
  23. package/dist/cli/backupCommand.d.ts +9 -0
  24. package/dist/cli/backupCommand.js +111 -0
  25. package/dist/cli/debugRunCommand.d.ts +10 -0
  26. package/dist/cli/debugRunCommand.js +109 -0
  27. package/dist/cli/doctorCommand.d.ts +32 -0
  28. package/dist/cli/doctorCommand.js +453 -0
  29. package/dist/cli/envelopeCommand.js +9 -2
  30. package/dist/cli/exportAllCommand.d.ts +55 -0
  31. package/dist/cli/exportAllCommand.js +218 -0
  32. package/dist/cli/exportRunCommand.js +23 -21
  33. package/dist/cli/hostClient.d.ts +21 -3
  34. package/dist/cli/hostClient.js +93 -12
  35. package/dist/cli/initTemplates.d.ts +1 -1
  36. package/dist/cli/initTemplates.js +8 -1
  37. package/dist/cli/resolveSafeOutPath.d.ts +2 -0
  38. package/dist/cli/resolveSafeOutPath.js +40 -0
  39. package/dist/cli/restoreCommand.d.ts +10 -0
  40. package/dist/cli/restoreCommand.js +90 -0
  41. package/dist/cli/runCommand.d.ts +3 -2
  42. package/dist/cli/runCommand.js +93 -11
  43. package/dist/cli/runOutput.d.ts +4 -0
  44. package/dist/cli/runOutput.js +33 -7
  45. package/dist/cli/runStageCommand.d.ts +1 -0
  46. package/dist/cli/runStageCommand.js +44 -25
  47. package/dist/cli/runsCommand.d.ts +1 -1
  48. package/dist/cli/runsCommand.js +162 -8
  49. package/dist/cli.js +171 -30
  50. package/dist/config/catalogRelativePath.d.ts +62 -0
  51. package/dist/config/catalogRelativePath.js +118 -0
  52. package/dist/config/configOrigin.d.ts +27 -0
  53. package/dist/config/configOrigin.js +59 -0
  54. package/dist/config/hostConfig.d.ts +55 -0
  55. package/dist/config/hostConfig.js +333 -0
  56. package/dist/config/listSkills.d.ts +26 -0
  57. package/dist/config/listSkills.js +190 -3
  58. package/dist/config/loadOutcome.d.ts +1 -1
  59. package/dist/config/loadPipeline.js +23 -2
  60. package/dist/config/loadStage.js +18 -0
  61. package/dist/config/loadTask.d.ts +2 -0
  62. package/dist/config/loadTask.js +57 -18
  63. package/dist/config/materializeStageModels.js +5 -1
  64. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  65. package/dist/config/mergePipelineIncludes.js +19 -0
  66. package/dist/config/migrateYaml.js +6 -11
  67. package/dist/config/multiProjectCatalog.d.ts +30 -0
  68. package/dist/config/multiProjectCatalog.js +142 -0
  69. package/dist/config/normalizePipelineStageEntry.js +20 -1
  70. package/dist/config/pipelineStageKeys.js +2 -0
  71. package/dist/config/resolveCatalogRoots.d.ts +27 -0
  72. package/dist/config/resolveCatalogRoots.js +76 -0
  73. package/dist/config/resolveModel.d.ts +7 -1
  74. package/dist/config/resolveModel.js +11 -1
  75. package/dist/config/resolveStageMcpServers.d.ts +9 -1
  76. package/dist/config/resolveStageMcpServers.js +36 -9
  77. package/dist/config/secretFromEnvOrFile.d.ts +9 -0
  78. package/dist/config/secretFromEnvOrFile.js +34 -0
  79. package/dist/config/seededCatalog.d.ts +11 -0
  80. package/dist/config/seededCatalog.js +29 -0
  81. package/dist/config/toolRequires.d.ts +24 -0
  82. package/dist/config/toolRequires.js +115 -0
  83. package/dist/config/validateCatalog.d.ts +5 -1
  84. package/dist/config/validateCatalog.js +140 -1
  85. package/dist/diagnostics/checks.d.ts +39 -0
  86. package/dist/diagnostics/checks.js +135 -0
  87. package/dist/errors/codes.d.ts +14 -0
  88. package/dist/errors/codes.js +59 -0
  89. package/dist/git/cache.d.ts +14 -0
  90. package/dist/git/cache.js +150 -0
  91. package/dist/git/credentials.d.ts +9 -0
  92. package/dist/git/credentials.js +88 -0
  93. package/dist/git/errors.d.ts +20 -0
  94. package/dist/git/errors.js +94 -0
  95. package/dist/git/exec.d.ts +16 -0
  96. package/dist/git/exec.js +135 -0
  97. package/dist/git/operations.d.ts +29 -0
  98. package/dist/git/operations.js +153 -0
  99. package/dist/git/version.d.ts +1 -0
  100. package/dist/git/version.js +10 -0
  101. package/dist/logging/audit.d.ts +16 -0
  102. package/dist/logging/audit.js +19 -0
  103. package/dist/logging/commonWords.d.ts +2 -0
  104. package/dist/logging/commonWords.js +13 -0
  105. package/dist/logging/logger.d.ts +49 -0
  106. package/dist/logging/logger.js +193 -0
  107. package/dist/logging/namedSecrets.d.ts +6 -0
  108. package/dist/logging/namedSecrets.js +58 -0
  109. package/dist/logging/redact.d.ts +13 -0
  110. package/dist/logging/redact.js +88 -0
  111. package/dist/mcp/catalogTools.js +456 -80
  112. package/dist/mcp/checkoutTools.d.ts +52 -0
  113. package/dist/mcp/checkoutTools.js +332 -0
  114. package/dist/mcp/controlTools.js +179 -5
  115. package/dist/mcp/deps.d.ts +1 -0
  116. package/dist/mcp/getStartedTool.d.ts +3 -0
  117. package/dist/mcp/getStartedTool.js +62 -0
  118. package/dist/mcp/readArtifact.d.ts +11 -0
  119. package/dist/mcp/readArtifact.js +46 -30
  120. package/dist/mcp/server.js +1 -0
  121. package/dist/mcp/tools.js +4 -0
  122. package/dist/net/proxy.d.ts +14 -0
  123. package/dist/net/proxy.js +78 -0
  124. package/dist/package-meta.d.ts +2 -1
  125. package/dist/package-meta.js +2 -1
  126. package/dist/preflight/bash.d.ts +8 -0
  127. package/dist/preflight/bash.js +34 -0
  128. package/dist/preflight/claudeRoot.d.ts +11 -0
  129. package/dist/preflight/claudeRoot.js +23 -0
  130. package/dist/preflight/mcpCommands.d.ts +8 -0
  131. package/dist/preflight/mcpCommands.js +36 -0
  132. package/dist/preflight/pipelinePreflight.d.ts +40 -0
  133. package/dist/preflight/pipelinePreflight.js +192 -0
  134. package/dist/preflight/tls.d.ts +6 -0
  135. package/dist/preflight/tls.js +18 -0
  136. package/dist/preflight/toolchain.d.ts +45 -0
  137. package/dist/preflight/toolchain.js +219 -0
  138. package/dist/project/findProjectRoot.js +3 -4
  139. package/dist/project/globalHome.d.ts +7 -0
  140. package/dist/project/globalHome.js +63 -2
  141. package/dist/project/resolveProjectContext.js +2 -2
  142. package/dist/project/resolveStageflowContext.js +2 -2
  143. package/dist/projection/projectRun.d.ts +2 -1
  144. package/dist/projection/projectRun.js +1 -0
  145. package/dist/runstore/assertTmpdir.d.ts +1 -0
  146. package/dist/runstore/assertTmpdir.js +21 -0
  147. package/dist/runstore/backup.d.ts +52 -0
  148. package/dist/runstore/backup.js +292 -0
  149. package/dist/runstore/createStore.d.ts +18 -1
  150. package/dist/runstore/createStore.js +64 -5
  151. package/dist/runstore/debugBundle.d.ts +60 -0
  152. package/dist/runstore/debugBundle.js +143 -0
  153. package/dist/runstore/diskUsage.d.ts +50 -0
  154. package/dist/runstore/diskUsage.js +214 -0
  155. package/dist/runstore/exportRunPayload.d.ts +8 -0
  156. package/dist/runstore/exportRunPayload.js +23 -0
  157. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  158. package/dist/runstore/normalizeCatalogPath.js +10 -0
  159. package/dist/runstore/paths.d.ts +5 -0
  160. package/dist/runstore/paths.js +145 -1
  161. package/dist/runstore/port.d.ts +111 -13
  162. package/dist/runstore/port.js +8 -1
  163. package/dist/runstore/restore.d.ts +81 -0
  164. package/dist/runstore/restore.js +355 -0
  165. package/dist/runstore/retention.d.ts +27 -0
  166. package/dist/runstore/retention.js +74 -0
  167. package/dist/runstore/runManifest.d.ts +146 -0
  168. package/dist/runstore/runManifest.js +288 -0
  169. package/dist/runstore/runProjection.d.ts +3 -1
  170. package/dist/runstore/runProjection.js +63 -1
  171. package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -3
  172. package/dist/runstore/sqlite/SqliteRunStore.js +352 -219
  173. package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
  174. package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
  175. package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
  176. package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
  177. package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
  178. package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
  179. package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
  180. package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
  181. package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
  182. package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
  183. package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
  184. package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
  185. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
  186. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
  187. package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
  188. package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
  189. package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
  190. package/dist/runstore/sqlite/migrations/index.js +72 -0
  191. package/dist/runstore/sqlite/schema.d.ts +20 -1
  192. package/dist/runstore/sqlite/schema.js +277 -1
  193. package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
  194. package/dist/runstore/sqlite/storeOpenError.js +11 -0
  195. package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
  196. package/dist/runstore/sqlite/storeSchemaError.js +8 -0
  197. package/dist/runstore/stageExecution.js +3 -0
  198. package/dist/runstore/storeFilesystem.d.ts +32 -0
  199. package/dist/runstore/storeFilesystem.js +148 -0
  200. package/dist/runstore/trackProjection.js +2 -0
  201. package/dist/runstore/workspaceLayout.d.ts +13 -0
  202. package/dist/runstore/workspaceLayout.js +76 -0
  203. package/dist/runtime/completionCheckRunner.d.ts +3 -0
  204. package/dist/runtime/completionCheckRunner.js +45 -7
  205. package/dist/runtime/containerLimits.d.ts +16 -0
  206. package/dist/runtime/containerLimits.js +84 -0
  207. package/dist/runtime/credentialMaterialisation.d.ts +28 -0
  208. package/dist/runtime/credentialMaterialisation.js +128 -0
  209. package/dist/runtime/gitCheckoutCapability.js +7 -13
  210. package/dist/runtime/pipelineRunner.d.ts +36 -1
  211. package/dist/runtime/pipelineRunner.js +178 -17
  212. package/dist/runtime/pipelineScheduler.d.ts +15 -0
  213. package/dist/runtime/pipelineScheduler.js +135 -27
  214. package/dist/runtime/reloadRunCatalog.js +6 -1
  215. package/dist/runtime/repositoryMaterialize.d.ts +47 -0
  216. package/dist/runtime/repositoryMaterialize.js +235 -0
  217. package/dist/runtime/resumeTimedOut.d.ts +1 -1
  218. package/dist/runtime/resumeTimedOut.js +5 -2
  219. package/dist/runtime/runChangeBus.js +9 -0
  220. package/dist/runtime/runDeletion.d.ts +7 -0
  221. package/dist/runtime/runDeletion.js +37 -0
  222. package/dist/runtime/runManager.d.ts +158 -4
  223. package/dist/runtime/runManager.js +1596 -79
  224. package/dist/runtime/runRetentionSweep.d.ts +31 -0
  225. package/dist/runtime/runRetentionSweep.js +328 -0
  226. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  227. package/dist/runtime/runRetryCoordinator.js +19 -2
  228. package/dist/runtime/runSkills.d.ts +40 -0
  229. package/dist/runtime/runSkills.js +173 -0
  230. package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
  231. package/dist/runtime/stageAttemptBootstrap.js +195 -24
  232. package/dist/runtime/stageCacheEnv.d.ts +6 -0
  233. package/dist/runtime/stageCacheEnv.js +34 -0
  234. package/dist/runtime/stageConcurrency.d.ts +2 -1
  235. package/dist/runtime/stageConcurrency.js +4 -2
  236. package/dist/runtime/stageEnvironment.d.ts +38 -0
  237. package/dist/runtime/stageEnvironment.js +193 -0
  238. package/dist/runtime/stageProcessLauncher.d.ts +18 -0
  239. package/dist/runtime/stageProcessLauncher.js +194 -38
  240. package/dist/runtime/stageRecovery.d.ts +3 -1
  241. package/dist/runtime/stageRecovery.js +19 -4
  242. package/dist/runtime/stageRoots.d.ts +38 -1
  243. package/dist/runtime/stageRoots.js +118 -0
  244. package/dist/runtime/stageRunner.d.ts +1 -0
  245. package/dist/runtime/stageRunner.js +3 -1
  246. package/dist/runtime/stageSecretDecl.d.ts +9 -0
  247. package/dist/runtime/stageSecretDecl.js +102 -0
  248. package/dist/runtime/stageSecrets.d.ts +40 -0
  249. package/dist/runtime/stageSecrets.js +181 -0
  250. package/dist/runtime/stageWorker.d.ts +3 -2
  251. package/dist/runtime/stageWorker.js +58 -10
  252. package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
  253. package/dist/runtime/stageWorkerProtocol.js +8 -0
  254. package/dist/runtime/startPayload.d.ts +32 -0
  255. package/dist/runtime/startPayload.js +59 -0
  256. package/dist/runtime/taskInput.js +14 -5
  257. package/dist/runtime/verifiedStageExecution.d.ts +1 -0
  258. package/dist/runtime/verifiedStageExecution.js +2 -1
  259. package/dist/runtime/workspaceBinding.d.ts +20 -0
  260. package/dist/runtime/workspaceBinding.js +60 -0
  261. package/dist/server/allowedHosts.d.ts +19 -0
  262. package/dist/server/allowedHosts.js +179 -0
  263. package/dist/server/bootstrap.d.ts +36 -2
  264. package/dist/server/bootstrap.js +209 -5
  265. package/dist/server/controlToken.d.ts +47 -0
  266. package/dist/server/controlToken.js +241 -0
  267. package/dist/server/createHttpHost.d.ts +11 -2
  268. package/dist/server/createHttpHost.js +103 -10
  269. package/dist/server/ensureGlobalService.d.ts +5 -1
  270. package/dist/server/ensureGlobalService.js +35 -1
  271. package/dist/server/healthSurfaces.d.ts +6 -0
  272. package/dist/server/healthSurfaces.js +98 -0
  273. package/dist/server/http.d.ts +12 -1
  274. package/dist/server/http.js +1085 -485
  275. package/dist/server/listenHost.d.ts +5 -0
  276. package/dist/server/listenHost.js +56 -0
  277. package/dist/server/mcpHost.d.ts +10 -1
  278. package/dist/server/mcpHost.js +36 -6
  279. package/dist/server/operatorResults.d.ts +2 -2
  280. package/dist/server/operatorResults.js +40 -29
  281. package/dist/server/requestAuthContext.d.ts +12 -0
  282. package/dist/server/requestAuthContext.js +21 -0
  283. package/dist/server/shutdown.d.ts +69 -0
  284. package/dist/server/shutdown.js +219 -0
  285. package/dist/types/pipeline.d.ts +7 -0
  286. package/dist/types/stage.d.ts +8 -0
  287. package/dist/types/task.d.ts +8 -0
  288. package/dist/ui/assets/index-B6hlSXXn.js +120 -0
  289. package/dist/ui/index.html +1 -1
  290. package/examples/README.md +98 -0
  291. package/examples/archify-on-pr/README.md +213 -0
  292. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
  293. package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
  294. package/examples/archify-on-pr/author-diagrams.yaml +106 -0
  295. package/examples/archify-on-pr/detect-changes.yaml +89 -0
  296. package/examples/ci-validate/README.md +35 -0
  297. package/examples/ci-validate/check.yaml +13 -0
  298. package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
  299. package/examples/ci-validate/validate.sh +5 -0
  300. package/examples/compliance-review-demo/README.md +125 -0
  301. package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
  302. package/examples/compliance-review-demo/connect-account.yaml +47 -0
  303. package/examples/compliance-review-demo/map-to-control.yaml +123 -0
  304. package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
  305. package/examples/compliance-review-demo/publish-report.yaml +79 -0
  306. package/examples/compliance-review-demo/review-verdict.yaml +122 -0
  307. package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
  308. package/examples/compliance-review-demo/store-evidence.yaml +143 -0
  309. package/examples/conditional-fork/README.md +89 -0
  310. package/examples/conditional-fork/branch-a.yaml +13 -0
  311. package/examples/conditional-fork/branch-b.yaml +13 -0
  312. package/examples/conditional-fork/decide.yaml +35 -0
  313. package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
  314. package/examples/conditional-fork/fork-demo.task.yaml +8 -0
  315. package/examples/context7-mcp/README.md +42 -0
  316. package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
  317. package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
  318. package/examples/context7-mcp/fetch-docs.yaml +52 -0
  319. package/examples/context7-mcp/resolve-library.yaml +31 -0
  320. package/examples/context7-mcp/write-brief.yaml +52 -0
  321. package/examples/feature-loop/README.md +104 -0
  322. package/examples/feature-loop/address-feedback.yaml +148 -0
  323. package/examples/feature-loop/align.yaml +116 -0
  324. package/examples/feature-loop/decompose.yaml +86 -0
  325. package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
  326. package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
  327. package/examples/feature-loop/feature-loop.task.yaml +25 -0
  328. package/examples/feature-loop/implement.yaml +128 -0
  329. package/examples/feature-loop/plan.yaml +111 -0
  330. package/examples/feature-loop/publish.yaml +167 -0
  331. package/examples/feature-loop/review.yaml +146 -0
  332. package/examples/feature-loop/verify.yaml +106 -0
  333. package/examples/feedback-loop/README.md +72 -0
  334. package/examples/feedback-loop/VERIFY.md +208 -0
  335. package/examples/feedback-loop/continue-only.task.yaml +4 -0
  336. package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
  337. package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
  338. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
  339. package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
  340. package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
  341. package/examples/feedback-loop/implement.yaml +14 -0
  342. package/examples/feedback-loop/plan.yaml +14 -0
  343. package/examples/feedback-loop/review.yaml +15 -0
  344. package/examples/feedback-loop/send-back-once.task.yaml +6 -0
  345. package/examples/feedback-loop/submit.yaml +12 -0
  346. package/examples/generic-fan-in/README.md +151 -0
  347. package/examples/generic-fan-in/clarify.yaml +18 -0
  348. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
  349. package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
  350. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
  351. package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
  352. package/examples/generic-fan-in/research.yaml +45 -0
  353. package/examples/generic-fan-in/synthesize.yaml +66 -0
  354. package/examples/generic-fan-in/validation.yaml +45 -0
  355. package/examples/github-release/README.md +78 -0
  356. package/examples/github-release/draft-release-notes.yaml +64 -0
  357. package/examples/github-release/github-release.pipeline.yaml +11 -0
  358. package/examples/github-release/github-release.task.yaml +13 -0
  359. package/examples/github-release/publish-github-release.yaml +64 -0
  360. package/examples/hello-world/README.md +28 -0
  361. package/examples/hello-world/hello.pipeline.yaml +4 -0
  362. package/examples/hello-world/my-task.task.yaml +6 -0
  363. package/examples/hello-world/research.yaml +18 -0
  364. package/examples/mcp-hitl-tour/README.md +113 -0
  365. package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
  366. package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
  367. package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
  368. package/examples/mcp-hitl-tour/gather.yaml +31 -0
  369. package/examples/mcp-hitl-tour/intake.yaml +62 -0
  370. package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
  371. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
  372. package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
  373. package/examples/mcp-hitl-tour/polish.yaml +33 -0
  374. package/examples/mcp-hitl-tour/review.yaml +17 -0
  375. package/examples/mcp-hitl-tour/ship.yaml +25 -0
  376. package/examples/oss-issue-contribution/README.md +218 -0
  377. package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
  378. package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
  379. package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
  380. package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
  381. package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
  382. package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
  383. package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
  384. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
  385. package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
  386. package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
  387. package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
  388. package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
  389. package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
  390. package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
  391. package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
  392. package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
  393. package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
  394. package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
  395. package/examples/oss-quick-fix/README.md +65 -0
  396. package/examples/oss-quick-fix/implement-fix.yaml +84 -0
  397. package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
  398. package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
  399. package/examples/oss-quick-fix/ship-fix.yaml +81 -0
  400. package/examples/oss-quick-fix/understand-issue.yaml +67 -0
  401. package/examples/oss-quick-fix/verify-fix.yaml +73 -0
  402. package/examples/plan-review/README.md +37 -0
  403. package/examples/plan-review/plan-review-followup.yaml +13 -0
  404. package/examples/plan-review/plan-review.pipeline.yaml +9 -0
  405. package/examples/plan-review/plan-review.task.yaml +9 -0
  406. package/examples/plan-review/plan-review.yaml +25 -0
  407. package/examples/playwright-mcp/README.md +39 -0
  408. package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
  409. package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
  410. package/examples/playwright-mcp/screenshot.yaml +40 -0
  411. package/examples/retry-tour/README.md +75 -0
  412. package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
  413. package/examples/retry-tour/retry-tour.task.yaml +9 -0
  414. package/examples/route-if-tour/README.md +202 -0
  415. package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
  416. package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
  417. package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
  418. package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
  419. package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
  420. package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
  421. package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
  422. package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
  423. package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
  424. package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
  425. package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
  426. package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
  427. package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
  428. package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
  429. package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
  430. package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
  431. package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
  432. package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
  433. package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
  434. package/examples/route-wiring-smoke-test/README.md +377 -0
  435. package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
  436. package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
  437. package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
  438. package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
  439. package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
  440. package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
  441. package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
  442. package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
  443. package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
  444. package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
  445. package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
  446. package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
  447. package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
  448. package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
  449. package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
  450. package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
  451. package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
  452. package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
  453. package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
  454. package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
  455. package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
  456. package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
  457. package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
  458. package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
  459. package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
  460. package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
  461. package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
  462. package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
  463. package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
  464. package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
  465. package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
  466. package/examples/ship-feature/README.md +190 -0
  467. package/examples/ship-feature/feat-address-feedback.yaml +119 -0
  468. package/examples/ship-feature/feat-implement.yaml +180 -0
  469. package/examples/ship-feature/feat-plan.yaml +120 -0
  470. package/examples/ship-feature/feat-review.yaml +109 -0
  471. package/examples/ship-feature/feat-ship.yaml +203 -0
  472. package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
  473. package/examples/ship-feature/ship-feature.task.yaml +78 -0
  474. package/examples/stage-mcp/README.md +144 -0
  475. package/examples/stage-mcp/echo-mcp.mjs +20 -0
  476. package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
  477. package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
  478. package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
  479. package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
  480. package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
  481. package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
  482. package/examples/stage-mcp/use-echo.yaml +20 -0
  483. package/examples/verify-tour/README.md +80 -0
  484. package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
  485. package/examples/verify-tour/verify-tour.task.yaml +11 -0
  486. package/package.json +5 -1
  487. package/skills/stageflow/SKILL.md +6 -6
  488. package/skills/stageflow/references/control-surface.md +11 -5
  489. package/skills/stageflow/scripts/detect-host.mjs +14 -1
  490. package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
  491. package/skills/stageflow-author/SKILL.md +4 -3
  492. package/skills/stageflow-author/references/catalog-mapping.md +16 -0
  493. package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
  494. package/skills/stageflow-run/SKILL.md +20 -12
  495. package/skills/stageflow-run/references/mcp-call.md +9 -1
  496. package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
  497. package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
  498. package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
  499. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
  500. package/skills/stageflow-setup/SKILL.md +40 -8
  501. package/dist/ui/assets/index-Da5EHU6M.js +0 -119
@@ -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,29 +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
- submission: options.submission,
69
- pipelineId: loaded.pipeline.id,
70
- taskYaml,
71
- taskId: task.id,
72
- checkoutRoot,
73
- gitSha: options.gitSha,
74
- ciPrUrl: options.ciPrUrl,
75
- ciJobUrl: options.ciJobUrl,
76
- pipelineDag: buildPipelineDagSnapshotFromLoaded(loaded),
77
- pipelinePath,
78
- taskPath,
79
- projectRoot,
80
- inlinePipeline: typeof options.pipeline === "string" ? undefined : options.pipeline,
81
- });
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
+ }
82
231
  const executionMode = readStageExecutionMode(process.env, options.executionMode);
83
232
  const stageProcessLauncher = resolveStageProcessLauncher(executionMode, options.stageProcessLauncher);
84
233
  return {
@@ -112,6 +261,7 @@ export async function executeStages(prepared, options) {
112
261
  startAtStageIndex: options?.startAtStageIndex,
113
262
  executionMode,
114
263
  stageProcessLauncher,
264
+ schedulingHalt: options?.schedulingHalt,
115
265
  });
116
266
  if (prepared.findings !== undefined && prepared.findings.length > 0) {
117
267
  return { ...result, findings: prepared.findings };
@@ -156,6 +306,13 @@ export async function startPipeline(options) {
156
306
  cwd,
157
307
  projectRoot,
158
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,
159
316
  gitSha: options.gitSha,
160
317
  ciPrUrl: options.ciPrUrl,
161
318
  ciJobUrl: options.ciJobUrl,
@@ -164,13 +321,17 @@ export async function startPipeline(options) {
164
321
  stageProcessLauncher: options.stageProcessLauncher,
165
322
  operatorCatalog: options.operatorCatalog,
166
323
  skipGates: options.skipGates,
324
+ callerId: options.callerId,
325
+ ...(options.skills !== undefined ? { skills: options.skills } : {}),
167
326
  });
168
327
  const done = executeStages(prepared, {
169
328
  maxActiveStagesPerRun: options.maxActiveStagesPerRun,
170
329
  executionMode: prepared.executionMode,
171
330
  stageProcessLauncher: prepared.stageProcessLauncher,
331
+ schedulingHalt: options.schedulingHalt,
172
332
  }).catch(async (err) => {
173
333
  await prepared.store.updateRunStatus(prepared.run.runId, "failed").catch(() => undefined);
334
+ await finaliseStoredRunManifest(prepared.store, prepared.run.runId).catch(() => undefined);
174
335
  return {
175
336
  ok: false,
176
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) {
@@ -349,10 +375,16 @@ export async function runPipelineDag(options) {
349
375
  let { states, completedEnvelopes, schedulingHalted, firstFailureReason, dag: hydratedDag, } = options.initialSchedule ??
350
376
  (await hydrateScheduleFromStore(store, run.runId, fallbackDag, executionMode));
351
377
  let dag = hydratedDag ?? fallbackDag;
378
+ const runMeta = await store.readRunMeta(run.runId);
352
379
  if (hydratedDag === undefined) {
353
- const meta = await store.readRunMeta(run.runId);
354
- dag = meta.pipeline_dag ?? fallbackDag;
380
+ dag = runMeta.pipeline_dag ?? fallbackDag;
355
381
  }
382
+ const stageBinding = stageBindingEnvFromRun({
383
+ meta: runMeta,
384
+ task,
385
+ runWorkspaceDir: run.workspaceDir,
386
+ hostEnv: process.env,
387
+ });
356
388
  const stageById = buildStageConfigById(loaded);
357
389
  const retryContext = options.retryContext;
358
390
  const feedbackSchedule = createReplaySchedule();
@@ -827,32 +859,83 @@ export async function runPipelineDag(options) {
827
859
  stageId,
828
860
  });
829
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
+ };
830
902
  if (executionMode === "process") {
831
903
  const launcher = options.stageProcessLauncher;
832
904
  if (!launcher) {
905
+ cleanupAttemptCredentials();
833
906
  await onStageFailure(stageId, "stage process launcher is not configured");
834
907
  return;
835
908
  }
836
- const launchResult = await launcher.launch({
837
- runId: run.runId,
838
- stageId,
839
- rootDir: factoryCwd,
840
- attempt,
841
- ...(sessionMode !== undefined
842
- ? {
843
- mode: sessionMode === "feedback_resume"
844
- ? "feedback_resume"
845
- : sessionMode === "new_session"
846
- ? "new_session"
847
- : "run",
848
- }
849
- : {}),
850
- ...(resumeToken !== undefined ? { sessionFilePath: resumeToken } : {}),
851
- ...(prepared.operatorCatalog !== undefined
852
- ? { operatorCatalog: prepared.operatorCatalog }
853
- : {}),
854
- ...(prepared.skipGates ? { skipGates: true } : {}),
855
- });
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
+ }
856
939
  if (launchResult.type === "succeeded") {
857
940
  try {
858
941
  const envelope = await store.readEnvelope(run.runId, stageId);
@@ -868,6 +951,10 @@ export async function runPipelineDag(options) {
868
951
  states.set(stageId, "waiting");
869
952
  return;
870
953
  }
954
+ if (options.schedulingHalt?.hostShutdown) {
955
+ states.set(stageId, "waiting");
956
+ return;
957
+ }
871
958
  await onStageFailure(stageId, launchResult.reason);
872
959
  return;
873
960
  }
@@ -887,15 +974,25 @@ export async function runPipelineDag(options) {
887
974
  operatorCatalog: prepared.operatorCatalog,
888
975
  completedEnvelopes,
889
976
  skipGates: prepared.skipGates,
977
+ stageEnv: {
978
+ ...stageBinding.env,
979
+ ...grants.env,
980
+ HOME: attemptHome,
981
+ },
890
982
  ...(sessionMode !== undefined ? { sessionMode } : {}),
891
983
  ...(feedbackLoopContext !== undefined ? { feedbackLoopContext } : {}),
892
984
  ...(resumeToken !== undefined ? { resumeToken } : {}),
893
985
  });
986
+ cleanupAttemptCredentials();
894
987
  if (isRunStageWaiting(result)) {
895
988
  await onStageFailure(stageId, WAIT_WITHOUT_WORKER_DISPATCH);
896
989
  return;
897
990
  }
898
991
  if (!result.ok) {
992
+ if (options.schedulingHalt?.hostShutdown) {
993
+ states.set(stageId, "waiting");
994
+ return;
995
+ }
899
996
  await onStageFailure(stageId, result.reason ?? "stage failed", result.envelope);
900
997
  return;
901
998
  }
@@ -944,11 +1041,17 @@ export async function runPipelineDag(options) {
944
1041
  return true;
945
1042
  };
946
1043
  while (!allTerminal()) {
1044
+ if (options.schedulingHalt?.halted) {
1045
+ schedulingHalted = true;
1046
+ }
947
1047
  drainRetryMutations();
948
1048
  await applyStalledJoinSkips();
949
1049
  if (options.onLoopTick !== undefined) {
950
1050
  await options.onLoopTick();
951
1051
  }
1052
+ if (options.schedulingHalt?.halted) {
1053
+ schedulingHalted = true;
1054
+ }
952
1055
  if (!schedulingHalted) {
953
1056
  const runnable = pickRunnable();
954
1057
  for (const stageId of runnable) {
@@ -992,11 +1095,16 @@ export async function runPipelineDag(options) {
992
1095
  if (schedulingHalted) {
993
1096
  markSkippedPending();
994
1097
  if (retryContext === undefined) {
995
- 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
+ }
996
1104
  }
997
1105
  return {
998
1106
  ok: false,
999
- outcome: "failed",
1107
+ outcome: options.schedulingHalt?.hostShutdown ? "waiting" : "failed",
1000
1108
  runDir: run.workspaceDir,
1001
1109
  runId: run.runId,
1002
1110
  reason: firstFailureReason,
@@ -1004,7 +1112,7 @@ export async function runPipelineDag(options) {
1004
1112
  }
1005
1113
  if (scheduleHasUnhandledFailure(dag, states) || !allTerminal()) {
1006
1114
  if (retryContext === undefined) {
1007
- await store.updateRunStatus(run.runId, "failed");
1115
+ await writeTerminalRunStatus(store, run.runId, "failed");
1008
1116
  }
1009
1117
  return {
1010
1118
  ok: false,
@@ -1014,7 +1122,7 @@ export async function runPipelineDag(options) {
1014
1122
  reason: firstFailureReason ?? "pipeline incomplete",
1015
1123
  };
1016
1124
  }
1017
- await store.updateRunStatus(run.runId, "succeeded");
1125
+ await writeTerminalRunStatus(store, run.runId, "succeeded");
1018
1126
  return {
1019
1127
  ok: true,
1020
1128
  outcome: "succeeded",
@@ -32,13 +32,18 @@ async function assertCatalogFileExists(filePath, label) {
32
32
  }
33
33
  }
34
34
  export async function reloadPipelineForRun(meta) {
35
- const projectRoot = requireProjectRoot(meta);
36
35
  // An inline-pipeline run (no pipeline_path — nothing was ever written to a
37
36
  // catalog file) carries its own pipeline body in meta.inline_pipeline
38
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).
39
40
  if (meta.inline_pipeline) {
41
+ const projectRoot = meta.project_root
42
+ ? normalizeCatalogPath(meta.project_root)
43
+ : process.cwd();
40
44
  return loadPipelineFromObject(meta.inline_pipeline, { projectRoot });
41
45
  }
46
+ const projectRoot = requireProjectRoot(meta);
42
47
  const pipelinePath = requirePipelinePath(meta);
43
48
  await assertCatalogFileExists(pipelinePath, "Pipeline");
44
49
  return loadPipeline(pipelinePath, { cwd: projectRoot });
@@ -0,0 +1,47 @@
1
+ import type { RunMeta, RunStore } from "../runstore/port.js";
2
+ import type { TaskFile } from "../types/task.js";
3
+ import type { WorkspaceBinding } from "./workspaceBinding.js";
4
+ export type StartFailureCode = "busy_capacity" | "busy_checkout" | "busy_caller_quota" | "repository_auth_failed" | "repository_not_found" | "ref_not_found" | "repository_fetch_failed" | "worktree_create_failed" | "git_missing" | "insufficient_disk" | "disk_check_failed" | "pinned_sha_unavailable" | "invalid_run_branch" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid" | "task.invalid_shape" | "task.load_error" | "start.token_rejected" | "inline_pipeline_too_large" | "skills_invalid_name" | "skills_invalid_path" | "skills_missing_skill_md" | "skills_payload_too_large" | "missing_tool" | "tool_version_mismatch" | "unknown_version" | "secret_unavailable" | "unresolved_var" | "shutting_down" | "autostart_disabled" | "ensure_project_not_allowed" | "claude_as_root";
5
+ export type MaterializedBinding = {
6
+ runId: string;
7
+ checkoutRoot?: string;
8
+ repository?: string;
9
+ ref?: string;
10
+ resolvedSha?: string;
11
+ runBranch?: string;
12
+ };
13
+ export type DerivedBindingKind = "repository" | "checkout" | "unbound";
14
+ export declare function derivedBindingKindFromMeta(meta: RunMeta): DerivedBindingKind;
15
+ export declare function worktreePathForRun(runId: string): string;
16
+ export declare function resolveRunBranchTemplate(task: TaskFile): string;
17
+ export declare class StartLinkError extends Error {
18
+ readonly code: StartFailureCode;
19
+ readonly status: number;
20
+ readonly stderr?: string;
21
+ constructor(message: string, options: {
22
+ code: StartFailureCode;
23
+ status: number;
24
+ stderr?: string;
25
+ });
26
+ }
27
+ export declare function throwMappedGitError(err: unknown, phase: "fetch" | "resolve" | "worktree"): never;
28
+ export type MaterializeOptions = {
29
+ runId: string;
30
+ task: TaskFile;
31
+ binding: WorkspaceBinding;
32
+ checkoutRoot?: string;
33
+ pinned?: {
34
+ ref: string;
35
+ resolvedSha: string;
36
+ };
37
+ };
38
+ export type ReclaimWorkspaceBindingOptions = {
39
+ /** When true, remove the worktree but leave `run_branch` (SLIM must keep the branch). */
40
+ keepRunBranch?: boolean;
41
+ };
42
+ export declare function reclaimWorkspaceBinding(meta: RunMeta, options?: ReclaimWorkspaceBindingOptions): Promise<void>;
43
+ export declare function reclaimWorkspaceOnRunSucceeded(store: RunStore, runId: string): Promise<void>;
44
+ export declare function materializeWorkspaceBinding(options: MaterializeOptions): Promise<{
45
+ materialized: MaterializedBinding;
46
+ rollback: () => Promise<void>;
47
+ }>;