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
@@ -0,0 +1,214 @@
1
+ import { readdir, stat, statfs } from "node:fs/promises";
2
+ import path from "node:path";
3
+ const BLOCK_SIZE = 512;
4
+ const STATE_DB_NAMES = ["state.db", "state.db-wal", "state.db-shm"];
5
+ export const DISK_WARN_LOG_PREFIX = "stageflow.disk_warn";
6
+ let walkCallCount = 0;
7
+ let freeSpaceReaderOverride = null;
8
+ export function getDiskUsageWalkCallCount() {
9
+ return walkCallCount;
10
+ }
11
+ export function resetDiskUsageWalkCallCount() {
12
+ walkCallCount = 0;
13
+ }
14
+ export function setFreeSpaceReaderForTests(reader) {
15
+ freeSpaceReaderOverride = reader;
16
+ }
17
+ function allocatedBytes(st) {
18
+ return st.blocks * BLOCK_SIZE;
19
+ }
20
+ async function pathExists(target) {
21
+ try {
22
+ await stat(target);
23
+ return true;
24
+ }
25
+ catch (err) {
26
+ if (err.code === "ENOENT")
27
+ return false;
28
+ throw err;
29
+ }
30
+ }
31
+ /** Walk `rootPath` summing `stat().blocks * 512`. Missing path → 0. */
32
+ export async function diskUsageOf(rootPath) {
33
+ walkCallCount += 1;
34
+ if (!(await pathExists(rootPath)))
35
+ return 0;
36
+ let total = 0;
37
+ async function walk(current) {
38
+ let st;
39
+ try {
40
+ st = await stat(current);
41
+ }
42
+ catch (err) {
43
+ if (err.code === "ENOENT")
44
+ return;
45
+ throw err;
46
+ }
47
+ total += allocatedBytes(st);
48
+ if (!st.isDirectory())
49
+ return;
50
+ let entries;
51
+ try {
52
+ entries = await readdir(current, { withFileTypes: true });
53
+ }
54
+ catch (err) {
55
+ if (err.code === "ENOENT")
56
+ return;
57
+ throw err;
58
+ }
59
+ for (const entry of entries) {
60
+ await walk(path.join(current, entry.name));
61
+ }
62
+ }
63
+ await walk(rootPath);
64
+ return total;
65
+ }
66
+ export async function readFilesystemSize(rootPath) {
67
+ if (freeSpaceReaderOverride !== null) {
68
+ return freeSpaceReaderOverride(rootPath);
69
+ }
70
+ let target = path.resolve(rootPath);
71
+ for (;;) {
72
+ try {
73
+ const fsStats = await statfs(target);
74
+ const blockSize = fsStats.bsize;
75
+ return {
76
+ freeBytes: fsStats.bavail * blockSize,
77
+ totalBytes: fsStats.blocks * blockSize,
78
+ };
79
+ }
80
+ catch (err) {
81
+ if (err.code !== "ENOENT")
82
+ throw err;
83
+ const parent = path.dirname(target);
84
+ if (parent === target)
85
+ throw err;
86
+ target = parent;
87
+ }
88
+ }
89
+ }
90
+ async function usageOfMissingOk(target) {
91
+ try {
92
+ return await diskUsageOf(target);
93
+ }
94
+ catch (err) {
95
+ if (err.code === "ENOENT")
96
+ return 0;
97
+ throw err;
98
+ }
99
+ }
100
+ async function stateDbBytes(durableRoot) {
101
+ let total = 0;
102
+ for (const name of STATE_DB_NAMES) {
103
+ const filePath = path.join(durableRoot, name);
104
+ try {
105
+ const st = await stat(filePath);
106
+ if (st.isFile()) {
107
+ walkCallCount += 1;
108
+ total += allocatedBytes(st);
109
+ }
110
+ }
111
+ catch (err) {
112
+ if (err.code === "ENOENT")
113
+ continue;
114
+ throw err;
115
+ }
116
+ }
117
+ return total;
118
+ }
119
+ /** Category breakdown for the durable root, reusing `diskUsageOf` for directory trees. */
120
+ export async function durableRootDiskBreakdown(durableRoot, options) {
121
+ const freeSpace = options?.freeSpace ?? readFilesystemSize;
122
+ const [runs_bytes, worktrees_bytes, repos_bytes, state_db_bytes, a2a_artifacts_bytes, cache_bytes, size] = await Promise.all([
123
+ usageOfMissingOk(path.join(durableRoot, "runs")),
124
+ usageOfMissingOk(path.join(durableRoot, "worktrees")),
125
+ usageOfMissingOk(path.join(durableRoot, "repos")),
126
+ stateDbBytes(durableRoot),
127
+ usageOfMissingOk(path.join(durableRoot, "a2a-artifacts")),
128
+ usageOfMissingOk(path.join(durableRoot, "cache")),
129
+ freeSpace(durableRoot),
130
+ ]);
131
+ return {
132
+ runs_bytes,
133
+ worktrees_bytes,
134
+ repos_bytes,
135
+ state_db_bytes,
136
+ a2a_artifacts_bytes,
137
+ cache_bytes,
138
+ free_bytes: size.freeBytes,
139
+ };
140
+ }
141
+ /**
142
+ * Parse `STAGEFLOW_DISK_WARN_BYTES` / floor-style env: integer bytes or `N%` of filesystem.
143
+ * Empty / unset / invalid → undefined (no threshold).
144
+ */
145
+ export function parseDiskBytesThreshold(raw, filesystemTotalBytes) {
146
+ if (raw === undefined)
147
+ return undefined;
148
+ const trimmed = raw.trim();
149
+ if (trimmed === "")
150
+ return undefined;
151
+ if (trimmed.endsWith("%")) {
152
+ const pct = Number.parseFloat(trimmed.slice(0, -1));
153
+ if (!Number.isFinite(pct) || pct < 0 || pct > 100)
154
+ return undefined;
155
+ if (!Number.isFinite(filesystemTotalBytes) || filesystemTotalBytes < 0) {
156
+ return undefined;
157
+ }
158
+ return Math.floor((filesystemTotalBytes * pct) / 100);
159
+ }
160
+ const n = Number.parseInt(trimmed, 10);
161
+ if (!Number.isFinite(n) || n < 0)
162
+ return undefined;
163
+ return n;
164
+ }
165
+ const DEFAULT_MIN_FREE_DISK_BYTES = 2 * 1024 * 1024 * 1024;
166
+ /**
167
+ * Resolve `STAGEFLOW_MIN_FREE_DISK_BYTES`: bytes or `%` of filesystem.
168
+ * Unset / empty / invalid → `max(2 GiB, 10% of filesystemTotalBytes)`.
169
+ */
170
+ export function resolveMinFreeDiskFloor(raw, filesystemTotalBytes) {
171
+ const parsed = parseDiskBytesThreshold(raw, filesystemTotalBytes);
172
+ if (parsed !== undefined)
173
+ return parsed;
174
+ const total = Number.isFinite(filesystemTotalBytes) && filesystemTotalBytes > 0
175
+ ? filesystemTotalBytes
176
+ : 0;
177
+ const tenPercent = Math.floor(total * 0.1);
178
+ return Math.max(DEFAULT_MIN_FREE_DISK_BYTES, tenPercent);
179
+ }
180
+ /**
181
+ * One named warning when free space is below `STAGEFLOW_DISK_WARN_BYTES`. Never throws.
182
+ * @returns true when a warning line was emitted
183
+ */
184
+ export async function warnDurableRootDiskIfNeeded(durableRoot, options) {
185
+ try {
186
+ const env = options?.env ?? process.env;
187
+ const raw = env.STAGEFLOW_DISK_WARN_BYTES;
188
+ if (raw === undefined || raw.trim() === "")
189
+ return false;
190
+ const freeSpace = options?.freeSpace ?? readFilesystemSize;
191
+ const size = await freeSpace(durableRoot);
192
+ const threshold = parseDiskBytesThreshold(raw, size.totalBytes);
193
+ if (threshold === undefined)
194
+ return false;
195
+ if (size.freeBytes >= threshold)
196
+ return false;
197
+ const log = options?.log ?? ((line) => console.warn(line));
198
+ log(`${DISK_WARN_LOG_PREFIX}: durable root free space ${size.freeBytes} bytes is below threshold ${threshold} bytes (${raw.trim()}); run sf runs gc`);
199
+ return true;
200
+ }
201
+ catch (err) {
202
+ const log = options?.log ?? ((line) => console.warn(line));
203
+ log(`${DISK_WARN_LOG_PREFIX}: free-space measurement failed: ${err instanceof Error ? err.message : String(err)}`);
204
+ return false;
205
+ }
206
+ }
207
+ /** Measure one run workspace and persist `disk_bytes` / `disk_measured_at`. */
208
+ export async function refreshRunDiskUsage(store, runId, options) {
209
+ const workspaceDir = store.getWorkspaceDir(runId);
210
+ const bytes = await diskUsageOf(workspaceDir);
211
+ const measuredAt = (options?.now ?? new Date()).toISOString();
212
+ await store.setRunDiskUsage(runId, bytes, measuredAt);
213
+ return bytes;
214
+ }
@@ -0,0 +1,8 @@
1
+ import { type RunProjection } from "../projection/projectRun.js";
2
+ import type { RunDetail } from "./port.js";
3
+ import { type RunManifest } from "./runManifest.js";
4
+ export type RunExportPayload = RunProjection & {
5
+ run_manifest: RunManifest | null;
6
+ };
7
+ export declare function buildRunExportPayload(detail: RunDetail): RunExportPayload;
8
+ export declare function runDetailWithRedactedManifest(detail: RunDetail): RunDetail;
@@ -0,0 +1,23 @@
1
+ import { projectRun } from "../projection/projectRun.js";
2
+ import { redactRunManifestForRead, } from "./runManifest.js";
3
+ import { getNamedSecrets } from "../logging/namedSecrets.js";
4
+ export function buildRunExportPayload(detail) {
5
+ return {
6
+ ...projectRun(detail),
7
+ run_manifest: redactRunManifestForRead(detail.run_manifest, {
8
+ namedSecrets: getNamedSecrets(),
9
+ }),
10
+ };
11
+ }
12
+ export function runDetailWithRedactedManifest(detail) {
13
+ const run_manifest = redactRunManifestForRead(detail.run_manifest, {
14
+ namedSecrets: getNamedSecrets(),
15
+ });
16
+ if (run_manifest === null) {
17
+ if (detail.run_manifest === undefined)
18
+ return detail;
19
+ const { run_manifest: _drop, ...rest } = detail;
20
+ return rest;
21
+ }
22
+ return { ...detail, run_manifest };
23
+ }
@@ -1 +1,2 @@
1
1
  export declare function normalizeCatalogPath(raw: string): string;
2
+ export declare function normalizeProjectRoot(raw: string): string;
@@ -1,4 +1,14 @@
1
+ import { realpathSync } from "node:fs";
1
2
  import path from "node:path";
2
3
  export function normalizeCatalogPath(raw) {
3
4
  return path.resolve(raw);
4
5
  }
6
+ export function normalizeProjectRoot(raw) {
7
+ const resolved = path.resolve(raw);
8
+ try {
9
+ return realpathSync(resolved);
10
+ }
11
+ catch {
12
+ return resolved;
13
+ }
14
+ }
@@ -1,6 +1,11 @@
1
1
  export declare function newRunId(): string;
2
2
  /** Root for factory state under a project: `<rootDir>/.stageflow`. */
3
3
  export declare function storeRootFor(rootDir: string): string;
4
+ export declare function isGlobalStageflowHome(rootDir: string): boolean;
5
+ /** Project store root or the durable home when `rootDir` is the global home. */
6
+ export declare function resolveStoreRoot(rootDir: string): string;
7
+ export declare const NESTED_GLOBAL_STORE_CONFLICT = "Cannot open the global store: flat state.db has no runs table while nested .stageflow/state.db still holds run data. Resolve the conflict manually.";
8
+ export declare function flattenNestedGlobalStore(home: string): void;
4
9
  export declare function migrateLegacyStoreRoot(rootDir: string): void;
5
10
  export declare function runsDir(storeRoot: string): string;
6
11
  export declare function runWorkspaceDir(storeRoot: string, runId: string): string;
@@ -1,6 +1,8 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { readdirSync, renameSync, rmdirSync, statSync } from "node:fs";
2
+ import { existsSync, readdirSync, renameSync, rmdirSync, statSync, } from "node:fs";
3
3
  import path from "node:path";
4
+ import Database from "better-sqlite3";
5
+ import { globalStageflowHome } from "../project/globalHome.js";
4
6
  import { guardStageId } from "./workspaceLayout.js";
5
7
  export function newRunId() {
6
8
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
@@ -10,6 +12,148 @@ export function newRunId() {
10
12
  export function storeRootFor(rootDir) {
11
13
  return path.join(rootDir, ".stageflow");
12
14
  }
15
+ export function isGlobalStageflowHome(rootDir) {
16
+ return path.resolve(rootDir) === globalStageflowHome();
17
+ }
18
+ /** Project store root or the durable home when `rootDir` is the global home. */
19
+ export function resolveStoreRoot(rootDir) {
20
+ if (isGlobalStageflowHome(rootDir)) {
21
+ return globalStageflowHome();
22
+ }
23
+ return storeRootFor(rootDir);
24
+ }
25
+ const NESTED_GLOBAL_STORE_DIR = ".stageflow";
26
+ const STATE_DB_BASENAME = "state.db";
27
+ const STATE_DB_SIDECARS = ["state.db-wal", "state.db-shm"];
28
+ const NESTED_STORE_MOVE_DIRS = ["runs", "a2a-artifacts"];
29
+ export const NESTED_GLOBAL_STORE_CONFLICT = "Cannot open the global store: flat state.db has no runs table while nested .stageflow/state.db still holds run data. Resolve the conflict manually.";
30
+ function sqliteHasRunsTable(dbPath) {
31
+ if (!existsSync(dbPath)) {
32
+ return false;
33
+ }
34
+ let db;
35
+ try {
36
+ db = new Database(dbPath, { readonly: true, fileMustExist: true });
37
+ const row = db
38
+ .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'runs'")
39
+ .get();
40
+ return row !== undefined;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ finally {
46
+ db?.close();
47
+ }
48
+ }
49
+ function assertNoNestedGlobalStoreConflict(home) {
50
+ const flatDb = path.join(home, STATE_DB_BASENAME);
51
+ const nestedDb = path.join(home, NESTED_GLOBAL_STORE_DIR, STATE_DB_BASENAME);
52
+ if (!existsSync(flatDb) || !existsSync(nestedDb)) {
53
+ return;
54
+ }
55
+ if (!sqliteHasRunsTable(flatDb) && sqliteHasRunsTable(nestedDb)) {
56
+ throw new Error(NESTED_GLOBAL_STORE_CONFLICT);
57
+ }
58
+ }
59
+ function renameIfExists(from, to) {
60
+ if (!existsSync(from) || existsSync(to)) {
61
+ return;
62
+ }
63
+ renameSync(from, to);
64
+ }
65
+ function rollbackStateDbSet(home, nested, moved) {
66
+ for (const name of [...moved].reverse()) {
67
+ const from = path.join(home, name);
68
+ const to = path.join(nested, name);
69
+ if (existsSync(from) && !existsSync(to)) {
70
+ renameSync(from, to);
71
+ }
72
+ }
73
+ }
74
+ function moveStateDbSet(home, nested) {
75
+ const flatMain = path.join(home, STATE_DB_BASENAME);
76
+ const nestedMain = path.join(nested, STATE_DB_BASENAME);
77
+ const flatHasMain = existsSync(flatMain);
78
+ const nestedHasMain = existsSync(nestedMain);
79
+ if (flatHasMain && nestedHasMain) {
80
+ return;
81
+ }
82
+ if (flatHasMain && !nestedHasMain) {
83
+ for (const sidecar of STATE_DB_SIDECARS) {
84
+ renameIfExists(path.join(nested, sidecar), path.join(home, sidecar));
85
+ }
86
+ return;
87
+ }
88
+ if (!flatHasMain && nestedHasMain) {
89
+ const names = [STATE_DB_BASENAME, ...STATE_DB_SIDECARS];
90
+ const moved = [];
91
+ try {
92
+ for (const name of names) {
93
+ const from = path.join(nested, name);
94
+ const to = path.join(home, name);
95
+ if (existsSync(from) && !existsSync(to)) {
96
+ renameSync(from, to);
97
+ moved.push(name);
98
+ }
99
+ }
100
+ }
101
+ catch (err) {
102
+ rollbackStateDbSet(home, nested, moved);
103
+ throw err;
104
+ }
105
+ }
106
+ }
107
+ function flatStorePathAbsent(home, name) {
108
+ const target = path.join(home, name);
109
+ const state = directoryState(target);
110
+ return state === "missing";
111
+ }
112
+ function moveNestedStoreDirs(home, nested) {
113
+ for (const dirName of NESTED_STORE_MOVE_DIRS) {
114
+ const from = path.join(nested, dirName);
115
+ const to = path.join(home, dirName);
116
+ if (directoryState(from) === "missing") {
117
+ continue;
118
+ }
119
+ if (!flatStorePathAbsent(home, dirName)) {
120
+ continue;
121
+ }
122
+ renameSync(from, to);
123
+ }
124
+ }
125
+ function removeNestedGlobalStoreDirIfEmpty(home) {
126
+ const nested = path.join(home, NESTED_GLOBAL_STORE_DIR);
127
+ const state = directoryState(nested);
128
+ if (state === "missing" || state === "other") {
129
+ return;
130
+ }
131
+ const inventory = [
132
+ STATE_DB_BASENAME,
133
+ ...STATE_DB_SIDECARS,
134
+ ...NESTED_STORE_MOVE_DIRS,
135
+ ];
136
+ for (const name of inventory) {
137
+ if (existsSync(path.join(nested, name))) {
138
+ return;
139
+ }
140
+ }
141
+ if (state === "empty") {
142
+ rmdirSync(nested);
143
+ }
144
+ }
145
+ export function flattenNestedGlobalStore(home) {
146
+ const nested = path.join(home, NESTED_GLOBAL_STORE_DIR);
147
+ const nestedState = directoryState(nested);
148
+ if (nestedState === "missing" || nestedState === "other") {
149
+ assertNoNestedGlobalStoreConflict(home);
150
+ return;
151
+ }
152
+ assertNoNestedGlobalStoreConflict(home);
153
+ moveStateDbSet(home, nested);
154
+ moveNestedStoreDirs(home, nested);
155
+ removeNestedGlobalStoreDirIfEmpty(home);
156
+ }
13
157
  function directoryState(dirPath) {
14
158
  try {
15
159
  const st = statSync(dirPath);
@@ -1,4 +1,5 @@
1
1
  import type { StageLogLine } from "../agent/activity.js";
2
+ import type { ConfigOriginRecord } from "../config/configOrigin.js";
2
3
  import type { RunSubmission, RunSubmissionRecord } from "./submission.js";
3
4
  import type { AskOperatorPrompt } from "../tools/askOperator.js";
4
5
  import type { StageEnvelope } from "../types/envelope.js";
@@ -6,14 +7,15 @@ import type { FeedbackLoopConfig, InlinePipelineDefinition, ResolvedPipelineDag
6
7
  import type { CompletionCheck } from "../types/completion.js";
7
8
  import type { StageGateKind } from "../types/stage.js";
8
9
  import type { StageUsage } from "../types/usage.js";
9
- export type RunStatus = "created" | "running" | "succeeded" | "failed";
10
+ export type { ConfigOriginRecord };
11
+ export type RunStatus = "created" | "queued" | "running" | "succeeded" | "failed" | "cancelled";
10
12
  export type RunPipelineDagSnapshot = ResolvedPipelineDag & {
11
13
  stage_ids: string[];
12
14
  gate_kinds?: Record<string, StageGateKind[]>;
13
15
  /** IR: per-stage clone assignment schema. YAML: `io.input.schema`. */
14
16
  clone_input_schema?: Record<string, unknown>;
15
17
  };
16
- export type StageReadiness = "blocked" | "ready" | "running" | "waiting" | "succeeded" | "failed" | "skipped";
18
+ export type StageReadiness = "blocked" | "ready" | "running" | "waiting" | "interrupted" | "succeeded" | "failed" | "skipped";
17
19
  export type PipelineTrackNode = {
18
20
  stage_id: string;
19
21
  status: StageSnapshot["status"];
@@ -52,12 +54,25 @@ export type RunMeta = {
52
54
  pipeline_path?: string;
53
55
  task_path?: string;
54
56
  project_root?: string;
57
+ repository?: string;
58
+ ref?: string;
59
+ resolved_sha?: string;
60
+ run_branch?: string;
61
+ git_author_name?: string;
62
+ git_author_email?: string;
63
+ cancel_reason?: string;
64
+ finished_at?: string;
65
+ slimmed_at?: string;
66
+ disk_bytes?: number;
67
+ disk_measured_at?: string;
68
+ config_origins?: ConfigOriginRecord[];
69
+ pipeline_source?: "inline" | "path";
70
+ caller_id?: string;
71
+ run_manifest?: unknown;
72
+ skip_gates?: boolean;
55
73
  /**
56
- * The raw pipeline body for a run started from an inline pipeline
57
- * (no pipeline_path). Lets a fresh stage-worker process — which has no
58
- * memory of the original in-process call — reconstruct the pipeline
59
- * without needing a catalog file, mirroring how task_yaml already lets
60
- * task reconstruction work without a task_path.
74
+ * Parsed inline pipeline body for stage-worker reload when there is no
75
+ * pipeline_path. Derived from stored pipeline_body.
61
76
  */
62
77
  inline_pipeline?: InlinePipelineDefinition;
63
78
  };
@@ -73,7 +88,7 @@ export type StageLogEvent = StageLogLine & {
73
88
  export type StageSnapshot = {
74
89
  stage_id: string;
75
90
  definition_id?: string;
76
- status: "pending" | "running" | "waiting_for_input" | "succeeded" | "failed" | "skipped";
91
+ status: "pending" | "running" | "waiting_for_input" | "interrupted" | "succeeded" | "failed" | "skipped";
77
92
  events: StageLogEvent[];
78
93
  envelope: StageEnvelope | null;
79
94
  artifacts: string[];
@@ -94,6 +109,7 @@ export type StageExecution = {
94
109
  envelope: StageEnvelope | null;
95
110
  cost_usd?: number;
96
111
  usage?: StageUsage;
112
+ auto_resume_count: number;
97
113
  };
98
114
  export type StageExecutionPatch = {
99
115
  status?: StageSnapshot["status"];
@@ -103,6 +119,7 @@ export type StageExecutionPatch = {
103
119
  envelope?: StageEnvelope | null;
104
120
  cost_usd?: number;
105
121
  usage?: StageUsage;
122
+ auto_resume_count?: number;
106
123
  };
107
124
  /** The durable disposition of completion verification for one stage attempt. */
108
125
  export type VerificationOutcome = "not_run" | "passed" | "failed" | "error";
@@ -238,6 +255,16 @@ export type CompactStage = {
238
255
  definition_id?: string;
239
256
  cost_usd?: number;
240
257
  };
258
+ export type RunBindingCompact = {
259
+ kind: "repository" | "checkout" | "unbound";
260
+ repository?: string;
261
+ ref?: string;
262
+ resolved_sha?: string;
263
+ };
264
+ export type RunBindingDetail = RunBindingCompact & {
265
+ run_branch?: string;
266
+ checkout_root?: string;
267
+ };
241
268
  export type RunSummary = {
242
269
  run_id: string;
243
270
  pipeline_id: string;
@@ -245,9 +272,11 @@ export type RunSummary = {
245
272
  pipeline_path?: string;
246
273
  task_path?: string;
247
274
  project_root?: string;
275
+ pipeline_source?: "inline" | "path";
248
276
  status: RunStatus;
249
277
  created_at: string;
250
278
  updated_at?: string;
279
+ binding: RunBindingCompact;
251
280
  stages: CompactStage[];
252
281
  /** Present when a stage is waiting_for_input (first such stage). */
253
282
  waiting_stage_id?: string;
@@ -265,13 +294,22 @@ export type RunSummary = {
265
294
  active_feedback_loop?: FeedbackLoopRecord;
266
295
  /** Sum of every stage's cost_usd; omitted when no stage reported usage. */
267
296
  total_cost_usd?: number;
297
+ cancel_reason?: string;
298
+ finished_at?: string;
299
+ slimmed_at?: string;
300
+ disk_bytes?: number;
301
+ disk_measured_at?: string;
268
302
  };
269
- export type RunDetail = Omit<RunSummary, "stages"> & {
303
+ export type RunDetail = Omit<RunSummary, "stages" | "binding"> & {
304
+ binding: RunBindingDetail;
270
305
  task_yaml: string;
271
306
  stages: StageSnapshot[];
272
307
  pipeline_track: PipelineTrackProjection;
273
308
  /** Append-only feedback-loop and replay history, ordered by creation. */
274
309
  feedback_loops: FeedbackLoopHistory[];
310
+ config_origins?: ConfigOriginRecord[];
311
+ caller_id?: string;
312
+ run_manifest?: unknown;
275
313
  };
276
314
  export type FeedbackLoopHistory = {
277
315
  loop: FeedbackLoopRecord;
@@ -285,6 +323,7 @@ export type FeedbackLoopHistory = {
285
323
  };
286
324
  export type CreateRunInput = {
287
325
  submission?: RunSubmission;
326
+ runId?: string;
288
327
  pipelineId: string;
289
328
  taskYaml: string;
290
329
  taskId?: string;
@@ -296,8 +335,24 @@ export type CreateRunInput = {
296
335
  pipelinePath?: string;
297
336
  taskPath?: string;
298
337
  projectRoot?: string;
299
- /** Raw inline pipeline body, persisted only when pipelinePath is absent. */
338
+ repository?: string;
339
+ ref?: string;
340
+ resolvedSha?: string;
341
+ runBranch?: string;
342
+ gitAuthorName?: string;
343
+ gitAuthorEmail?: string;
344
+ status?: RunStatus;
345
+ pipelineSource?: "inline" | "path";
346
+ /** Durable JSON string stored in pipeline_body. Prefer this for slots writers. */
347
+ pipelineBody?: string;
348
+ /**
349
+ * Convenience for callers/tests that have a parsed inline pipeline.
350
+ * Stored as pipeline_body JSON; surfaced back as meta.inline_pipeline on read.
351
+ */
300
352
  inlinePipeline?: InlinePipelineDefinition;
353
+ callerId?: string;
354
+ runManifest?: unknown;
355
+ skipGates?: boolean;
301
356
  };
302
357
  export type ListRunsFilter = {
303
358
  status?: RunStatus;
@@ -305,6 +360,7 @@ export type ListRunsFilter = {
305
360
  since?: string;
306
361
  /** Match pipeline_id or pipeline_path */
307
362
  pipeline?: string;
363
+ caller_id?: string;
308
364
  };
309
365
  /**
310
366
  * Persistence port for pipeline run state.
@@ -313,11 +369,49 @@ export type ListRunsFilter = {
313
369
  * run id is all you have (catalog / rehydrate).
314
370
  */
315
371
  export interface RunStore {
372
+ /** Checkpoint WAL (when applicable) and release the store connection. */
373
+ close(): Promise<void>;
374
+ /**
375
+ * Consistent compacted snapshot of the live DB via `VACUUM INTO`.
376
+ * Only SqliteRunStore implements this; callers must not open a second raw connection.
377
+ */
378
+ snapshotInto(destPath: string): Promise<{
379
+ userVersion: number;
380
+ }>;
316
381
  getRunBySubmission(key: string): Promise<RunSubmissionRecord | null>;
317
382
  createRun(input: CreateRunInput): Promise<CreatedRun>;
318
383
  updateRunStatus(runId: string, status: RunStatus): Promise<void>;
384
+ /**
385
+ * Conditional status update (CAS): sets `status` only when the row currently
386
+ * has `expectedStatus`. Returns false when the run exists but status differs;
387
+ * throws when the run is missing.
388
+ */
389
+ tryUpdateRunStatus(runId: string, status: RunStatus, expectedStatus: RunStatus): Promise<boolean>;
390
+ /** Patch workspace-binding columns on an existing run (queued → materialize). */
391
+ patchRunWorkspaceBinding(runId: string, patch: {
392
+ checkoutRoot?: string;
393
+ repository?: string;
394
+ ref?: string;
395
+ resolvedSha?: string;
396
+ runBranch?: string;
397
+ }): Promise<void>;
398
+ /** Append resolved config origin records (MCP / skill / verify). Dedupes by name+origin+path. */
399
+ appendConfigOrigins(runId: string, origins: ConfigOriginRecord[]): Promise<void>;
400
+ setCancelReason(runId: string, reason: string): Promise<void>;
401
+ /** Persist cached disk usage for `listRuns` (never measured inside listRuns). */
402
+ setRunDiskUsage(runId: string, diskBytes: number, measuredAt: string): Promise<void>;
403
+ /** Record that SLIM reclaim completed for this run (R18 idempotency gate). */
404
+ setSlimmedAt(runId: string, slimmedAt: string): Promise<void>;
405
+ /** Hard-delete every run-scoped row. Throws `Run not found: …` when missing. */
406
+ deleteRun(runId: string): Promise<void>;
319
407
  readRunMeta(runId: string): Promise<RunMeta>;
320
408
  readTaskYaml(runId: string): Promise<string>;
409
+ readPipelineBody(runId: string): Promise<string | null>;
410
+ /**
411
+ * Atomic replace of the `run_manifest` JSON blob (build → redact → write).
412
+ * Pass `null` to clear.
413
+ */
414
+ updateRunManifest(runId: string, manifest: unknown): Promise<void>;
321
415
  /** Opaque run workspace root for agents and artifact tools. */
322
416
  getWorkspaceDir(runId: string): string;
323
417
  ensureStageWorkspace(runId: string, stageId: string): Promise<void>;
@@ -327,6 +421,8 @@ export interface RunStore {
327
421
  getLatestStageExecution(runId: string, stageId: string): Promise<StageExecution | null>;
328
422
  countStageAttempts(runId: string, stageId: string): Promise<number>;
329
423
  getStageExecution(runId: string, stageId: string, attempt: number): Promise<StageExecution>;
424
+ /** Latest attempt rows whose status is `interrupted` (targeted scan; not listRuns). */
425
+ listInterruptedStageExecutions(): Promise<StageExecution[]>;
330
426
  updateStageExecution(runId: string, stageId: string, attempt: number, patch: StageExecutionPatch): Promise<void>;
331
427
  /** Create or update evidence for one check in a stage execution attempt. */
332
428
  upsertVerificationCheckResult(runId: string, stageId: string, result: VerificationCheckResultPatch, options?: {
@@ -346,8 +442,10 @@ export interface RunStore {
346
442
  }): Promise<void>;
347
443
  listStageEvents(runId: string, stageId: string, attempt?: number): Promise<StageLogEvent[]>;
348
444
  listRuns(filter?: ListRunsFilter): Promise<RunSummary[]>;
349
- /** Every distinct non-empty project_root recorded across all runs. */
350
- listProjectRoots(): Promise<string[]>;
445
+ /** Idempotent upsert; returns the realpath/resolve-normalized absolute key. */
446
+ ensureProject(absPath: string): Promise<string>;
447
+ /** Absolute roots from the durable projects registry. */
448
+ listRegisteredProjects(): Promise<string[]>;
351
449
  readRun(runId: string): Promise<RunDetail>;
352
450
  updatePipelineDag(runId: string, dag: RunPipelineDagSnapshot): Promise<void>;
353
451
  createFeedbackLoop(runId: string, input: CreateFeedbackLoopInput): Promise<FeedbackLoopRecord>;
@@ -377,4 +475,4 @@ export interface RunStore {
377
475
  }
378
476
  export declare function stageStatusFromEvents(events: StageLogEvent[]): StageSnapshot["status"];
379
477
  export declare function findUnhandledFailedStage(stages: StageSnapshot[], dag?: Pick<RunPipelineDagSnapshot, "nodes"> | null): StageSnapshot | undefined;
380
- export declare function deriveStatusFromStages(stages: StageSnapshot[], dag?: Pick<RunPipelineDagSnapshot, "nodes"> | null): RunStatus;
478
+ export declare function deriveStatusFromStages(stages: StageSnapshot[], dag?: Pick<RunPipelineDagSnapshot, "nodes"> | null, currentStatus?: RunStatus): RunStatus;