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
package/dist/cli.js CHANGED
@@ -8,6 +8,10 @@ import { globalAgentBackendFromManifest, resolveAgentPort } from "./agent/resolv
8
8
  import { ARTIFACT_USAGE, runArtifactCommand } from "./cli/artifactCommand.js";
9
9
  import { ENVELOPE_USAGE, runEnvelopeCommand, } from "./cli/envelopeCommand.js";
10
10
  import { EXPORT_RUN_USAGE, runExportRunCommand, } from "./cli/exportRunCommand.js";
11
+ import { DEBUG_RUN_USAGE, runDebugRunCommand, } from "./cli/debugRunCommand.js";
12
+ import { BACKUP_USAGE, runBackupCommand, } from "./cli/backupCommand.js";
13
+ import { RESTORE_USAGE, runRestoreCommand, } from "./cli/restoreCommand.js";
14
+ import { EXPORT_ALL_USAGE, runExportAllCommand, } from "./cli/exportAllCommand.js";
11
15
  import { INIT_USAGE, runInitCommand } from "./cli/initCommand.js";
12
16
  import { PROVIDERS_USAGE, runProvidersCommand } from "./cli/providersCommand.js";
13
17
  import { RUN_USAGE, runRunCommand } from "./cli/runCommand.js";
@@ -18,24 +22,35 @@ import { SKILLS_USAGE, runSkillsCommand } from "./cli/skillsCommand.js";
18
22
  import { VALIDATE_USAGE, runValidateCommand } from "./cli/validateCommand.js";
19
23
  import { GRAPH_USAGE, runGraphCommand } from "./cli/graphCommand.js";
20
24
  import { MIGRATE_YAML_USAGE, runMigrateYamlCommand } from "./cli/migrateYamlCommand.js";
21
- import { createRunStore } from "./runstore/createStore.js";
25
+ import { DOCTOR_USAGE, runDoctorCommand } from "./cli/doctorCommand.js";
22
26
  import { resolveStageflowContext } from "./project/resolveStageflowContext.js";
23
27
  import { exitForOutcome, runStageWorker } from "./runtime/stageWorker.js";
28
+ import { scheduleExitWithDrain } from "./runtime/stageWorkerProtocol.js";
24
29
  import { SF_STAGE_WORKER } from "./runtime/stageWorkerProtocol.js";
25
30
  import { DEFAULT_PORT, startUiServer } from "./server/http.js";
26
31
  import { startMcpServer } from "./server/mcpHost.js";
32
+ import { resolveListenHost } from "./server/listenHost.js";
33
+ import { assertBindAllowed, BindRefusedError, loadControlTokens, } from "./server/controlToken.js";
27
34
  import { resolveMcpStateless } from "./mcp/server.js";
28
- import { PACKAGE_VERSION } from "./package-meta.js";
35
+ import { PACKAGE_VERSION, BUILD_SHA } from "./package-meta.js";
36
+ import { installProxyDispatcher } from "./net/proxy.js";
37
+ import { warnMissingCaPaths } from "./preflight/tls.js";
38
+ import { logger as cliLogger } from "./logging/logger.js";
29
39
  const USAGE = `Usage:
30
40
  sf init
31
- sf run --task <path> --pipeline <path> [--checkout <path>] [--json] [--include stages] [--skip-gates] [--git-sha <sha>] [--ci-pr-url <url>] [--ci-job-url <url>] [--operator-cwd <path>] [--operator-agent-dir <path>]
41
+ sf run --task <path> --pipeline <path> [--checkout <path>] [--repository <owner/repo>] [--ref <ref>] [--json] [--include stages] [--skip-gates] [--git-sha <sha>] [--ci-pr-url <url>] [--ci-job-url <url>] [--operator-cwd <path>] [--operator-agent-dir <path>]
32
42
  sf run-stage (--stage <path> | --stage-inline '<json>') (--task <path> | --task-inline '<json>' | --envelope-ref <runId>:<stageId>[:<attempt>]) [--checkout <path>] [--model <id>] [--blocking] [--timeout-ms <n>] [--json]
33
43
  sf validate [--pipeline <path>] [--task <path>] [--strict] [--json]
44
+ sf doctor [--json] [--pipeline <path>] [--strict]
34
45
  sf graph --pipeline <path> [--json]
35
46
  sf migrate-yaml [path] [--root <path>] [--write] [--json] [--force]
36
47
  sf artifact read --run <runId> --path <relPath> [--out <file>]
37
48
  sf envelope get --run <runId> --stage <stageId> [--json] [--from <sf-run.json>] [--detect-stage <id>] [--format envelope|handoff]
38
49
  sf export-run --run <runId> [--from <sf-run.json>] [--out <file>]
50
+ sf debug-run <runId> [--out <file>]
51
+ sf backup [--out <file>] [--db-only] [--no-credentials] [--include-a2a-artifacts] [--json]
52
+ sf restore <file> [--force] [--json]
53
+ sf export --all [--status <status>] [--since <iso>] [--pipeline <id-or-path>] [--out <file>]
39
54
  sf runs list [--status created|running|succeeded|failed] [--since <iso>] [--pipeline <id-or-path>] [--json]
40
55
  sf runs show --run <runId> [--from <sf-run.json>] [--json]
41
56
  sf runs verify --run <runId> --stage <stageId> [--json]
@@ -46,9 +61,9 @@ const USAGE = `Usage:
46
61
  sf runs retry --run <runId> --stage <stageId> [--json]
47
62
  sf runs resume --run <runId> --stage <stageId> [--json]
48
63
  sf runs abandon --run <runId> --stage <stageId> [--json]
49
- sf runs rerun --run <runId> [--json]
50
- sf ui [--port ${DEFAULT_PORT}] [--mcp-stateless]
51
- sf mcp [--port ${DEFAULT_PORT}] [--mcp-stateless]
64
+ sf runs rerun --run <runId> [--pinned] [--json]
65
+ sf ui [--host <addr>] [--port ${DEFAULT_PORT}] [--no-open] [--mcp-stateless]
66
+ sf mcp [--host <addr>] [--port ${DEFAULT_PORT}] [--mcp-stateless]
52
67
  sf providers list
53
68
  sf providers status [--provider <id>]
54
69
  sf providers detect
@@ -76,6 +91,8 @@ ${RUN_STAGE_USAGE}
76
91
 
77
92
  ${VALIDATE_USAGE}
78
93
 
94
+ ${DOCTOR_USAGE}
95
+
79
96
  ${GRAPH_USAGE}
80
97
 
81
98
  ${A2A_USAGE}
@@ -88,6 +105,14 @@ ${ENVELOPE_USAGE}
88
105
 
89
106
  ${EXPORT_RUN_USAGE}
90
107
 
108
+ ${DEBUG_RUN_USAGE}
109
+
110
+ ${BACKUP_USAGE}
111
+
112
+ ${RESTORE_USAGE}
113
+
114
+ ${EXPORT_ALL_USAGE}
115
+
91
116
  ${RUNS_USAGE}
92
117
 
93
118
  ${PROVIDERS_USAGE}
@@ -103,14 +128,17 @@ function parseArgs(argv) {
103
128
  return { help: true };
104
129
  }
105
130
  if (args[0] === "--version" || args[0] === "-V") {
106
- if (args.length > 1) {
107
- throw new Error(`Unexpected argument: ${args[1]}`);
131
+ const versionJson = args.includes("--json");
132
+ const rest = args.slice(1).filter((a) => a !== "--json");
133
+ if (rest.length > 0) {
134
+ throw new Error(`Unexpected argument: ${rest[0]}`);
108
135
  }
109
- return { help: false, version: true };
136
+ return { help: false, version: true, versionJson };
110
137
  }
111
138
  const command = args[0];
112
139
  if (command === "providers" ||
113
140
  command === "validate" ||
141
+ command === "doctor" ||
114
142
  command === "graph" ||
115
143
  command === "a2a" ||
116
144
  command === "migrate-yaml" ||
@@ -120,6 +148,10 @@ function parseArgs(argv) {
120
148
  command === "artifact" ||
121
149
  command === "envelope" ||
122
150
  command === "export-run" ||
151
+ command === "debug-run" ||
152
+ command === "backup" ||
153
+ command === "restore" ||
154
+ command === "export" ||
123
155
  command === "runs" ||
124
156
  command === "skills") {
125
157
  return { help: false, command };
@@ -130,7 +162,11 @@ function parseArgs(argv) {
130
162
  let task;
131
163
  let pipeline;
132
164
  let port;
165
+ let host;
166
+ let noOpen = false;
133
167
  let checkout;
168
+ let repository;
169
+ let ref;
134
170
  let mcpStateless = false;
135
171
  for (let i = 1; i < args.length; i++) {
136
172
  if (args[i] === "--task") {
@@ -146,6 +182,20 @@ function parseArgs(argv) {
146
182
  }
147
183
  checkout = raw;
148
184
  }
185
+ else if (args[i] === "--repository") {
186
+ const raw = args[++i];
187
+ if (raw === undefined || raw.length === 0) {
188
+ throw new Error("Missing value for --repository");
189
+ }
190
+ repository = raw;
191
+ }
192
+ else if (args[i] === "--ref") {
193
+ const raw = args[++i];
194
+ if (raw === undefined || raw.length === 0) {
195
+ throw new Error("Missing value for --ref");
196
+ }
197
+ ref = raw;
198
+ }
149
199
  else if (args[i] === "--port") {
150
200
  const raw = args[++i];
151
201
  port = Number(raw);
@@ -153,11 +203,33 @@ function parseArgs(argv) {
153
203
  throw new Error(`Invalid --port: ${raw}`);
154
204
  }
155
205
  }
206
+ else if (args[i] === "--host") {
207
+ const raw = args[++i];
208
+ if (raw === undefined || raw.length === 0) {
209
+ throw new Error("Missing value for --host");
210
+ }
211
+ host = raw;
212
+ }
213
+ else if (args[i] === "--no-open") {
214
+ noOpen = true;
215
+ }
156
216
  else if (args[i] === "--mcp-stateless") {
157
217
  mcpStateless = true;
158
218
  }
159
219
  }
160
- return { help: false, command, task, pipeline, port, checkout, mcpStateless };
220
+ return {
221
+ help: false,
222
+ command,
223
+ task,
224
+ pipeline,
225
+ port,
226
+ host,
227
+ noOpen,
228
+ checkout,
229
+ repository,
230
+ ref,
231
+ mcpStateless,
232
+ };
161
233
  }
162
234
  export function parseRunStageArgs(argv) {
163
235
  let runId;
@@ -254,6 +326,9 @@ async function handleInternalRunStage(argv) {
254
326
  if (process.env[SF_STAGE_WORKER] !== "1") {
255
327
  process.env[SF_STAGE_WORKER] = "1";
256
328
  }
329
+ installProxyDispatcher(process.env, {
330
+ log: (msg) => cliLogger.info("proxy.dispatcher", msg),
331
+ });
257
332
  const parsed = parseRunStageArgs(argv);
258
333
  const outcome = await runStageWorker({
259
334
  runId: parsed.runId,
@@ -267,29 +342,55 @@ async function handleInternalRunStage(argv) {
267
342
  operatorCatalog: parsed.operatorCatalog,
268
343
  skipGates: parsed.skipGates,
269
344
  });
270
- exitForOutcome(outcome);
345
+ return exitForOutcome(outcome);
271
346
  }
272
347
  function openBrowser(url) {
273
348
  const platform = process.platform;
349
+ let child;
274
350
  if (platform === "darwin") {
275
- spawn("open", [url], { detached: true, stdio: "ignore" }).unref();
351
+ child = spawn("open", [url], { detached: true, stdio: "ignore" });
276
352
  }
277
353
  else if (platform === "win32") {
278
- spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
354
+ child = spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" });
279
355
  }
280
356
  else {
281
- spawn("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
357
+ child = spawn("xdg-open", [url], { detached: true, stdio: "ignore" });
282
358
  }
359
+ child.on("error", () => { });
360
+ child.unref();
361
+ }
362
+ function isNoOpenEnabled(flag, env = process.env) {
363
+ if (flag)
364
+ return true;
365
+ const raw = env.STAGEFLOW_NO_OPEN;
366
+ if (raw === undefined || raw.trim() === "")
367
+ return false;
368
+ const normalized = raw.trim().toLowerCase();
369
+ return normalized !== "0" && normalized !== "false";
283
370
  }
284
371
  async function main(argv) {
285
372
  try {
373
+ installProxyDispatcher(process.env, {
374
+ log: (msg) => cliLogger.info("proxy.dispatcher", msg),
375
+ });
376
+ for (const warning of warnMissingCaPaths(process.env)) {
377
+ cliLogger.warn("tls.ca_missing", `${warning.name} points to missing path: ${warning.path}`);
378
+ }
286
379
  const parsed = parseArgs(argv);
287
380
  if (parsed.help) {
288
381
  console.log(USAGE);
289
382
  return argv.slice(2).length === 0 ? 1 : 0;
290
383
  }
291
384
  if (parsed.version) {
292
- console.log(PACKAGE_VERSION);
385
+ if (parsed.versionJson) {
386
+ console.log(JSON.stringify({
387
+ version: PACKAGE_VERSION,
388
+ build_sha: BUILD_SHA,
389
+ }));
390
+ }
391
+ else {
392
+ console.log(PACKAGE_VERSION);
393
+ }
293
394
  return 0;
294
395
  }
295
396
  const ctx = await resolveStageflowContext(process.cwd());
@@ -305,6 +406,9 @@ async function main(argv) {
305
406
  projectRoot: ctx.projectRoot,
306
407
  });
307
408
  }
409
+ if (parsed.command === "doctor") {
410
+ return runDoctorCommand(argv.slice(3), { cwd: ctx.invocationCwd });
411
+ }
308
412
  if (parsed.command === "graph") {
309
413
  return runGraphCommand(argv.slice(3), {
310
414
  cwd: ctx.invocationCwd,
@@ -345,6 +449,25 @@ async function main(argv) {
345
449
  projectRoot: ctx.projectRoot,
346
450
  });
347
451
  }
452
+ if (parsed.command === "debug-run") {
453
+ return runDebugRunCommand(argv.slice(3), {
454
+ cwd: ctx.invocationCwd,
455
+ projectRoot: ctx.projectRoot,
456
+ });
457
+ }
458
+ if (parsed.command === "backup") {
459
+ return runBackupCommand(argv.slice(3), {
460
+ cwd: ctx.invocationCwd,
461
+ });
462
+ }
463
+ if (parsed.command === "restore") {
464
+ return runRestoreCommand(argv.slice(3));
465
+ }
466
+ if (parsed.command === "export") {
467
+ return runExportAllCommand(argv.slice(3), {
468
+ cwd: ctx.invocationCwd,
469
+ });
470
+ }
348
471
  if (parsed.command === "runs") {
349
472
  return runRunsCommand(argv.slice(3), {
350
473
  cwd: ctx.invocationCwd,
@@ -359,41 +482,53 @@ async function main(argv) {
359
482
  projectRoot: ctx.projectRoot,
360
483
  });
361
484
  }
362
- const store = createRunStore({ rootDir: ctx.globalHome });
363
485
  const globalAgent = globalAgentBackendFromManifest(ctx.manifest);
364
486
  if (parsed.command === "ui") {
487
+ const listenHost = resolveListenHost({ flag: parsed.host });
488
+ const tokens = loadControlTokens();
489
+ assertBindAllowed(listenHost, tokens);
365
490
  const mcpStateless = resolveMcpStateless({
366
491
  mcpStateless: parsed.mcpStateless,
367
492
  });
368
- const { url, mcpUrl } = await startUiServer({
493
+ const host = await startUiServer({
369
494
  agent: resolveAgentPort({ global: globalAgent }),
370
- store,
371
495
  cwd: ctx.invocationCwd,
372
496
  rootDir: ctx.projectRoot,
373
497
  port: parsed.port,
498
+ host: listenHost,
374
499
  mcpStateless,
500
+ controlTokens: tokens,
375
501
  });
376
- console.log(`Operator console: ${url}`);
377
- console.log(`MCP endpoint: ${mcpUrl}`);
378
- openBrowser(url);
379
- await new Promise(() => undefined);
380
- return 0;
502
+ console.log(`Operator console: ${host.url}`);
503
+ console.log(`MCP endpoint: ${host.mcpUrl}`);
504
+ if (!isNoOpenEnabled(parsed.noOpen)) {
505
+ openBrowser(host.url);
506
+ }
507
+ const outcome = await host.shutdown.whenDrained();
508
+ return outcome.exitCode;
381
509
  }
382
510
  if (parsed.command === "mcp") {
511
+ if (parsed.noOpen) {
512
+ throw new Error("--no-open is only valid with sf ui");
513
+ }
514
+ const listenHost = resolveListenHost({ flag: parsed.host });
515
+ const tokens = loadControlTokens();
516
+ assertBindAllowed(listenHost, tokens);
383
517
  const mcpStateless = resolveMcpStateless({
384
518
  mcpStateless: parsed.mcpStateless,
385
519
  });
386
- const { mcpUrl } = await startMcpServer({
520
+ const host = await startMcpServer({
387
521
  agent: resolveAgentPort({ global: globalAgent }),
388
- store,
389
522
  cwd: ctx.invocationCwd,
390
523
  rootDir: ctx.projectRoot,
391
524
  port: parsed.port,
525
+ host: listenHost,
392
526
  mcpStateless,
527
+ controlTokens: tokens,
393
528
  });
394
- console.log(`MCP endpoint: ${mcpUrl}`);
395
- await new Promise(() => undefined);
396
- return 0;
529
+ console.log(`MCP endpoint: ${host.mcpUrl}`);
530
+ const outcome = await host.shutdown.whenDrained();
531
+ return outcome.exitCode;
397
532
  }
398
533
  if (parsed.command === "internal") {
399
534
  const subArgs = argv.slice(3);
@@ -409,6 +544,10 @@ async function main(argv) {
409
544
  return 1;
410
545
  }
411
546
  catch (err) {
547
+ if (err instanceof BindRefusedError) {
548
+ console.error(err.message);
549
+ return err.exitCode;
550
+ }
412
551
  console.error(err instanceof Error ? err.message : String(err));
413
552
  return 1;
414
553
  }
@@ -433,9 +572,11 @@ function isDirectCliInvocation() {
433
572
  }
434
573
  if (isDirectCliInvocation()) {
435
574
  main(process.argv)
436
- .then((code) => process.exit(code))
575
+ .then((code) => {
576
+ scheduleExitWithDrain(code);
577
+ })
437
578
  .catch((err) => {
438
579
  console.error(err instanceof Error ? err.message : String(err));
439
- process.exit(1);
580
+ scheduleExitWithDrain(1);
440
581
  });
441
582
  }
@@ -0,0 +1,62 @@
1
+ import type { CatalogRoot, ResolveCatalogRootsOptions } from "./resolveCatalogRoots.js";
2
+ export type CatalogPathErrorCode = "absolute_path_not_allowed" | "path_outside_project_root" | "unknown_project_root" | "catalog_root_read_only";
3
+ export declare class CatalogPathError extends Error {
4
+ readonly code: CatalogPathErrorCode;
5
+ readonly registered_roots: string[];
6
+ constructor(message: string, code: CatalogPathErrorCode, registered_roots: string[]);
7
+ }
8
+ export declare function isInsideProjectRoot(projectRoot: string, candidate: string): boolean;
9
+ export type ResolveCatalogRelativePathInput = {
10
+ /** Caller-supplied path (pipeline, task, etc.). */
11
+ inputPath: string;
12
+ /** Optional wire project_root (symbolic seeded id or absolute). */
13
+ projectRoot?: string;
14
+ roots: CatalogRoot[];
15
+ fieldName?: string;
16
+ };
17
+ export type ResolvedCatalogPath = {
18
+ absolutePath: string;
19
+ root: CatalogRoot;
20
+ relativePath: string;
21
+ };
22
+ /**
23
+ * Network-surface path contract: refuse absolute paths; resolve relative under
24
+ * a selected catalog root; refuse `..` escape via realpath containment.
25
+ */
26
+ export declare function resolveCatalogRelativePath(input: ResolveCatalogRelativePathInput): ResolvedCatalogPath;
27
+ export declare function catalogPathErrorBody(err: CatalogPathError): {
28
+ error: string;
29
+ code: CatalogPathErrorCode;
30
+ registered_roots: string[];
31
+ };
32
+ /**
33
+ * Pick the catalog root for start_run / POST /api/runs.
34
+ * Wire project_root (symbolic seeded id or absolute) maps to CatalogRoot.path
35
+ * (absolute store key). When omitted: sole root, or sole non-seeded root;
36
+ * otherwise require explicit — no invent.
37
+ */
38
+ export declare function selectCatalogRootForStart(roots: CatalogRoot[], projectRoot?: string): CatalogRoot;
39
+ /**
40
+ * Shared helper: resolveCatalogRoots → selectCatalogRootForStart.
41
+ * All network-surface start-input call sites use this to avoid the hand-copy sequence.
42
+ */
43
+ export declare function resolveCatalogStartInput(options: ResolveCatalogRootsOptions, projectRoot?: string): Promise<{
44
+ roots: CatalogRoot[];
45
+ wireRoot: CatalogRoot;
46
+ }>;
47
+ /**
48
+ * Like resolveCatalogStartInput but additionally refuses read-only roots.
49
+ * Used by write surfaces (POST /api/stages, POST /api/pipelines).
50
+ */
51
+ export declare function resolveWritableCatalogRoot(options: ResolveCatalogRootsOptions, projectRoot?: string): Promise<{
52
+ roots: CatalogRoot[];
53
+ wireRoot: CatalogRoot;
54
+ }>;
55
+ /**
56
+ * Local CLI control: turn a cwd-resolved filesystem path into a catalog-relative
57
+ * wire path + project_root so the network surface does not see an absolute path.
58
+ */
59
+ export declare function relativizeLocalPathForNetwork(cwd: string, inputPath: string): {
60
+ path: string;
61
+ project_root: string;
62
+ };
@@ -0,0 +1,118 @@
1
+ import path from "node:path";
2
+ import { realpathSync } from "node:fs";
3
+ import { findCatalogRoot, resolveCatalogRoots } from "./resolveCatalogRoots.js";
4
+ export class CatalogPathError extends Error {
5
+ code;
6
+ registered_roots;
7
+ constructor(message, code, registered_roots) {
8
+ super(message);
9
+ this.name = "CatalogPathError";
10
+ this.code = code;
11
+ this.registered_roots = registered_roots;
12
+ }
13
+ }
14
+ function realOrResolve(p) {
15
+ try {
16
+ return realpathSync(p);
17
+ }
18
+ catch {
19
+ return path.resolve(p);
20
+ }
21
+ }
22
+ export function isInsideProjectRoot(projectRoot, candidate) {
23
+ const rootReal = realOrResolve(projectRoot);
24
+ const candidateReal = realOrResolve(candidate);
25
+ const rel = path.relative(rootReal, candidateReal);
26
+ return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
27
+ }
28
+ /**
29
+ * Network-surface path contract: refuse absolute paths; resolve relative under
30
+ * a selected catalog root; refuse `..` escape via realpath containment.
31
+ */
32
+ export function resolveCatalogRelativePath(input) {
33
+ const field = input.fieldName ?? "path";
34
+ const registered = input.roots.map((r) => r.project_root);
35
+ if (path.isAbsolute(input.inputPath)) {
36
+ throw new CatalogPathError(`Absolute ${field} is not allowed on network surfaces; use a catalog-relative path under a registered project_root, or an inline definition.`, "absolute_path_not_allowed", registered);
37
+ }
38
+ const root = selectCatalogRootForStart(input.roots, input.projectRoot);
39
+ const absolutePath = path.resolve(root.path, input.inputPath);
40
+ if (!isInsideProjectRoot(root.path, absolutePath)) {
41
+ throw new CatalogPathError(`${field} escapes project_root ${root.project_root}`, "path_outside_project_root", registered);
42
+ }
43
+ return {
44
+ absolutePath,
45
+ root,
46
+ relativePath: path.relative(root.path, absolutePath).replace(/\\/g, "/"),
47
+ };
48
+ }
49
+ export function catalogPathErrorBody(err) {
50
+ return {
51
+ error: err.message,
52
+ code: err.code,
53
+ registered_roots: err.registered_roots,
54
+ };
55
+ }
56
+ /**
57
+ * Pick the catalog root for start_run / POST /api/runs.
58
+ * Wire project_root (symbolic seeded id or absolute) maps to CatalogRoot.path
59
+ * (absolute store key). When omitted: sole root, or sole non-seeded root;
60
+ * otherwise require explicit — no invent.
61
+ */
62
+ export function selectCatalogRootForStart(roots, projectRoot) {
63
+ const registered = roots.map((r) => r.project_root);
64
+ if (projectRoot !== undefined) {
65
+ const found = findCatalogRoot(roots, projectRoot);
66
+ if (found === undefined) {
67
+ throw new CatalogPathError(`Unknown project_root: ${projectRoot}`, "unknown_project_root", registered);
68
+ }
69
+ return found;
70
+ }
71
+ if (roots.length === 0) {
72
+ throw new CatalogPathError("No catalog roots configured; ensure a project_root first", "unknown_project_root", registered);
73
+ }
74
+ if (roots.length === 1) {
75
+ return roots[0];
76
+ }
77
+ const writable = roots.filter((r) => r.kind !== "seeded");
78
+ if (writable.length === 1) {
79
+ return writable[0];
80
+ }
81
+ throw new CatalogPathError("project_root is required when multiple catalog roots are configured", "unknown_project_root", registered);
82
+ }
83
+ /**
84
+ * Shared helper: resolveCatalogRoots → selectCatalogRootForStart.
85
+ * All network-surface start-input call sites use this to avoid the hand-copy sequence.
86
+ */
87
+ export async function resolveCatalogStartInput(options, projectRoot) {
88
+ const roots = await resolveCatalogRoots(options);
89
+ const wireRoot = selectCatalogRootForStart(roots, projectRoot);
90
+ return { roots, wireRoot };
91
+ }
92
+ /**
93
+ * Like resolveCatalogStartInput but additionally refuses read-only roots.
94
+ * Used by write surfaces (POST /api/stages, POST /api/pipelines).
95
+ */
96
+ export async function resolveWritableCatalogRoot(options, projectRoot) {
97
+ const { roots, wireRoot } = await resolveCatalogStartInput(options, projectRoot);
98
+ if (wireRoot.read_only) {
99
+ throw new CatalogPathError(`Catalog root ${wireRoot.project_root} is read-only`, "catalog_root_read_only", roots.map((r) => r.project_root));
100
+ }
101
+ return { roots, wireRoot };
102
+ }
103
+ /**
104
+ * Local CLI control: turn a cwd-resolved filesystem path into a catalog-relative
105
+ * wire path + project_root so the network surface does not see an absolute path.
106
+ */
107
+ export function relativizeLocalPathForNetwork(cwd, inputPath) {
108
+ const abs = realOrResolve(path.resolve(cwd, inputPath));
109
+ const cwdAbs = realOrResolve(cwd);
110
+ const rel = path.relative(cwdAbs, abs);
111
+ if (rel.startsWith("..") || path.isAbsolute(rel)) {
112
+ throw new Error(`Path ${abs} is outside CLI cwd ${cwdAbs}; run from the project root, pass a path under cwd, or use an inline definition on the Host API`);
113
+ }
114
+ return {
115
+ path: rel === "" ? "." : rel.replace(/\\/g, "/"),
116
+ project_root: cwdAbs,
117
+ };
118
+ }
@@ -0,0 +1,27 @@
1
+ export type ConfigOriginKind = "catalog" | "inline" | "workspace" | "seeded";
2
+ export type ConfigOriginRecord = {
3
+ name: string;
4
+ origin: ConfigOriginKind;
5
+ path?: string;
6
+ };
7
+ export type BindingKindForOrigin = "repository" | "checkout" | "none";
8
+ export type TrustWorkspaceDecision = {
9
+ allow: boolean;
10
+ origin: ConfigOriginKind;
11
+ code?: "untrusted_config_origin";
12
+ message?: string;
13
+ };
14
+ export declare function bindingKindForOrigin(kind: "repository" | "checkout" | "unbound" | "none" | undefined): BindingKindForOrigin;
15
+ /**
16
+ * Decide whether workspace-sourced config (.mcp.json / skills under checkout)
17
+ * is permitted. Default: refuse for repository bindings; allow for checkout;
18
+ * host trust_workspace_config can allowlisted roots.
19
+ */
20
+ export declare function decideWorkspaceConfigTrust(options: {
21
+ bindingKind: BindingKindForOrigin;
22
+ projectRoot: string;
23
+ trustWorkspaceConfig?: string[];
24
+ source: "workspace" | "catalog" | "inline" | "seeded";
25
+ }): TrustWorkspaceDecision;
26
+ export declare function skillOriginKind(scope: "user" | "project" | "temporary", filePath: string, checkoutRoot: string | undefined): ConfigOriginKind;
27
+ export declare function catalogOrSeededOrigin(projectRoot: string | undefined, seededRoots: readonly string[]): ConfigOriginKind;
@@ -0,0 +1,59 @@
1
+ import path from "node:path";
2
+ export function bindingKindForOrigin(kind) {
3
+ if (kind === "repository" || kind === "checkout")
4
+ return kind;
5
+ return "none";
6
+ }
7
+ /**
8
+ * Decide whether workspace-sourced config (.mcp.json / skills under checkout)
9
+ * is permitted. Default: refuse for repository bindings; allow for checkout;
10
+ * host trust_workspace_config can allowlisted roots.
11
+ */
12
+ export function decideWorkspaceConfigTrust(options) {
13
+ if (options.source !== "workspace") {
14
+ return { allow: true, origin: options.source };
15
+ }
16
+ const trusted = (options.trustWorkspaceConfig ?? []).some((root) => root === options.projectRoot);
17
+ if (trusted) {
18
+ return { allow: true, origin: "workspace" };
19
+ }
20
+ if (options.bindingKind === "checkout") {
21
+ return { allow: true, origin: "workspace" };
22
+ }
23
+ if (options.bindingKind === "repository") {
24
+ return {
25
+ allow: false,
26
+ origin: "workspace",
27
+ code: "untrusted_config_origin",
28
+ message: `Workspace config is not trusted for repository binding at ${options.projectRoot}; set trust_workspace_config in HostConfig to allowlist this root`,
29
+ };
30
+ }
31
+ return {
32
+ allow: false,
33
+ origin: "workspace",
34
+ code: "untrusted_config_origin",
35
+ message: `Workspace config is not trusted at ${options.projectRoot}`,
36
+ };
37
+ }
38
+ function isUnderRoot(candidate, root) {
39
+ const resolvedRoot = path.resolve(root);
40
+ const resolved = path.resolve(candidate);
41
+ const rel = path.relative(resolvedRoot, resolved);
42
+ return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
43
+ }
44
+ export function skillOriginKind(scope, filePath, checkoutRoot) {
45
+ if (scope === "temporary")
46
+ return "inline";
47
+ if (scope === "project" &&
48
+ checkoutRoot !== undefined &&
49
+ isUnderRoot(filePath, checkoutRoot)) {
50
+ return "workspace";
51
+ }
52
+ return "catalog";
53
+ }
54
+ export function catalogOrSeededOrigin(projectRoot, seededRoots) {
55
+ if (projectRoot !== undefined && seededRoots.some((root) => root === projectRoot)) {
56
+ return "seeded";
57
+ }
58
+ return "catalog";
59
+ }