stageflow 0.25.0 → 0.30.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 (681) hide show
  1. package/README.md +14 -3
  2. package/builtin-skills/browser/SKILL.md +42 -0
  3. package/dist/a2a/contracts.d.ts +1 -0
  4. package/dist/a2a/contracts.js +1 -0
  5. package/dist/a2a/registry.d.ts +2 -0
  6. package/dist/a2a/registry.js +20 -1
  7. package/dist/a2a/server.d.ts +7 -0
  8. package/dist/a2a/server.js +5 -2
  9. package/dist/a2a/service.d.ts +1 -1
  10. package/dist/a2a/service.js +57 -8
  11. package/dist/a2a/store.d.ts +8 -5
  12. package/dist/a2a/store.js +24 -67
  13. package/dist/agent/activity.d.ts +3 -0
  14. package/dist/agent/bootProviderConfig.d.ts +21 -0
  15. package/dist/agent/bootProviderConfig.js +74 -0
  16. package/dist/agent/claudeAdapter.js +2 -2
  17. package/dist/agent/cursorProvider.d.ts +2 -0
  18. package/dist/agent/cursorProvider.js +30 -5
  19. package/dist/agent/fakeAgent.d.ts +1 -0
  20. package/dist/agent/fakeAgent.js +13 -0
  21. package/dist/agent/piAdapter.d.ts +11 -24
  22. package/dist/agent/piAdapter.js +107 -50
  23. package/dist/agent/piIsolatedMcp.d.ts +2 -0
  24. package/dist/agent/piIsolatedMcp.js +10 -2
  25. package/dist/agent/piSessionFactory.d.ts +38 -0
  26. package/dist/agent/piSessionFactory.js +60 -0
  27. package/dist/agent/port.d.ts +8 -0
  28. package/dist/agent/streamLogRedact.d.ts +7 -1
  29. package/dist/agent/streamLogRedact.js +26 -11
  30. package/dist/browser/anchor.d.ts +27 -0
  31. package/dist/browser/anchor.js +127 -0
  32. package/dist/browser/auditSink.d.ts +38 -0
  33. package/dist/browser/auditSink.js +34 -0
  34. package/dist/browser/browserHost.d.ts +86 -0
  35. package/dist/browser/browserHost.js +7 -0
  36. package/dist/browser/browserSweep.d.ts +14 -0
  37. package/dist/browser/browserSweep.js +54 -0
  38. package/dist/browser/browserTeardown.d.ts +56 -0
  39. package/dist/browser/browserTeardown.js +235 -0
  40. package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -0
  41. package/dist/browser/fakeRemoteBrowserHost.js +34 -0
  42. package/dist/browser/gateHandoff.d.ts +25 -0
  43. package/dist/browser/gateHandoff.js +83 -0
  44. package/dist/browser/humanLogin.d.ts +18 -0
  45. package/dist/browser/humanLogin.js +34 -0
  46. package/dist/browser/keyProvider.d.ts +10 -0
  47. package/dist/browser/keyProvider.js +39 -0
  48. package/dist/browser/localBrowserHost.d.ts +10 -0
  49. package/dist/browser/localBrowserHost.js +152 -0
  50. package/dist/browser/localProfileLock.d.ts +2 -0
  51. package/dist/browser/localProfileLock.js +218 -0
  52. package/dist/browser/localProfileStore.d.ts +5 -0
  53. package/dist/browser/localProfileStore.js +91 -0
  54. package/dist/browser/loginCheck.d.ts +53 -0
  55. package/dist/browser/loginCheck.js +147 -0
  56. package/dist/browser/memoryProfileLock.d.ts +2 -0
  57. package/dist/browser/memoryProfileLock.js +53 -0
  58. package/dist/browser/memoryProfileStore.d.ts +2 -0
  59. package/dist/browser/memoryProfileStore.js +31 -0
  60. package/dist/browser/navigationAudit.d.ts +16 -0
  61. package/dist/browser/navigationAudit.js +53 -0
  62. package/dist/browser/persistedEnv.d.ts +3 -0
  63. package/dist/browser/persistedEnv.js +15 -0
  64. package/dist/browser/profileLock.d.ts +40 -0
  65. package/dist/browser/profileLock.js +10 -0
  66. package/dist/browser/profileStore.d.ts +23 -0
  67. package/dist/browser/profileStore.js +39 -0
  68. package/dist/browser/runLiveness.d.ts +13 -0
  69. package/dist/browser/runLiveness.js +39 -0
  70. package/dist/browser/sitePolicy.d.ts +10 -0
  71. package/dist/browser/sitePolicy.js +61 -0
  72. package/dist/browser/stageBrowserEnv.d.ts +22 -0
  73. package/dist/browser/stageBrowserEnv.js +147 -0
  74. package/dist/browser/stageProfileLock.d.ts +17 -0
  75. package/dist/browser/stageProfileLock.js +39 -0
  76. package/dist/cli/artifactCommand.js +9 -16
  77. package/dist/cli/backupCommand.d.ts +9 -0
  78. package/dist/cli/backupCommand.js +111 -0
  79. package/dist/cli/browserCommand.d.ts +44 -0
  80. package/dist/cli/browserCommand.js +472 -0
  81. package/dist/cli/debugRunCommand.d.ts +10 -0
  82. package/dist/cli/debugRunCommand.js +109 -0
  83. package/dist/cli/doctorCommand.d.ts +32 -0
  84. package/dist/cli/doctorCommand.js +453 -0
  85. package/dist/cli/envelopeCommand.js +9 -2
  86. package/dist/cli/exportAllCommand.d.ts +55 -0
  87. package/dist/cli/exportAllCommand.js +218 -0
  88. package/dist/cli/exportRunCommand.js +23 -21
  89. package/dist/cli/hostClient.d.ts +41 -3
  90. package/dist/cli/hostClient.js +129 -14
  91. package/dist/cli/initCommand.d.ts +1 -0
  92. package/dist/cli/initCommand.js +23 -7
  93. package/dist/cli/initTemplates.d.ts +5 -2
  94. package/dist/cli/initTemplates.js +32 -2
  95. package/dist/cli/resolveSafeOutPath.d.ts +2 -0
  96. package/dist/cli/resolveSafeOutPath.js +40 -0
  97. package/dist/cli/restoreCommand.d.ts +10 -0
  98. package/dist/cli/restoreCommand.js +90 -0
  99. package/dist/cli/runCommand.d.ts +3 -2
  100. package/dist/cli/runCommand.js +93 -11
  101. package/dist/cli/runOutput.d.ts +4 -0
  102. package/dist/cli/runOutput.js +33 -7
  103. package/dist/cli/runStageCommand.d.ts +1 -0
  104. package/dist/cli/runStageCommand.js +44 -25
  105. package/dist/cli/runsCommand.d.ts +1 -1
  106. package/dist/cli/runsCommand.js +168 -10
  107. package/dist/cli/triggerCommand.d.ts +12 -0
  108. package/dist/cli/triggerCommand.js +183 -0
  109. package/dist/cli/validateCommand.d.ts +1 -1
  110. package/dist/cli/validateCommand.js +23 -6
  111. package/dist/cli.js +202 -32
  112. package/dist/config/browseCatalog.d.ts +1 -0
  113. package/dist/config/browseCatalog.js +5 -4
  114. package/dist/config/builtinSkills.d.ts +4 -0
  115. package/dist/config/builtinSkills.js +23 -0
  116. package/dist/config/catalogRelativePath.d.ts +63 -0
  117. package/dist/config/catalogRelativePath.js +126 -0
  118. package/dist/config/configOrigin.d.ts +27 -0
  119. package/dist/config/configOrigin.js +59 -0
  120. package/dist/config/createTrigger.d.ts +27 -0
  121. package/dist/config/createTrigger.js +232 -0
  122. package/dist/config/draftPackage.d.ts +117 -0
  123. package/dist/config/draftPackage.js +550 -0
  124. package/dist/config/ensureCatalogScanRoot.d.ts +16 -0
  125. package/dist/config/ensureCatalogScanRoot.js +73 -0
  126. package/dist/config/hostConfig.d.ts +57 -0
  127. package/dist/config/hostConfig.js +360 -0
  128. package/dist/config/listSkills.d.ts +26 -0
  129. package/dist/config/listSkills.js +206 -5
  130. package/dist/config/loadOutcome.d.ts +7 -1
  131. package/dist/config/loadPipeline.js +39 -2
  132. package/dist/config/loadStage.js +25 -0
  133. package/dist/config/loadStageflowManifest.js +25 -0
  134. package/dist/config/loadTask.d.ts +2 -0
  135. package/dist/config/loadTask.js +57 -18
  136. package/dist/config/loadTrigger.d.ts +9 -0
  137. package/dist/config/loadTrigger.js +120 -0
  138. package/dist/config/materializeStageModels.js +5 -1
  139. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  140. package/dist/config/mergePipelineIncludes.js +19 -0
  141. package/dist/config/migrateYaml.js +6 -11
  142. package/dist/config/multiProjectCatalog.d.ts +32 -0
  143. package/dist/config/multiProjectCatalog.js +150 -0
  144. package/dist/config/normalizePipelineStageEntry.js +27 -1
  145. package/dist/config/parseCompletionContract.js +6 -0
  146. package/dist/config/pipelineStageKeys.js +3 -0
  147. package/dist/config/publishDraftPackage.d.ts +7 -0
  148. package/dist/config/publishDraftPackage.js +25 -0
  149. package/dist/config/resolveCatalogContext.js +1 -1
  150. package/dist/config/resolveCatalogRoots.d.ts +27 -0
  151. package/dist/config/resolveCatalogRoots.js +76 -0
  152. package/dist/config/resolveModel.d.ts +7 -1
  153. package/dist/config/resolveModel.js +11 -1
  154. package/dist/config/resolvePipelineDag.js +1 -1
  155. package/dist/config/resolveStageMcpServers.d.ts +9 -1
  156. package/dist/config/resolveStageMcpServers.js +36 -9
  157. package/dist/config/scanCatalogPaths.d.ts +1 -1
  158. package/dist/config/scanCatalogPaths.js +6 -2
  159. package/dist/config/secretFromEnvOrFile.d.ts +9 -0
  160. package/dist/config/secretFromEnvOrFile.js +34 -0
  161. package/dist/config/seededCatalog.d.ts +11 -0
  162. package/dist/config/seededCatalog.js +29 -0
  163. package/dist/config/stageBrowser.d.ts +12 -0
  164. package/dist/config/stageBrowser.js +118 -0
  165. package/dist/config/toolRequires.d.ts +24 -0
  166. package/dist/config/toolRequires.js +115 -0
  167. package/dist/config/triggerCatalog.d.ts +10 -0
  168. package/dist/config/triggerCatalog.js +37 -0
  169. package/dist/config/validateCatalog.d.ts +17 -3
  170. package/dist/config/validateCatalog.js +223 -3
  171. package/dist/config/validateCompletionContract.js +8 -0
  172. package/dist/diagnostics/checks.d.ts +39 -0
  173. package/dist/diagnostics/checks.js +135 -0
  174. package/dist/envelope/preEmitChecks.d.ts +1 -1
  175. package/dist/envelope/preEmitChecks.js +8 -0
  176. package/dist/errors/codes.d.ts +14 -0
  177. package/dist/errors/codes.js +59 -0
  178. package/dist/git/cache.d.ts +14 -0
  179. package/dist/git/cache.js +150 -0
  180. package/dist/git/credentials.d.ts +9 -0
  181. package/dist/git/credentials.js +88 -0
  182. package/dist/git/errors.d.ts +20 -0
  183. package/dist/git/errors.js +94 -0
  184. package/dist/git/exec.d.ts +16 -0
  185. package/dist/git/exec.js +135 -0
  186. package/dist/git/operations.d.ts +29 -0
  187. package/dist/git/operations.js +153 -0
  188. package/dist/git/version.d.ts +1 -0
  189. package/dist/git/version.js +10 -0
  190. package/dist/logging/audit.d.ts +16 -0
  191. package/dist/logging/audit.js +19 -0
  192. package/dist/logging/commonWords.d.ts +2 -0
  193. package/dist/logging/commonWords.js +13 -0
  194. package/dist/logging/logger.d.ts +49 -0
  195. package/dist/logging/logger.js +193 -0
  196. package/dist/logging/namedSecrets.d.ts +6 -0
  197. package/dist/logging/namedSecrets.js +58 -0
  198. package/dist/logging/redact.d.ts +17 -0
  199. package/dist/logging/redact.js +105 -0
  200. package/dist/mcp/catalogTools.js +492 -81
  201. package/dist/mcp/checkoutTools.d.ts +52 -0
  202. package/dist/mcp/checkoutTools.js +332 -0
  203. package/dist/mcp/controlTools.js +182 -6
  204. package/dist/mcp/deps.d.ts +3 -0
  205. package/dist/mcp/getStartedTool.d.ts +3 -0
  206. package/dist/mcp/getStartedTool.js +62 -0
  207. package/dist/mcp/readArtifact.d.ts +11 -0
  208. package/dist/mcp/readArtifact.js +46 -30
  209. package/dist/mcp/server.js +2 -0
  210. package/dist/mcp/tools.js +6 -0
  211. package/dist/mcp/triggerTools.d.ts +3 -0
  212. package/dist/mcp/triggerTools.js +176 -0
  213. package/dist/net/proxy.d.ts +14 -0
  214. package/dist/net/proxy.js +78 -0
  215. package/dist/operatorAgent/docsRetrieval.d.ts +40 -0
  216. package/dist/operatorAgent/docsRetrieval.js +269 -0
  217. package/dist/operatorAgent/draftContext.d.ts +16 -0
  218. package/dist/operatorAgent/draftContext.js +68 -0
  219. package/dist/operatorAgent/fakeHost.d.ts +39 -0
  220. package/dist/operatorAgent/fakeHost.js +92 -0
  221. package/dist/operatorAgent/host.d.ts +40 -0
  222. package/dist/operatorAgent/host.js +179 -0
  223. package/dist/operatorAgent/index.d.ts +9 -0
  224. package/dist/operatorAgent/index.js +8 -0
  225. package/dist/operatorAgent/piModel.d.ts +80 -0
  226. package/dist/operatorAgent/piModel.js +528 -0
  227. package/dist/operatorAgent/profiles/workshopAuthor.d.ts +23 -0
  228. package/dist/operatorAgent/profiles/workshopAuthor.js +338 -0
  229. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +6 -0
  230. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +103 -0
  231. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +57 -0
  232. package/dist/operatorAgent/profiles/workshopAuthorTools.js +623 -0
  233. package/dist/operatorAgent/proposals.d.ts +32 -0
  234. package/dist/operatorAgent/proposals.js +144 -0
  235. package/dist/operatorAgent/types.d.ts +128 -0
  236. package/dist/operatorAgent/types.js +1 -0
  237. package/dist/package-meta.d.ts +2 -1
  238. package/dist/package-meta.js +2 -1
  239. package/dist/preflight/bash.d.ts +8 -0
  240. package/dist/preflight/bash.js +34 -0
  241. package/dist/preflight/claudeRoot.d.ts +11 -0
  242. package/dist/preflight/claudeRoot.js +23 -0
  243. package/dist/preflight/mcpCommands.d.ts +8 -0
  244. package/dist/preflight/mcpCommands.js +36 -0
  245. package/dist/preflight/pipelinePreflight.d.ts +40 -0
  246. package/dist/preflight/pipelinePreflight.js +192 -0
  247. package/dist/preflight/tls.d.ts +6 -0
  248. package/dist/preflight/tls.js +18 -0
  249. package/dist/preflight/toolchain.d.ts +45 -0
  250. package/dist/preflight/toolchain.js +219 -0
  251. package/dist/project/findManifestRoot.d.ts +3 -0
  252. package/dist/project/findManifestRoot.js +35 -0
  253. package/dist/project/findProjectRoot.js +3 -4
  254. package/dist/project/globalHome.d.ts +7 -0
  255. package/dist/project/globalHome.js +63 -2
  256. package/dist/project/resolveProjectContext.js +2 -2
  257. package/dist/project/resolveStageflowContext.d.ts +7 -0
  258. package/dist/project/resolveStageflowContext.js +46 -30
  259. package/dist/projection/projectRun.d.ts +2 -1
  260. package/dist/projection/projectRun.js +1 -0
  261. package/dist/runstore/assertTmpdir.d.ts +1 -0
  262. package/dist/runstore/assertTmpdir.js +25 -0
  263. package/dist/runstore/backup.d.ts +52 -0
  264. package/dist/runstore/backup.js +292 -0
  265. package/dist/runstore/createStore.d.ts +18 -1
  266. package/dist/runstore/createStore.js +64 -5
  267. package/dist/runstore/debugBundle.d.ts +60 -0
  268. package/dist/runstore/debugBundle.js +143 -0
  269. package/dist/runstore/diskUsage.d.ts +50 -0
  270. package/dist/runstore/diskUsage.js +214 -0
  271. package/dist/runstore/exportRunPayload.d.ts +8 -0
  272. package/dist/runstore/exportRunPayload.js +23 -0
  273. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  274. package/dist/runstore/normalizeCatalogPath.js +10 -0
  275. package/dist/runstore/paths.d.ts +5 -0
  276. package/dist/runstore/paths.js +145 -1
  277. package/dist/runstore/port.d.ts +139 -13
  278. package/dist/runstore/port.js +8 -1
  279. package/dist/runstore/restore.d.ts +81 -0
  280. package/dist/runstore/restore.js +355 -0
  281. package/dist/runstore/retention.d.ts +27 -0
  282. package/dist/runstore/retention.js +74 -0
  283. package/dist/runstore/runManifest.d.ts +146 -0
  284. package/dist/runstore/runManifest.js +288 -0
  285. package/dist/runstore/runProjection.d.ts +3 -1
  286. package/dist/runstore/runProjection.js +63 -1
  287. package/dist/runstore/sqlite/SqliteRunStore.d.ts +35 -3
  288. package/dist/runstore/sqlite/SqliteRunStore.js +442 -219
  289. package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
  290. package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
  291. package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
  292. package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
  293. package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
  294. package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
  295. package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
  296. package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
  297. package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
  298. package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
  299. package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
  300. package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
  301. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
  302. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
  303. package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
  304. package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
  305. package/dist/runstore/sqlite/migrations/008-triggers-table.d.ts +7 -0
  306. package/dist/runstore/sqlite/migrations/008-triggers-table.js +19 -0
  307. package/dist/runstore/sqlite/migrations/009-trigger-next-run.d.ts +7 -0
  308. package/dist/runstore/sqlite/migrations/009-trigger-next-run.js +19 -0
  309. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.d.ts +7 -0
  310. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.js +17 -0
  311. package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
  312. package/dist/runstore/sqlite/migrations/index.js +78 -0
  313. package/dist/runstore/sqlite/schema.d.ts +20 -1
  314. package/dist/runstore/sqlite/schema.js +277 -1
  315. package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
  316. package/dist/runstore/sqlite/storeOpenError.js +11 -0
  317. package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
  318. package/dist/runstore/sqlite/storeSchemaError.js +8 -0
  319. package/dist/runstore/stageExecution.js +3 -0
  320. package/dist/runstore/storeFilesystem.d.ts +32 -0
  321. package/dist/runstore/storeFilesystem.js +148 -0
  322. package/dist/runstore/trackProjection.js +2 -0
  323. package/dist/runstore/workspaceLayout.d.ts +13 -0
  324. package/dist/runstore/workspaceLayout.js +76 -0
  325. package/dist/runtime/answerResume.d.ts +1 -0
  326. package/dist/runtime/answerResume.js +3 -1
  327. package/dist/runtime/completionCheckRunner.d.ts +15 -1
  328. package/dist/runtime/completionCheckRunner.js +67 -7
  329. package/dist/runtime/containerLimits.d.ts +16 -0
  330. package/dist/runtime/containerLimits.js +84 -0
  331. package/dist/runtime/credentialBinding.d.ts +2 -0
  332. package/dist/runtime/credentialBinding.js +3 -0
  333. package/dist/runtime/credentialMaterialisation.d.ts +28 -0
  334. package/dist/runtime/credentialMaterialisation.js +128 -0
  335. package/dist/runtime/emailSource.d.ts +72 -0
  336. package/dist/runtime/emailSource.js +304 -0
  337. package/dist/runtime/gitCheckoutCapability.js +7 -13
  338. package/dist/runtime/githubPollSource.d.ts +86 -0
  339. package/dist/runtime/githubPollSource.js +284 -0
  340. package/dist/runtime/pipelineRunner.d.ts +40 -1
  341. package/dist/runtime/pipelineRunner.js +181 -17
  342. package/dist/runtime/pipelineScheduler.d.ts +17 -0
  343. package/dist/runtime/pipelineScheduler.js +220 -28
  344. package/dist/runtime/reloadRunCatalog.js +6 -1
  345. package/dist/runtime/repositoryMaterialize.d.ts +47 -0
  346. package/dist/runtime/repositoryMaterialize.js +235 -0
  347. package/dist/runtime/resumeTimedOut.d.ts +1 -1
  348. package/dist/runtime/resumeTimedOut.js +5 -2
  349. package/dist/runtime/runChangeBus.js +9 -0
  350. package/dist/runtime/runDeletion.d.ts +7 -0
  351. package/dist/runtime/runDeletion.js +37 -0
  352. package/dist/runtime/runManager.d.ts +169 -4
  353. package/dist/runtime/runManager.js +1748 -83
  354. package/dist/runtime/runRetentionSweep.d.ts +31 -0
  355. package/dist/runtime/runRetentionSweep.js +328 -0
  356. package/dist/runtime/runRetryCoordinator.d.ts +4 -0
  357. package/dist/runtime/runRetryCoordinator.js +20 -2
  358. package/dist/runtime/runSkills.d.ts +40 -0
  359. package/dist/runtime/runSkills.js +173 -0
  360. package/dist/runtime/scheduleSource.d.ts +38 -0
  361. package/dist/runtime/scheduleSource.js +119 -0
  362. package/dist/runtime/settingsFile.d.ts +5 -0
  363. package/dist/runtime/settingsFile.js +61 -54
  364. package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
  365. package/dist/runtime/stageAttemptBootstrap.js +250 -27
  366. package/dist/runtime/stageCacheEnv.d.ts +6 -0
  367. package/dist/runtime/stageCacheEnv.js +34 -0
  368. package/dist/runtime/stageConcurrency.d.ts +2 -1
  369. package/dist/runtime/stageConcurrency.js +4 -2
  370. package/dist/runtime/stageEnvironment.d.ts +38 -0
  371. package/dist/runtime/stageEnvironment.js +194 -0
  372. package/dist/runtime/stageHitl.d.ts +1 -0
  373. package/dist/runtime/stageHitl.js +5 -1
  374. package/dist/runtime/stageProcessLauncher.d.ts +20 -0
  375. package/dist/runtime/stageProcessLauncher.js +236 -41
  376. package/dist/runtime/stageRecovery.d.ts +3 -1
  377. package/dist/runtime/stageRecovery.js +19 -4
  378. package/dist/runtime/stageRoots.d.ts +38 -1
  379. package/dist/runtime/stageRoots.js +118 -0
  380. package/dist/runtime/stageRunner.d.ts +6 -0
  381. package/dist/runtime/stageRunner.js +32 -6
  382. package/dist/runtime/stageSecretDecl.d.ts +9 -0
  383. package/dist/runtime/stageSecretDecl.js +102 -0
  384. package/dist/runtime/stageSecrets.d.ts +40 -0
  385. package/dist/runtime/stageSecrets.js +181 -0
  386. package/dist/runtime/stageStreamLog.d.ts +1 -0
  387. package/dist/runtime/stageStreamLog.js +2 -1
  388. package/dist/runtime/stageWorker.d.ts +3 -2
  389. package/dist/runtime/stageWorker.js +58 -10
  390. package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
  391. package/dist/runtime/stageWorkerProtocol.js +8 -0
  392. package/dist/runtime/startPayload.d.ts +32 -0
  393. package/dist/runtime/startPayload.js +59 -0
  394. package/dist/runtime/taskInput.js +14 -5
  395. package/dist/runtime/triggerCatalog.d.ts +6 -0
  396. package/dist/runtime/triggerCatalog.js +24 -0
  397. package/dist/runtime/triggerEventMatch.d.ts +2 -0
  398. package/dist/runtime/triggerEventMatch.js +6 -0
  399. package/dist/runtime/triggerPort.d.ts +14 -0
  400. package/dist/runtime/triggerPort.js +1 -0
  401. package/dist/runtime/triggerRunner.d.ts +17 -0
  402. package/dist/runtime/triggerRunner.js +89 -0
  403. package/dist/runtime/verifiedStageExecution.d.ts +8 -0
  404. package/dist/runtime/verifiedStageExecution.js +16 -1
  405. package/dist/runtime/webhookSignature.d.ts +1 -0
  406. package/dist/runtime/webhookSignature.js +12 -0
  407. package/dist/runtime/workspaceBinding.d.ts +20 -0
  408. package/dist/runtime/workspaceBinding.js +60 -0
  409. package/dist/server/allowedHosts.d.ts +19 -0
  410. package/dist/server/allowedHosts.js +179 -0
  411. package/dist/server/bootstrap.d.ts +42 -2
  412. package/dist/server/bootstrap.js +273 -5
  413. package/dist/server/controlToken.d.ts +47 -0
  414. package/dist/server/controlToken.js +254 -0
  415. package/dist/server/createHttpHost.d.ts +11 -2
  416. package/dist/server/createHttpHost.js +106 -10
  417. package/dist/server/ensureGlobalService.d.ts +5 -1
  418. package/dist/server/ensureGlobalService.js +35 -1
  419. package/dist/server/healthSurfaces.d.ts +6 -0
  420. package/dist/server/healthSurfaces.js +123 -0
  421. package/dist/server/http.d.ts +27 -1
  422. package/dist/server/http.js +2254 -477
  423. package/dist/server/listenHost.d.ts +5 -0
  424. package/dist/server/listenHost.js +56 -0
  425. package/dist/server/mcpHost.d.ts +10 -1
  426. package/dist/server/mcpHost.js +36 -6
  427. package/dist/server/operatorResults.d.ts +2 -2
  428. package/dist/server/operatorResults.js +40 -29
  429. package/dist/server/requestAuthContext.d.ts +12 -0
  430. package/dist/server/requestAuthContext.js +21 -0
  431. package/dist/server/shutdown.d.ts +69 -0
  432. package/dist/server/shutdown.js +219 -0
  433. package/dist/server/triggerRoutes.d.ts +15 -0
  434. package/dist/server/triggerRoutes.js +268 -0
  435. package/dist/tools/askOperator.d.ts +3 -2
  436. package/dist/types/completion.d.ts +3 -0
  437. package/dist/types/pipeline.d.ts +10 -1
  438. package/dist/types/preEmitCheck.d.ts +7 -0
  439. package/dist/types/stage.d.ts +22 -0
  440. package/dist/types/stageflowManifest.d.ts +3 -0
  441. package/dist/types/task.d.ts +8 -0
  442. package/dist/types/trigger.d.ts +18 -0
  443. package/dist/types/trigger.js +1 -0
  444. package/dist/ui/assets/{index-CSsDued1.css → index-Bv4p1aPK.css} +1 -1
  445. package/dist/ui/assets/index-CntB4bZR.js +133 -0
  446. package/dist/ui/index.html +2 -2
  447. package/dist/workshop/autosave.d.ts +58 -0
  448. package/dist/workshop/autosave.js +222 -0
  449. package/dist/workshop/buildStore.d.ts +79 -0
  450. package/dist/workshop/buildStore.js +326 -0
  451. package/dist/workshop/chatTurn.d.ts +232 -0
  452. package/dist/workshop/chatTurn.js +475 -0
  453. package/dist/workshop/modelSettings.d.ts +18 -0
  454. package/dist/workshop/modelSettings.js +44 -0
  455. package/dist/workshop/sessionStore.d.ts +61 -0
  456. package/dist/workshop/sessionStore.js +254 -0
  457. package/dist/workshop/workshopPin.d.ts +72 -0
  458. package/dist/workshop/workshopPin.js +193 -0
  459. package/examples/README.md +99 -0
  460. package/examples/archify-on-pr/README.md +213 -0
  461. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
  462. package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
  463. package/examples/archify-on-pr/author-diagrams.yaml +106 -0
  464. package/examples/archify-on-pr/detect-changes.yaml +89 -0
  465. package/examples/browser-session/README.md +77 -0
  466. package/examples/browser-session/browser-session.pipeline.yaml +50 -0
  467. package/examples/browser-session/browser-session.task.yaml +6 -0
  468. package/examples/browser-session/check-login.yaml +22 -0
  469. package/examples/browser-session/fixture-server.mjs +64 -0
  470. package/examples/browser-session/human-login.yaml +31 -0
  471. package/examples/browser-session/merge.yaml +36 -0
  472. package/examples/browser-session/work-a.yaml +41 -0
  473. package/examples/browser-session/work-b.yaml +41 -0
  474. package/examples/ci-validate/README.md +35 -0
  475. package/examples/ci-validate/check.yaml +13 -0
  476. package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
  477. package/examples/ci-validate/validate.sh +5 -0
  478. package/examples/compliance-review-demo/README.md +125 -0
  479. package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
  480. package/examples/compliance-review-demo/connect-account.yaml +47 -0
  481. package/examples/compliance-review-demo/map-to-control.yaml +123 -0
  482. package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
  483. package/examples/compliance-review-demo/publish-report.yaml +79 -0
  484. package/examples/compliance-review-demo/review-verdict.yaml +122 -0
  485. package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
  486. package/examples/compliance-review-demo/store-evidence.yaml +143 -0
  487. package/examples/conditional-fork/README.md +89 -0
  488. package/examples/conditional-fork/branch-a.yaml +13 -0
  489. package/examples/conditional-fork/branch-b.yaml +13 -0
  490. package/examples/conditional-fork/decide.yaml +35 -0
  491. package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
  492. package/examples/conditional-fork/fork-demo.task.yaml +8 -0
  493. package/examples/context7-mcp/README.md +42 -0
  494. package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
  495. package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
  496. package/examples/context7-mcp/fetch-docs.yaml +52 -0
  497. package/examples/context7-mcp/resolve-library.yaml +31 -0
  498. package/examples/context7-mcp/write-brief.yaml +52 -0
  499. package/examples/feature-loop/README.md +104 -0
  500. package/examples/feature-loop/address-feedback.yaml +148 -0
  501. package/examples/feature-loop/align.yaml +116 -0
  502. package/examples/feature-loop/decompose.yaml +86 -0
  503. package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
  504. package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
  505. package/examples/feature-loop/feature-loop.task.yaml +25 -0
  506. package/examples/feature-loop/implement.yaml +128 -0
  507. package/examples/feature-loop/plan.yaml +111 -0
  508. package/examples/feature-loop/publish.yaml +167 -0
  509. package/examples/feature-loop/review.yaml +146 -0
  510. package/examples/feature-loop/verify.yaml +106 -0
  511. package/examples/feedback-loop/README.md +72 -0
  512. package/examples/feedback-loop/VERIFY.md +208 -0
  513. package/examples/feedback-loop/continue-only.task.yaml +4 -0
  514. package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
  515. package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
  516. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
  517. package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
  518. package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
  519. package/examples/feedback-loop/implement.yaml +14 -0
  520. package/examples/feedback-loop/plan.yaml +14 -0
  521. package/examples/feedback-loop/review.yaml +15 -0
  522. package/examples/feedback-loop/send-back-once.task.yaml +6 -0
  523. package/examples/feedback-loop/submit.yaml +12 -0
  524. package/examples/generic-fan-in/README.md +151 -0
  525. package/examples/generic-fan-in/clarify.yaml +18 -0
  526. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
  527. package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
  528. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
  529. package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
  530. package/examples/generic-fan-in/research.yaml +45 -0
  531. package/examples/generic-fan-in/synthesize.yaml +66 -0
  532. package/examples/generic-fan-in/validation.yaml +45 -0
  533. package/examples/github-release/README.md +78 -0
  534. package/examples/github-release/draft-release-notes.yaml +64 -0
  535. package/examples/github-release/github-release.pipeline.yaml +11 -0
  536. package/examples/github-release/github-release.task.yaml +13 -0
  537. package/examples/github-release/publish-github-release.yaml +64 -0
  538. package/examples/hello-world/README.md +28 -0
  539. package/examples/hello-world/hello.pipeline.yaml +4 -0
  540. package/examples/hello-world/my-task.task.yaml +6 -0
  541. package/examples/hello-world/research.yaml +18 -0
  542. package/examples/mcp-hitl-tour/README.md +113 -0
  543. package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
  544. package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
  545. package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
  546. package/examples/mcp-hitl-tour/gather.yaml +31 -0
  547. package/examples/mcp-hitl-tour/intake.yaml +62 -0
  548. package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
  549. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
  550. package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
  551. package/examples/mcp-hitl-tour/polish.yaml +33 -0
  552. package/examples/mcp-hitl-tour/review.yaml +17 -0
  553. package/examples/mcp-hitl-tour/ship.yaml +25 -0
  554. package/examples/oss-issue-contribution/README.md +218 -0
  555. package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
  556. package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
  557. package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
  558. package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
  559. package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
  560. package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
  561. package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
  562. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
  563. package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
  564. package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
  565. package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
  566. package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
  567. package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
  568. package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
  569. package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
  570. package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
  571. package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
  572. package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
  573. package/examples/oss-quick-fix/README.md +65 -0
  574. package/examples/oss-quick-fix/implement-fix.yaml +84 -0
  575. package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
  576. package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
  577. package/examples/oss-quick-fix/ship-fix.yaml +81 -0
  578. package/examples/oss-quick-fix/understand-issue.yaml +67 -0
  579. package/examples/oss-quick-fix/verify-fix.yaml +73 -0
  580. package/examples/plan-review/README.md +37 -0
  581. package/examples/plan-review/plan-review-followup.yaml +13 -0
  582. package/examples/plan-review/plan-review.pipeline.yaml +9 -0
  583. package/examples/plan-review/plan-review.task.yaml +9 -0
  584. package/examples/plan-review/plan-review.yaml +25 -0
  585. package/examples/playwright-mcp/README.md +39 -0
  586. package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
  587. package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
  588. package/examples/playwright-mcp/screenshot.yaml +40 -0
  589. package/examples/retry-tour/README.md +75 -0
  590. package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
  591. package/examples/retry-tour/retry-tour.task.yaml +9 -0
  592. package/examples/route-if-tour/README.md +202 -0
  593. package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
  594. package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
  595. package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
  596. package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
  597. package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
  598. package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
  599. package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
  600. package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
  601. package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
  602. package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
  603. package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
  604. package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
  605. package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
  606. package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
  607. package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
  608. package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
  609. package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
  610. package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
  611. package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
  612. package/examples/route-wiring-smoke-test/README.md +377 -0
  613. package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
  614. package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
  615. package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
  616. package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
  617. package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
  618. package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
  619. package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
  620. package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
  621. package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
  622. package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
  623. package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
  624. package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
  625. package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
  626. package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
  627. package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
  628. package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
  629. package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
  630. package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
  631. package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
  632. package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
  633. package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
  634. package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
  635. package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
  636. package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
  637. package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
  638. package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
  639. package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
  640. package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
  641. package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
  642. package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
  643. package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
  644. package/examples/ship-feature/README.md +190 -0
  645. package/examples/ship-feature/feat-address-feedback.yaml +119 -0
  646. package/examples/ship-feature/feat-implement.yaml +180 -0
  647. package/examples/ship-feature/feat-plan.yaml +120 -0
  648. package/examples/ship-feature/feat-review.yaml +109 -0
  649. package/examples/ship-feature/feat-ship.yaml +203 -0
  650. package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
  651. package/examples/ship-feature/ship-feature.task.yaml +78 -0
  652. package/examples/stage-mcp/README.md +145 -0
  653. package/examples/stage-mcp/echo-mcp.mjs +20 -0
  654. package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
  655. package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
  656. package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
  657. package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
  658. package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
  659. package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
  660. package/examples/stage-mcp/use-echo.yaml +20 -0
  661. package/examples/stageflow.yaml +51 -0
  662. package/examples/verify-tour/README.md +80 -0
  663. package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
  664. package/examples/verify-tour/verify-tour.task.yaml +11 -0
  665. package/package.json +9 -1
  666. package/skills/stageflow/SKILL.md +6 -6
  667. package/skills/stageflow/references/control-surface.md +13 -5
  668. package/skills/stageflow/scripts/detect-host.mjs +14 -1
  669. package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
  670. package/skills/stageflow-author/SKILL.md +4 -3
  671. package/skills/stageflow-author/references/catalog-mapping.md +16 -0
  672. package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
  673. package/skills/stageflow-author/references/stage-prompt-template.md +4 -4
  674. package/skills/stageflow-run/SKILL.md +22 -12
  675. package/skills/stageflow-run/references/mcp-call.md +9 -1
  676. package/skills/stageflow-run/references/task-and-pipeline-selection.md +19 -6
  677. package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
  678. package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
  679. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
  680. package/skills/stageflow-setup/SKILL.md +51 -8
  681. package/dist/ui/assets/index-Da5EHU6M.js +0 -119
@@ -1,196 +1,20 @@
1
1
  import Database from "better-sqlite3";
2
+ import { existsSync, statSync } from "node:fs";
2
3
  import { mkdir } from "node:fs/promises";
3
4
  import path from "node:path";
4
5
  import { projectRunDetail, projectRunSummary, orderStageSnapshots } from "../runProjection.js";
5
- import { normalizeCatalogPath } from "../normalizeCatalogPath.js";
6
+ import { normalizeCatalogPath, normalizeProjectRoot } from "../normalizeCatalogPath.js";
6
7
  import { buildStageSnapshotFromStore } from "../stageSnapshot.js";
7
8
  import { parsePipelineDagSnapshot } from "../pipelineDagSnapshot.js";
8
9
  import { newRunId, runWorkspaceDir } from "../paths.js";
9
10
  import { attemptAgentDir, attemptArtifactsDir, stageDir, } from "../workspaceLayout.js";
10
11
  import { importDiskRunsIfEmpty } from "./migrateFromDisk.js";
11
- import { SCHEMA_SQL } from "./schema.js";
12
+ import { applyPendingMigrations, assertSchemaVersion, } from "./migrations/index.js";
13
+ import { StoreSchemaError } from "./storeSchemaError.js";
14
+ import { applyStorePragmas } from "./applyStorePragmas.js";
12
15
  import { RunSubmissionExistsError } from "../submission.js";
16
+ const EXECUTION_SELECT_COLS = `run_id, stage_id, attempt, status, verification_outcome, started_at, finished_at, envelope_json, cost_usd, usage_json, auto_resume_count`;
13
17
  const ensuredStageDirs = new Set();
14
- const DEFAULT_SQLITE_BUSY_TIMEOUT_MS = 5000;
15
- function readSqliteBusyTimeoutMs() {
16
- const raw = process.env.STAGEFLOW_SQLITE_BUSY_TIMEOUT_MS;
17
- if (raw === undefined || raw.trim() === "") {
18
- return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;
19
- }
20
- const parsed = Number.parseInt(raw, 10);
21
- if (!Number.isFinite(parsed) || parsed < 0) {
22
- return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;
23
- }
24
- return parsed;
25
- }
26
- function ensureCheckoutRootColumn(db) {
27
- const cols = db.prepare(`PRAGMA table_info(runs)`).all();
28
- if (!cols.some((c) => c.name === "checkout_root")) {
29
- db.exec(`ALTER TABLE runs ADD COLUMN checkout_root TEXT`);
30
- }
31
- }
32
- function ensureCiIdentityColumns(db) {
33
- const cols = db.prepare(`PRAGMA table_info(runs)`).all();
34
- const names = new Set(cols.map((c) => c.name));
35
- for (const name of ["git_sha", "ci_pr_url", "ci_job_url"]) {
36
- if (!names.has(name)) {
37
- db.exec(`ALTER TABLE runs ADD COLUMN ${name} TEXT`);
38
- }
39
- }
40
- }
41
- function ensurePipelineDagColumn(db) {
42
- const cols = db.prepare(`PRAGMA table_info(runs)`).all();
43
- if (!cols.some((c) => c.name === "pipeline_dag_json")) {
44
- db.exec(`ALTER TABLE runs ADD COLUMN pipeline_dag_json TEXT`);
45
- }
46
- }
47
- function ensureRunLocatorColumns(db) {
48
- const cols = db.prepare(`PRAGMA table_info(runs)`).all();
49
- const names = new Set(cols.map((c) => c.name));
50
- for (const name of ["pipeline_path", "task_path", "project_root"]) {
51
- if (!names.has(name)) {
52
- db.exec(`ALTER TABLE runs ADD COLUMN ${name} TEXT`);
53
- }
54
- }
55
- }
56
- function ensureInlinePipelineColumn(db) {
57
- const cols = db.prepare(`PRAGMA table_info(runs)`).all();
58
- if (!cols.some((c) => c.name === "inline_pipeline_json")) {
59
- db.exec(`ALTER TABLE runs ADD COLUMN inline_pipeline_json TEXT`);
60
- }
61
- }
62
- function ensureStageExecutionsTable(db) {
63
- db.exec(`
64
- CREATE TABLE IF NOT EXISTS stage_executions (
65
- run_id TEXT NOT NULL,
66
- stage_id TEXT NOT NULL,
67
- attempt INTEGER NOT NULL,
68
- status TEXT NOT NULL,
69
- verification_outcome TEXT NOT NULL DEFAULT 'not_run',
70
- started_at TEXT,
71
- finished_at TEXT,
72
- envelope_json TEXT,
73
- PRIMARY KEY (run_id, stage_id, attempt),
74
- FOREIGN KEY (run_id) REFERENCES runs(run_id)
75
- );
76
- CREATE INDEX IF NOT EXISTS idx_stage_executions_run_stage
77
- ON stage_executions (run_id, stage_id, attempt);
78
- `);
79
- }
80
- function ensureStageExecutionVerificationOutcomeColumn(db) {
81
- const cols = db
82
- .prepare(`PRAGMA table_info(stage_executions)`)
83
- .all();
84
- if (!cols.some((c) => c.name === "verification_outcome")) {
85
- db.exec(`ALTER TABLE stage_executions ADD COLUMN verification_outcome TEXT NOT NULL DEFAULT 'not_run'`);
86
- }
87
- }
88
- function ensureStageExecutionCostColumns(db) {
89
- const cols = db
90
- .prepare(`PRAGMA table_info(stage_executions)`)
91
- .all();
92
- const names = new Set(cols.map((c) => c.name));
93
- if (!names.has("cost_usd")) {
94
- db.exec(`ALTER TABLE stage_executions ADD COLUMN cost_usd REAL`);
95
- }
96
- if (!names.has("usage_json")) {
97
- db.exec(`ALTER TABLE stage_executions ADD COLUMN usage_json TEXT`);
98
- }
99
- }
100
- function backfillVerificationOutcomes(db) {
101
- db.exec(`
102
- UPDATE stage_executions
103
- SET verification_outcome = CASE
104
- WHEN status = 'succeeded'
105
- AND EXISTS (
106
- SELECT 1 FROM verification_check_results AS check_result
107
- WHERE check_result.run_id = stage_executions.run_id
108
- AND check_result.stage_id = stage_executions.stage_id
109
- AND check_result.attempt = stage_executions.attempt
110
- )
111
- AND NOT EXISTS (
112
- SELECT 1 FROM verification_check_results AS check_result
113
- WHERE check_result.run_id = stage_executions.run_id
114
- AND check_result.stage_id = stage_executions.stage_id
115
- AND check_result.attempt = stage_executions.attempt
116
- AND check_result.status != 'passed'
117
- )
118
- THEN 'passed'
119
- WHEN status = 'failed'
120
- AND EXISTS (
121
- SELECT 1 FROM verification_check_results AS check_result
122
- WHERE check_result.run_id = stage_executions.run_id
123
- AND check_result.stage_id = stage_executions.stage_id
124
- AND check_result.attempt = stage_executions.attempt
125
- )
126
- THEN 'failed'
127
- ELSE verification_outcome
128
- END
129
- WHERE verification_outcome = 'not_run';
130
- `);
131
- }
132
- function ensureStageEventsAttemptColumn(db) {
133
- const cols = db
134
- .prepare(`PRAGMA table_info(stage_events)`)
135
- .all();
136
- if (!cols.some((c) => c.name === "attempt")) {
137
- db.exec(`ALTER TABLE stage_events ADD COLUMN attempt INTEGER NOT NULL DEFAULT 1`);
138
- db.exec(`
139
- CREATE INDEX IF NOT EXISTS idx_stage_events_run_stage_attempt_at
140
- ON stage_events (run_id, stage_id, attempt, at);
141
- `);
142
- }
143
- }
144
- function ensureVerificationCheckResultsTable(db) {
145
- db.exec(`
146
- CREATE TABLE IF NOT EXISTS verification_check_results (
147
- run_id TEXT NOT NULL,
148
- stage_id TEXT NOT NULL,
149
- attempt INTEGER NOT NULL,
150
- check_id TEXT NOT NULL,
151
- check_type TEXT NOT NULL,
152
- status TEXT NOT NULL,
153
- started_at TEXT,
154
- finished_at TEXT,
155
- evidence_json TEXT,
156
- PRIMARY KEY (run_id, stage_id, attempt, check_id),
157
- FOREIGN KEY (run_id, stage_id, attempt)
158
- REFERENCES stage_executions(run_id, stage_id, attempt)
159
- );
160
- CREATE INDEX IF NOT EXISTS idx_verification_check_results_execution
161
- ON verification_check_results (run_id, stage_id, attempt, check_id);
162
- `);
163
- }
164
- function ensureFeedbackReplayStagePassEnvelopeColumn(db) {
165
- const cols = db
166
- .prepare(`PRAGMA table_info(feedback_replay_stage_passes)`)
167
- .all();
168
- if (cols.length === 0)
169
- return;
170
- if (!cols.some((c) => c.name === "emitted_envelope_json")) {
171
- db.exec(`ALTER TABLE feedback_replay_stage_passes ADD COLUMN emitted_envelope_json TEXT`);
172
- }
173
- }
174
- function ensureFeedbackReplayStagePassSessionOriginColumn(db) {
175
- const cols = db
176
- .prepare(`PRAGMA table_info(feedback_replay_stage_passes)`)
177
- .all();
178
- if (cols.length === 0)
179
- return;
180
- if (!cols.some((c) => c.name === "session_origin_attempt")) {
181
- db.exec(`ALTER TABLE feedback_replay_stage_passes ADD COLUMN session_origin_attempt INTEGER`);
182
- }
183
- }
184
- function ensureFeedbackLoopDeferredSendBackColumn(db) {
185
- const cols = db
186
- .prepare(`PRAGMA table_info(feedback_loops)`)
187
- .all();
188
- if (cols.length === 0)
189
- return;
190
- if (!cols.some((c) => c.name === "deferred_send_back_json")) {
191
- db.exec(`ALTER TABLE feedback_loops ADD COLUMN deferred_send_back_json TEXT`);
192
- }
193
- }
194
18
  function executionFromRow(row) {
195
19
  return {
196
20
  run_id: row.run_id,
@@ -204,7 +28,10 @@ function executionFromRow(row) {
204
28
  ? JSON.parse(row.envelope_json)
205
29
  : null,
206
30
  ...(row.cost_usd != null ? { cost_usd: row.cost_usd } : {}),
207
- ...(row.usage_json != null ? { usage: JSON.parse(row.usage_json) } : {}),
31
+ ...(row.usage_json != null
32
+ ? { usage: JSON.parse(row.usage_json) }
33
+ : {}),
34
+ auto_resume_count: row.auto_resume_count ?? 0,
208
35
  };
209
36
  }
210
37
  function verificationCheckResultFromRow(row) {
@@ -245,6 +72,18 @@ function feedbackLoopFromRow(row) {
245
72
  updated_at: row.updated_at,
246
73
  };
247
74
  }
75
+ function triggerFromRow(row) {
76
+ return {
77
+ id: row.id,
78
+ definition_ref: row.definition_ref,
79
+ enabled: row.enabled !== 0,
80
+ ...(row.last_fired_at != null ? { last_fired_at: row.last_fired_at } : {}),
81
+ ...(row.last_run_id != null ? { last_run_id: row.last_run_id } : {}),
82
+ ...(row.next_run_at != null ? { next_run_at: row.next_run_at } : {}),
83
+ created_at: row.created_at,
84
+ updated_at: row.updated_at,
85
+ };
86
+ }
248
87
  function feedbackReplayFromRow(row) {
249
88
  return {
250
89
  run_id: row.run_id,
@@ -300,33 +139,44 @@ export class SqliteRunStore {
300
139
  storeRoot;
301
140
  db;
302
141
  migratePromise;
303
- constructor(storeRoot) {
142
+ constructor(storeRoot, options) {
304
143
  this.storeRoot = storeRoot;
144
+ const openerMode = options?.openerMode ??
145
+ (process.env.VITEST === "true" ? "migrate" : "assert");
305
146
  const dbPath = path.join(storeRoot, "state.db");
147
+ if (openerMode === "assert") {
148
+ if (!existsSync(dbPath)) {
149
+ throw new StoreSchemaError("store_schema_migration_required: database file is missing", "store_schema_migration_required");
150
+ }
151
+ this.db = new Database(dbPath);
152
+ applyStorePragmas(this.db);
153
+ assertSchemaVersion(this.db);
154
+ this.migratePromise = Promise.resolve();
155
+ return;
156
+ }
306
157
  this.db = new Database(dbPath);
307
- this.db.pragma("journal_mode = WAL");
308
- this.db.pragma(`busy_timeout = ${readSqliteBusyTimeoutMs()}`);
309
- this.db.exec(SCHEMA_SQL);
310
- ensureCheckoutRootColumn(this.db);
311
- ensureCiIdentityColumns(this.db);
312
- ensurePipelineDagColumn(this.db);
313
- ensureRunLocatorColumns(this.db);
314
- ensureInlinePipelineColumn(this.db);
315
- ensureStageExecutionsTable(this.db);
316
- ensureStageExecutionVerificationOutcomeColumn(this.db);
317
- ensureStageExecutionCostColumns(this.db);
318
- ensureStageEventsAttemptColumn(this.db);
319
- ensureVerificationCheckResultsTable(this.db);
320
- ensureFeedbackReplayStagePassEnvelopeColumn(this.db);
321
- ensureFeedbackReplayStagePassSessionOriginColumn(this.db);
322
- ensureFeedbackLoopDeferredSendBackColumn(this.db);
323
- backfillVerificationOutcomes(this.db);
158
+ applyStorePragmas(this.db);
159
+ applyPendingMigrations(this.db);
324
160
  this.migratePromise = importDiskRunsIfEmpty(this.db, storeRoot).then(() => undefined);
325
161
  }
326
162
  /** Await one-shot disk import before catalog reads (create paths also wait). */
327
163
  async ready() {
328
164
  await this.migratePromise;
329
165
  }
166
+ async close() {
167
+ await this.ready();
168
+ this.db.pragma("wal_checkpoint(TRUNCATE)");
169
+ this.db.close();
170
+ }
171
+ async snapshotInto(destPath) {
172
+ await this.ready();
173
+ const userVersion = this.db.pragma("user_version", {
174
+ simple: true,
175
+ });
176
+ const escaped = destPath.replace(/'/g, "''");
177
+ this.db.exec(`VACUUM INTO '${escaped}'`);
178
+ return { userVersion };
179
+ }
330
180
  /**
331
181
  * The connection this store owns, for the one caller allowed to share it: the composition root
332
182
  * wiring the A2A tables into the same `state.db` file. Not part of the `RunStore` interface.
@@ -339,7 +189,7 @@ export class SqliteRunStore {
339
189
  }
340
190
  async createRun(input) {
341
191
  await this.ready();
342
- const runId = newRunId();
192
+ const runId = input.runId ?? newRunId();
343
193
  const workspaceDir = this.getWorkspaceDir(runId);
344
194
  await mkdir(path.join(workspaceDir, "stages"), { recursive: true });
345
195
  const now = new Date().toISOString();
@@ -352,6 +202,12 @@ export class SqliteRunStore {
352
202
  const projectRoot = input.projectRoot
353
203
  ? normalizeCatalogPath(input.projectRoot)
354
204
  : null;
205
+ const pipelineBody = input.pipelineBody ??
206
+ (input.inlinePipeline !== undefined
207
+ ? JSON.stringify(input.inlinePipeline)
208
+ : null);
209
+ const pipelineSource = input.pipelineSource ??
210
+ (pipelineBody != null && pipelinePath == null ? "inline" : null);
355
211
  this.db.transaction(() => {
356
212
  if (input.submission) {
357
213
  const existing = this.readSubmission(input.submission.key);
@@ -360,15 +216,15 @@ export class SqliteRunStore {
360
216
  }
361
217
  this.db
362
218
  .prepare(`INSERT INTO runs
363
- (run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, inline_pipeline_json)
219
+ (run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, repository, ref, resolved_sha, run_branch, git_author_name, git_author_email, pipeline_source, pipeline_body, caller_id, run_manifest, skip_gates)
364
220
  VALUES
365
- (@run_id, @pipeline_id, @task_id, @task_yaml, @status, @created_at, @updated_at, @checkout_root, @pipeline_dag_json, @git_sha, @ci_pr_url, @ci_job_url, @pipeline_path, @task_path, @project_root, @inline_pipeline_json)`)
221
+ (@run_id, @pipeline_id, @task_id, @task_yaml, @status, @created_at, @updated_at, @checkout_root, @pipeline_dag_json, @git_sha, @ci_pr_url, @ci_job_url, @pipeline_path, @task_path, @project_root, @repository, @ref, @resolved_sha, @run_branch, @git_author_name, @git_author_email, @pipeline_source, @pipeline_body, @caller_id, @run_manifest, @skip_gates)`)
366
222
  .run({
367
223
  run_id: runId,
368
224
  pipeline_id: input.pipelineId,
369
225
  task_id: input.taskId ?? null,
370
226
  task_yaml: input.taskYaml,
371
- status: "running",
227
+ status: input.status ?? "running",
372
228
  created_at: now,
373
229
  updated_at: now,
374
230
  checkout_root: input.checkoutRoot ?? null,
@@ -381,9 +237,19 @@ export class SqliteRunStore {
381
237
  pipeline_path: pipelinePath,
382
238
  task_path: taskPath,
383
239
  project_root: projectRoot,
384
- inline_pipeline_json: input.inlinePipeline
385
- ? JSON.stringify(input.inlinePipeline)
240
+ repository: input.repository ?? null,
241
+ ref: input.ref ?? null,
242
+ resolved_sha: input.resolvedSha ?? null,
243
+ run_branch: input.runBranch ?? null,
244
+ git_author_name: input.gitAuthorName ?? null,
245
+ git_author_email: input.gitAuthorEmail ?? null,
246
+ pipeline_source: pipelineSource,
247
+ pipeline_body: pipelineBody,
248
+ caller_id: input.callerId ?? null,
249
+ run_manifest: input.runManifest !== undefined
250
+ ? JSON.stringify(input.runManifest)
386
251
  : null,
252
+ skip_gates: input.skipGates === undefined ? null : input.skipGates ? 1 : 0,
387
253
  });
388
254
  if (input.submission) {
389
255
  this.db.prepare("INSERT INTO run_submissions (submission_key, request_hash, run_id) VALUES (?, ?, ?)")
@@ -403,17 +269,198 @@ export class SqliteRunStore {
403
269
  }
404
270
  async updateRunStatus(runId, status) {
405
271
  await this.ready();
272
+ const now = new Date().toISOString();
273
+ const isTerminal = status === "succeeded" || status === "failed" || status === "cancelled";
274
+ const result = isTerminal
275
+ ? this.db
276
+ .prepare(`UPDATE runs SET status = @status, updated_at = @updated_at,
277
+ finished_at = COALESCE(finished_at, @finished_at)
278
+ WHERE run_id = @run_id`)
279
+ .run({
280
+ run_id: runId,
281
+ status,
282
+ updated_at: now,
283
+ finished_at: now,
284
+ })
285
+ : this.db
286
+ .prepare(`UPDATE runs SET status = @status, updated_at = @updated_at WHERE run_id = @run_id`)
287
+ .run({
288
+ run_id: runId,
289
+ status,
290
+ updated_at: now,
291
+ });
292
+ if (result.changes === 0) {
293
+ throw new Error(`Run not found: ${runId}`);
294
+ }
295
+ }
296
+ async tryUpdateRunStatus(runId, status, expectedStatus) {
297
+ await this.ready();
298
+ const now = new Date().toISOString();
299
+ const isTerminal = status === "succeeded" || status === "failed" || status === "cancelled";
300
+ const result = isTerminal
301
+ ? this.db
302
+ .prepare(`UPDATE runs SET status = @status, updated_at = @updated_at,
303
+ finished_at = COALESCE(finished_at, @finished_at)
304
+ WHERE run_id = @run_id AND status = @expected_status`)
305
+ .run({
306
+ run_id: runId,
307
+ status,
308
+ expected_status: expectedStatus,
309
+ updated_at: now,
310
+ finished_at: now,
311
+ })
312
+ : this.db
313
+ .prepare(`UPDATE runs SET status = @status, updated_at = @updated_at
314
+ WHERE run_id = @run_id AND status = @expected_status`)
315
+ .run({
316
+ run_id: runId,
317
+ status,
318
+ expected_status: expectedStatus,
319
+ updated_at: now,
320
+ });
321
+ if (result.changes > 0)
322
+ return true;
323
+ const exists = this.db
324
+ .prepare(`SELECT 1 AS ok FROM runs WHERE run_id = ?`)
325
+ .get(runId);
326
+ if (exists === undefined) {
327
+ throw new Error(`Run not found: ${runId}`);
328
+ }
329
+ return false;
330
+ }
331
+ async patchRunWorkspaceBinding(runId, patch) {
332
+ await this.ready();
333
+ const sets = ["updated_at = @updated_at"];
334
+ const params = {
335
+ run_id: runId,
336
+ updated_at: new Date().toISOString(),
337
+ };
338
+ if (patch.checkoutRoot !== undefined) {
339
+ sets.push("checkout_root = @checkout_root");
340
+ params.checkout_root = patch.checkoutRoot;
341
+ }
342
+ if (patch.repository !== undefined) {
343
+ sets.push("repository = @repository");
344
+ params.repository = patch.repository;
345
+ }
346
+ if (patch.ref !== undefined) {
347
+ sets.push("ref = @ref");
348
+ params.ref = patch.ref;
349
+ }
350
+ if (patch.resolvedSha !== undefined) {
351
+ sets.push("resolved_sha = @resolved_sha");
352
+ params.resolved_sha = patch.resolvedSha;
353
+ }
354
+ if (patch.runBranch !== undefined) {
355
+ sets.push("run_branch = @run_branch");
356
+ params.run_branch = patch.runBranch;
357
+ }
358
+ if (sets.length === 1) {
359
+ return;
360
+ }
406
361
  const result = this.db
407
- .prepare(`UPDATE runs SET status = @status, updated_at = @updated_at WHERE run_id = @run_id`)
362
+ .prepare(`UPDATE runs SET ${sets.join(", ")} WHERE run_id = @run_id`)
363
+ .run(params);
364
+ if (result.changes === 0) {
365
+ throw new Error(`Run not found: ${runId}`);
366
+ }
367
+ }
368
+ async appendConfigOrigins(runId, origins) {
369
+ await this.ready();
370
+ if (origins.length === 0)
371
+ return;
372
+ const row = this.getRunRow(runId);
373
+ const existing = row.config_origins_json
374
+ ? JSON.parse(row.config_origins_json)
375
+ : [];
376
+ const keyOf = (o) => `${o.name}\0${o.origin}\0${o.path ?? ""}`;
377
+ const seen = new Set(existing.map(keyOf));
378
+ const merged = [...existing];
379
+ for (const origin of origins) {
380
+ const key = keyOf(origin);
381
+ if (seen.has(key))
382
+ continue;
383
+ seen.add(key);
384
+ merged.push(origin);
385
+ }
386
+ if (merged.length === existing.length)
387
+ return;
388
+ const result = this.db
389
+ .prepare(`UPDATE runs SET config_origins_json = @config_origins_json, updated_at = @updated_at WHERE run_id = @run_id`)
408
390
  .run({
409
391
  run_id: runId,
410
- status,
392
+ config_origins_json: JSON.stringify(merged),
393
+ updated_at: new Date().toISOString(),
394
+ });
395
+ if (result.changes === 0) {
396
+ throw new Error(`Run not found: ${runId}`);
397
+ }
398
+ }
399
+ async setCancelReason(runId, reason) {
400
+ await this.ready();
401
+ const result = this.db
402
+ .prepare(`UPDATE runs SET cancel_reason = @cancel_reason, updated_at = @updated_at WHERE run_id = @run_id`)
403
+ .run({
404
+ run_id: runId,
405
+ cancel_reason: reason,
411
406
  updated_at: new Date().toISOString(),
412
407
  });
413
408
  if (result.changes === 0) {
414
409
  throw new Error(`Run not found: ${runId}`);
415
410
  }
416
411
  }
412
+ async setRunDiskUsage(runId, diskBytes, measuredAt) {
413
+ await this.ready();
414
+ const result = this.db
415
+ .prepare(`UPDATE runs SET disk_bytes = @disk_bytes, disk_measured_at = @disk_measured_at
416
+ WHERE run_id = @run_id`)
417
+ .run({
418
+ run_id: runId,
419
+ disk_bytes: diskBytes,
420
+ disk_measured_at: measuredAt,
421
+ });
422
+ if (result.changes === 0) {
423
+ throw new Error(`Run not found: ${runId}`);
424
+ }
425
+ }
426
+ async setSlimmedAt(runId, slimmedAt) {
427
+ await this.ready();
428
+ const result = this.db
429
+ .prepare(`UPDATE runs SET slimmed_at = @slimmed_at WHERE run_id = @run_id`)
430
+ .run({
431
+ run_id: runId,
432
+ slimmed_at: slimmedAt,
433
+ });
434
+ if (result.changes === 0) {
435
+ throw new Error(`Run not found: ${runId}`);
436
+ }
437
+ }
438
+ async deleteRun(runId) {
439
+ await this.ready();
440
+ const deleteAll = this.db.transaction(() => {
441
+ const exists = this.db
442
+ .prepare(`SELECT 1 AS ok FROM runs WHERE run_id = ?`)
443
+ .get(runId);
444
+ if (exists === undefined) {
445
+ throw new Error(`Run not found: ${runId}`);
446
+ }
447
+ this.db.prepare(`DELETE FROM stage_events WHERE run_id = ?`).run(runId);
448
+ this.db
449
+ .prepare(`DELETE FROM verification_check_results WHERE run_id = ?`)
450
+ .run(runId);
451
+ this.db.prepare(`DELETE FROM stage_executions WHERE run_id = ?`).run(runId);
452
+ this.db
453
+ .prepare(`DELETE FROM feedback_replay_stage_passes WHERE run_id = ?`)
454
+ .run(runId);
455
+ this.db.prepare(`DELETE FROM fork_generations WHERE run_id = ?`).run(runId);
456
+ this.db.prepare(`DELETE FROM feedback_replays WHERE run_id = ?`).run(runId);
457
+ this.db.prepare(`DELETE FROM feedback_loops WHERE run_id = ?`).run(runId);
458
+ this.db.prepare(`DELETE FROM stages WHERE run_id = ?`).run(runId);
459
+ this.db.prepare(`DELETE FROM run_submissions WHERE run_id = ?`).run(runId);
460
+ this.db.prepare(`DELETE FROM runs WHERE run_id = ?`).run(runId);
461
+ });
462
+ deleteAll();
463
+ }
417
464
  async updatePipelineDag(runId, dag) {
418
465
  await this.ready();
419
466
  const result = this.db
@@ -435,6 +482,25 @@ export class SqliteRunStore {
435
482
  await this.ready();
436
483
  return this.getRunRow(runId).task_yaml;
437
484
  }
485
+ async readPipelineBody(runId) {
486
+ await this.ready();
487
+ return this.getRunRow(runId).pipeline_body;
488
+ }
489
+ async updateRunManifest(runId, manifest) {
490
+ await this.ready();
491
+ const result = this.db
492
+ .prepare(`UPDATE runs SET run_manifest = @run_manifest, updated_at = @updated_at WHERE run_id = @run_id`)
493
+ .run({
494
+ run_id: runId,
495
+ run_manifest: manifest === null || manifest === undefined
496
+ ? null
497
+ : JSON.stringify(manifest),
498
+ updated_at: new Date().toISOString(),
499
+ });
500
+ if (result.changes === 0) {
501
+ throw new Error(`Run not found: ${runId}`);
502
+ }
503
+ }
438
504
  async ensureStageWorkspace(runId, stageId) {
439
505
  await this.ready();
440
506
  this.getRunRow(runId);
@@ -485,7 +551,7 @@ export class SqliteRunStore {
485
551
  verification_outcome: "not_run",
486
552
  });
487
553
  const row = this.db
488
- .prepare(`SELECT run_id, stage_id, attempt, status, verification_outcome, started_at, finished_at, envelope_json, cost_usd, usage_json
554
+ .prepare(`SELECT ${EXECUTION_SELECT_COLS}
489
555
  FROM stage_executions
490
556
  WHERE run_id = ? AND stage_id = ? AND attempt = ?`)
491
557
  .get(runId, stageId, attempt);
@@ -495,7 +561,7 @@ export class SqliteRunStore {
495
561
  async listStageExecutions(runId, stageId) {
496
562
  await this.ready();
497
563
  const rows = this.db
498
- .prepare(`SELECT run_id, stage_id, attempt, status, verification_outcome, started_at, finished_at, envelope_json, cost_usd, usage_json
564
+ .prepare(`SELECT ${EXECUTION_SELECT_COLS}
499
565
  FROM stage_executions
500
566
  WHERE run_id = ? AND stage_id = ?
501
567
  ORDER BY attempt ASC`)
@@ -505,7 +571,7 @@ export class SqliteRunStore {
505
571
  async getLatestStageExecution(runId, stageId) {
506
572
  await this.ready();
507
573
  const row = this.db
508
- .prepare(`SELECT run_id, stage_id, attempt, status, verification_outcome, started_at, finished_at, envelope_json, cost_usd, usage_json
574
+ .prepare(`SELECT ${EXECUTION_SELECT_COLS}
509
575
  FROM stage_executions
510
576
  WHERE run_id = ? AND stage_id = ?
511
577
  ORDER BY attempt DESC
@@ -524,7 +590,7 @@ export class SqliteRunStore {
524
590
  async getStageExecution(runId, stageId, attempt) {
525
591
  await this.ready();
526
592
  const row = this.db
527
- .prepare(`SELECT run_id, stage_id, attempt, status, verification_outcome, started_at, finished_at, envelope_json, cost_usd, usage_json
593
+ .prepare(`SELECT ${EXECUTION_SELECT_COLS}
528
594
  FROM stage_executions
529
595
  WHERE run_id = ? AND stage_id = ? AND attempt = ?`)
530
596
  .get(runId, stageId, attempt);
@@ -533,6 +599,21 @@ export class SqliteRunStore {
533
599
  }
534
600
  return executionFromRow(row);
535
601
  }
602
+ async listInterruptedStageExecutions() {
603
+ await this.ready();
604
+ const rows = this.db
605
+ .prepare(`SELECT ${EXECUTION_SELECT_COLS}
606
+ FROM stage_executions e
607
+ WHERE e.status = 'interrupted'
608
+ AND e.attempt = (
609
+ SELECT MAX(e2.attempt)
610
+ FROM stage_executions e2
611
+ WHERE e2.run_id = e.run_id AND e2.stage_id = e.stage_id
612
+ )
613
+ ORDER BY e.run_id ASC, e.stage_id ASC, e.attempt ASC`)
614
+ .all();
615
+ return rows.map(executionFromRow);
616
+ }
536
617
  async updateStageExecution(runId, stageId, attempt, patch) {
537
618
  await this.ready();
538
619
  const sets = [];
@@ -570,6 +651,10 @@ export class SqliteRunStore {
570
651
  sets.push("usage_json = @usage_json");
571
652
  params.usage_json = JSON.stringify(patch.usage);
572
653
  }
654
+ if (patch.auto_resume_count !== undefined) {
655
+ sets.push("auto_resume_count = @auto_resume_count");
656
+ params.auto_resume_count = patch.auto_resume_count;
657
+ }
573
658
  if (sets.length === 0)
574
659
  return;
575
660
  const result = this.db
@@ -746,9 +831,13 @@ export class SqliteRunStore {
746
831
  clauses.push("(pipeline_id = ? OR pipeline_path = ? OR pipeline_path = ?)");
747
832
  params.push(pipeline, pipeline, normalized);
748
833
  }
834
+ if (filter?.caller_id !== undefined) {
835
+ clauses.push("caller_id = ?");
836
+ params.push(filter.caller_id);
837
+ }
749
838
  const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
750
839
  const rows = this.db
751
- .prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, inline_pipeline_json
840
+ .prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, repository, ref, resolved_sha, run_branch, git_author_name, git_author_email, cancel_reason, finished_at, slimmed_at, disk_bytes, disk_measured_at, config_origins_json, pipeline_source, pipeline_body, caller_id, run_manifest, skip_gates
752
841
  FROM runs ${where} ORDER BY created_at DESC`)
753
842
  .all(...params);
754
843
  const summaries = [];
@@ -762,13 +851,115 @@ export class SqliteRunStore {
762
851
  }
763
852
  return summaries;
764
853
  }
765
- async listProjectRoots() {
854
+ async ensureProject(absPath) {
855
+ await this.ready();
856
+ const resolved = path.resolve(absPath);
857
+ let st;
858
+ try {
859
+ st = statSync(resolved);
860
+ }
861
+ catch {
862
+ throw new Error(`project_root does not exist: ${resolved}`);
863
+ }
864
+ if (!st.isDirectory()) {
865
+ throw new Error(`project_root is not a directory: ${resolved}`);
866
+ }
867
+ const normalized = normalizeProjectRoot(absPath);
868
+ if (normalized === path.parse(normalized).root) {
869
+ throw new Error(`project_root must not be filesystem root: ${normalized}`);
870
+ }
871
+ const now = new Date().toISOString();
872
+ this.db
873
+ .prepare(`INSERT INTO projects (project_root, created_at) VALUES (?, ?)
874
+ ON CONFLICT(project_root) DO NOTHING`)
875
+ .run(normalized, now);
876
+ return normalized;
877
+ }
878
+ async listRegisteredProjects() {
766
879
  await this.ready();
767
880
  const rows = this.db
768
- .prepare(`SELECT DISTINCT project_root FROM runs WHERE project_root IS NOT NULL AND project_root != ''`)
881
+ .prepare(`SELECT project_root FROM projects ORDER BY project_root`)
769
882
  .all();
770
883
  return rows.map((row) => row.project_root);
771
884
  }
885
+ async upsertTrigger(input) {
886
+ await this.ready();
887
+ const now = new Date().toISOString();
888
+ this.db
889
+ .prepare(`INSERT INTO triggers (id, definition_ref, enabled, created_at, updated_at)
890
+ VALUES (@id, @definition_ref, @enabled, @created_at, @updated_at)
891
+ ON CONFLICT(id) DO UPDATE SET
892
+ definition_ref = @definition_ref,
893
+ enabled = @enabled,
894
+ updated_at = @updated_at`)
895
+ .run({
896
+ id: input.id,
897
+ definition_ref: input.definitionRef,
898
+ enabled: input.enabled ? 1 : 0,
899
+ created_at: now,
900
+ updated_at: now,
901
+ });
902
+ const record = await this.getTrigger(input.id);
903
+ if (!record)
904
+ throw new Error(`Trigger not found after upsert: ${input.id}`);
905
+ return record;
906
+ }
907
+ async getTrigger(id) {
908
+ await this.ready();
909
+ const row = this.db
910
+ .prepare(`SELECT id, definition_ref, enabled, last_fired_at, last_run_id, next_run_at, created_at, updated_at
911
+ FROM triggers WHERE id = ?`)
912
+ .get(id);
913
+ return row ? triggerFromRow(row) : null;
914
+ }
915
+ async listTriggers() {
916
+ await this.ready();
917
+ const rows = this.db
918
+ .prepare(`SELECT id, definition_ref, enabled, last_fired_at, last_run_id, next_run_at, created_at, updated_at
919
+ FROM triggers ORDER BY id`)
920
+ .all();
921
+ return rows.map(triggerFromRow);
922
+ }
923
+ async recordTriggerFired(id, runId) {
924
+ await this.ready();
925
+ const now = new Date().toISOString();
926
+ const result = this.db
927
+ .prepare(`UPDATE triggers SET last_fired_at = @last_fired_at, last_run_id = @last_run_id, updated_at = @updated_at
928
+ WHERE id = @id`)
929
+ .run({ id, last_fired_at: now, last_run_id: runId, updated_at: now });
930
+ if (result.changes === 0) {
931
+ throw new Error(`Trigger not found: ${id}`);
932
+ }
933
+ }
934
+ async setTriggerNextRun(id, nextRunAt) {
935
+ await this.ready();
936
+ const now = new Date().toISOString();
937
+ const result = this.db
938
+ .prepare(`UPDATE triggers SET next_run_at = @next_run_at, updated_at = @updated_at
939
+ WHERE id = @id`)
940
+ .run({ id, next_run_at: nextRunAt, updated_at: now });
941
+ if (result.changes === 0) {
942
+ throw new Error(`Trigger not found: ${id}`);
943
+ }
944
+ }
945
+ async getTriggerAdapterState(triggerId, key) {
946
+ await this.ready();
947
+ const row = this.db
948
+ .prepare(`SELECT value FROM trigger_adapter_state WHERE trigger_id = ? AND key = ?`)
949
+ .get(triggerId, key);
950
+ return row ? row.value : null;
951
+ }
952
+ async setTriggerAdapterState(triggerId, key, value) {
953
+ await this.ready();
954
+ const now = new Date().toISOString();
955
+ this.db
956
+ .prepare(`INSERT INTO trigger_adapter_state (trigger_id, key, value, updated_at)
957
+ VALUES (@trigger_id, @key, @value, @updated_at)
958
+ ON CONFLICT(trigger_id, key) DO UPDATE SET
959
+ value = @value,
960
+ updated_at = @updated_at`)
961
+ .run({ trigger_id: triggerId, key, value, updated_at: now });
962
+ }
772
963
  async readRun(runId) {
773
964
  await this.ready();
774
965
  const row = this.getRunRow(runId);
@@ -1176,15 +1367,47 @@ export class SqliteRunStore {
1176
1367
  ...(row.pipeline_path != null ? { pipeline_path: row.pipeline_path } : {}),
1177
1368
  ...(row.task_path != null ? { task_path: row.task_path } : {}),
1178
1369
  ...(row.project_root != null ? { project_root: row.project_root } : {}),
1370
+ ...(row.repository != null ? { repository: row.repository } : {}),
1371
+ ...(row.ref != null ? { ref: row.ref } : {}),
1372
+ ...(row.resolved_sha != null ? { resolved_sha: row.resolved_sha } : {}),
1373
+ ...(row.run_branch != null ? { run_branch: row.run_branch } : {}),
1374
+ ...(row.git_author_name != null
1375
+ ? { git_author_name: row.git_author_name }
1376
+ : {}),
1377
+ ...(row.git_author_email != null
1378
+ ? { git_author_email: row.git_author_email }
1379
+ : {}),
1380
+ ...(row.cancel_reason != null ? { cancel_reason: row.cancel_reason } : {}),
1381
+ ...(row.finished_at != null ? { finished_at: row.finished_at } : {}),
1382
+ ...(row.slimmed_at != null ? { slimmed_at: row.slimmed_at } : {}),
1383
+ ...(row.disk_bytes != null ? { disk_bytes: row.disk_bytes } : {}),
1384
+ ...(row.disk_measured_at != null
1385
+ ? { disk_measured_at: row.disk_measured_at }
1386
+ : {}),
1387
+ ...(row.config_origins_json
1388
+ ? {
1389
+ config_origins: JSON.parse(row.config_origins_json),
1390
+ }
1391
+ : {}),
1392
+ ...(row.pipeline_source === "inline" || row.pipeline_source === "path"
1393
+ ? { pipeline_source: row.pipeline_source }
1394
+ : {}),
1395
+ ...(row.caller_id != null ? { caller_id: row.caller_id } : {}),
1396
+ ...(row.run_manifest
1397
+ ? { run_manifest: JSON.parse(row.run_manifest) }
1398
+ : {}),
1399
+ ...(row.skip_gates != null ? { skip_gates: row.skip_gates !== 0 } : {}),
1179
1400
  ...(pipeline_dag ? { pipeline_dag } : {}),
1180
- ...(row.inline_pipeline_json != null
1181
- ? { inline_pipeline: JSON.parse(row.inline_pipeline_json) }
1401
+ ...(row.pipeline_body
1402
+ ? {
1403
+ inline_pipeline: JSON.parse(row.pipeline_body),
1404
+ }
1182
1405
  : {}),
1183
1406
  };
1184
1407
  }
1185
1408
  getRunRow(runId) {
1186
1409
  const row = this.db
1187
- .prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, inline_pipeline_json
1410
+ .prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, repository, ref, resolved_sha, run_branch, git_author_name, git_author_email, cancel_reason, finished_at, slimmed_at, disk_bytes, disk_measured_at, config_origins_json, pipeline_source, pipeline_body, caller_id, run_manifest, skip_gates
1188
1411
  FROM runs WHERE run_id = ?`)
1189
1412
  .get(runId);
1190
1413
  if (!row)