stageflow 0.2.0 → 0.8.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 (224) hide show
  1. package/README.md +179 -14
  2. package/dist/agent/activity.d.ts +12 -1
  3. package/dist/agent/activity.js +37 -2
  4. package/dist/agent/activityObserver.d.ts +5 -1
  5. package/dist/agent/activityObserver.js +174 -11
  6. package/dist/agent/cursorProvider.d.ts +1 -10
  7. package/dist/agent/cursorProvider.js +18 -10
  8. package/dist/agent/fakeAgent.js +15 -7
  9. package/dist/agent/piAdapter.d.ts +18 -1
  10. package/dist/agent/piAdapter.js +115 -45
  11. package/dist/agent/port.d.ts +7 -0
  12. package/dist/agent/port.js +3 -0
  13. package/dist/agent/providerAuth.js +12 -7
  14. package/dist/catalog/displayCatalogPath.d.ts +12 -0
  15. package/dist/catalog/displayCatalogPath.js +28 -0
  16. package/dist/cli/artifactCommand.d.ts +10 -0
  17. package/dist/cli/artifactCommand.js +120 -0
  18. package/dist/cli/envelopeCommand.d.ts +32 -0
  19. package/dist/cli/envelopeCommand.js +285 -0
  20. package/dist/cli/exportRunCommand.d.ts +10 -0
  21. package/dist/cli/exportRunCommand.js +150 -0
  22. package/dist/cli/handoffFormat.d.ts +22 -0
  23. package/dist/cli/handoffFormat.js +61 -0
  24. package/dist/cli/initCommand.d.ts +9 -0
  25. package/dist/cli/initCommand.js +71 -0
  26. package/dist/cli/initTemplates.d.ts +3 -0
  27. package/dist/cli/initTemplates.js +19 -0
  28. package/dist/cli/operatorCatalog.d.ts +10 -0
  29. package/dist/cli/operatorCatalog.js +16 -0
  30. package/dist/cli/runCommand.d.ts +7 -1
  31. package/dist/cli/runCommand.js +83 -11
  32. package/dist/cli/runOutput.d.ts +4 -1
  33. package/dist/cli/runOutput.js +36 -8
  34. package/dist/cli/skillsCommand.d.ts +16 -0
  35. package/dist/cli/skillsCommand.js +459 -0
  36. package/dist/cli/validateCommand.d.ts +1 -1
  37. package/dist/cli/validateCommand.js +20 -3
  38. package/dist/cli.d.ts +1 -0
  39. package/dist/cli.js +128 -22
  40. package/dist/config/browseCatalog.d.ts +45 -0
  41. package/dist/config/browseCatalog.js +170 -0
  42. package/dist/config/createPipeline.d.ts +12 -3
  43. package/dist/config/createPipeline.js +292 -100
  44. package/dist/config/createStage.d.ts +10 -4
  45. package/dist/config/createStage.js +44 -14
  46. package/dist/config/listConfig.d.ts +14 -19
  47. package/dist/config/listConfig.js +26 -191
  48. package/dist/config/listModelsFromManifest.d.ts +2 -0
  49. package/dist/config/listModelsFromManifest.js +4 -0
  50. package/dist/config/loadOutcome.d.ts +4 -0
  51. package/dist/config/loadPipeline.d.ts +1 -15
  52. package/dist/config/loadPipeline.js +88 -142
  53. package/dist/config/loadStage.d.ts +4 -0
  54. package/dist/config/loadStage.js +60 -32
  55. package/dist/config/loadStageflowManifest.d.ts +5 -0
  56. package/dist/config/loadStageflowManifest.js +157 -0
  57. package/dist/config/mergePipelineIncludes.d.ts +9 -0
  58. package/dist/config/mergePipelineIncludes.js +141 -0
  59. package/dist/config/normalizePipelineStageEntry.d.ts +18 -0
  60. package/dist/config/normalizePipelineStageEntry.js +210 -0
  61. package/dist/config/pipelineStageKeys.d.ts +4 -0
  62. package/dist/config/pipelineStageKeys.js +14 -0
  63. package/dist/config/resolveCatalogContext.d.ts +13 -0
  64. package/dist/config/resolveCatalogContext.js +13 -0
  65. package/dist/config/resolveForkEmitContext.d.ts +4 -0
  66. package/dist/config/resolveForkEmitContext.js +34 -0
  67. package/dist/config/resolvePipelineDag.d.ts +5 -1
  68. package/dist/config/resolvePipelineDag.js +86 -36
  69. package/dist/config/scanCatalogPaths.d.ts +4 -0
  70. package/dist/config/scanCatalogPaths.js +83 -0
  71. package/dist/config/validateCatalog.d.ts +22 -4
  72. package/dist/config/validateCatalog.js +169 -132
  73. package/dist/envelope/check.d.ts +2 -0
  74. package/dist/envelope/check.js +58 -0
  75. package/dist/envelope/cloneForks.d.ts +2 -0
  76. package/dist/envelope/cloneForks.js +62 -0
  77. package/dist/envelope/forkChoice.d.ts +3 -0
  78. package/dist/envelope/forkChoice.js +47 -0
  79. package/dist/index.d.ts +6 -0
  80. package/dist/index.js +6 -0
  81. package/dist/mcp/catalogTools.d.ts +3 -0
  82. package/dist/mcp/catalogTools.js +187 -0
  83. package/dist/mcp/controlTools.d.ts +3 -0
  84. package/dist/mcp/controlTools.js +147 -0
  85. package/dist/mcp/deps.d.ts +11 -0
  86. package/dist/mcp/deps.js +1 -0
  87. package/dist/mcp/projectRun.d.ts +1 -37
  88. package/dist/mcp/projectRun.js +1 -57
  89. package/dist/mcp/resources.d.ts +5 -0
  90. package/dist/mcp/resources.js +45 -0
  91. package/dist/mcp/server.d.ts +16 -3
  92. package/dist/mcp/server.js +159 -3
  93. package/dist/mcp/toolResults.d.ts +7 -0
  94. package/dist/mcp/toolResults.js +6 -0
  95. package/dist/mcp/tools.d.ts +2 -7
  96. package/dist/mcp/tools.js +52 -86
  97. package/dist/mcp/waitRun.d.ts +46 -0
  98. package/dist/mcp/waitRun.js +146 -0
  99. package/dist/mcp/waitingGates.d.ts +12 -0
  100. package/dist/mcp/waitingGates.js +83 -0
  101. package/dist/project/findProjectRoot.d.ts +2 -0
  102. package/dist/project/findProjectRoot.js +51 -0
  103. package/dist/project/globalHome.d.ts +2 -0
  104. package/dist/project/globalHome.js +19 -0
  105. package/dist/project/resolveProjectContext.d.ts +9 -0
  106. package/dist/project/resolveProjectContext.js +38 -0
  107. package/dist/project/resolveStageflowContext.d.ts +11 -0
  108. package/dist/project/resolveStageflowContext.js +66 -0
  109. package/dist/projection/projectRun.d.ts +44 -0
  110. package/dist/projection/projectRun.js +71 -0
  111. package/dist/prompt/priorEnvelope.d.ts +1 -1
  112. package/dist/prompt/priorEnvelope.js +4 -1
  113. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  114. package/dist/runstore/normalizeCatalogPath.js +4 -0
  115. package/dist/runstore/paths.js +2 -0
  116. package/dist/runstore/pipelineDagSnapshot.d.ts +9 -0
  117. package/dist/runstore/pipelineDagSnapshot.js +90 -1
  118. package/dist/runstore/port.d.ts +22 -2
  119. package/dist/runstore/port.js +4 -1
  120. package/dist/runstore/runProjection.d.ts +1 -1
  121. package/dist/runstore/runProjection.js +25 -4
  122. package/dist/runstore/sqlite/SqliteRunStore.d.ts +3 -2
  123. package/dist/runstore/sqlite/SqliteRunStore.js +65 -7
  124. package/dist/runstore/sqlite/schema.d.ts +1 -1
  125. package/dist/runstore/sqlite/schema.js +4 -1
  126. package/dist/runstore/stageInstanceId.d.ts +4 -0
  127. package/dist/runstore/stageInstanceId.js +23 -0
  128. package/dist/runstore/syntheticStageSnapshot.d.ts +1 -1
  129. package/dist/runstore/syntheticStageSnapshot.js +2 -1
  130. package/dist/runstore/trackProjection.js +28 -12
  131. package/dist/runstore/workspaceLayout.d.ts +1 -0
  132. package/dist/runstore/workspaceLayout.js +1 -1
  133. package/dist/runtime/cloneSchedule.d.ts +18 -0
  134. package/dist/runtime/cloneSchedule.js +233 -0
  135. package/dist/runtime/credentialBinding.d.ts +8 -6
  136. package/dist/runtime/credentialBinding.js +18 -24
  137. package/dist/runtime/envelopeRouting.d.ts +2 -1
  138. package/dist/runtime/envelopeRouting.js +80 -13
  139. package/dist/runtime/pipelineRunner.d.ts +3 -0
  140. package/dist/runtime/pipelineRunner.js +15 -1
  141. package/dist/runtime/pipelineScheduler.d.ts +8 -2
  142. package/dist/runtime/pipelineScheduler.js +215 -39
  143. package/dist/runtime/reloadRunCatalog.d.ts +5 -0
  144. package/dist/runtime/reloadRunCatalog.js +44 -0
  145. package/dist/runtime/resumeReconstruct.d.ts +1 -0
  146. package/dist/runtime/resumeReconstruct.js +31 -10
  147. package/dist/runtime/runChangeBus.d.ts +18 -0
  148. package/dist/runtime/runChangeBus.js +83 -0
  149. package/dist/runtime/runManager.d.ts +4 -0
  150. package/dist/runtime/runManager.js +36 -16
  151. package/dist/runtime/settingsFile.d.ts +12 -0
  152. package/dist/runtime/settingsFile.js +87 -6
  153. package/dist/runtime/stageAttemptBootstrap.d.ts +1 -0
  154. package/dist/runtime/stageAttemptBootstrap.js +18 -7
  155. package/dist/runtime/stageProcessLauncher.js +3 -0
  156. package/dist/runtime/stageRecovery.js +3 -1
  157. package/dist/runtime/stageRunner.d.ts +1 -0
  158. package/dist/runtime/stageRunner.js +17 -15
  159. package/dist/runtime/stageWorker.js +13 -10
  160. package/dist/server/bootstrap.d.ts +32 -0
  161. package/dist/server/bootstrap.js +56 -0
  162. package/dist/server/createHttpHost.d.ts +34 -0
  163. package/dist/server/createHttpHost.js +70 -0
  164. package/dist/server/http.d.ts +6 -13
  165. package/dist/server/http.js +297 -352
  166. package/dist/server/mcpHost.d.ts +22 -0
  167. package/dist/server/mcpHost.js +21 -0
  168. package/dist/server/operatorResults.d.ts +13 -0
  169. package/dist/server/operatorResults.js +22 -0
  170. package/dist/tools/emitStageEnvelope.d.ts +12 -1
  171. package/dist/tools/emitStageEnvelope.js +27 -1
  172. package/dist/types/envelope.d.ts +3 -0
  173. package/dist/types/forkChoice.d.ts +30 -0
  174. package/dist/types/forkChoice.js +1 -0
  175. package/dist/types/pipeline.d.ts +59 -2
  176. package/dist/types/stageflowManifest.d.ts +23 -0
  177. package/dist/types/stageflowManifest.js +1 -0
  178. package/dist/ui/assets/{index-DCsDopak.css → index-C3N7MXAC.css} +1 -1
  179. package/dist/ui/assets/index-CSoGDA3A.js +118 -0
  180. package/dist/ui/index.html +3 -2
  181. package/dist/ui/stageflow-icon.svg +12 -0
  182. package/package.json +8 -5
  183. package/skills/install-suite.sh +107 -0
  184. package/skills/stageflow/SKILL.md +26 -0
  185. package/skills/stageflow/references/control-surface.md +26 -0
  186. package/skills/stageflow/scripts/detect-host.mjs +54 -0
  187. package/skills/stageflow/scripts/detect-host.test.mjs +97 -0
  188. package/skills/stageflow-author/SKILL.md +58 -0
  189. package/skills/stageflow-author/assets/examples/branch-decision/hotfix.yaml +10 -0
  190. package/skills/stageflow-author/assets/examples/branch-decision/release-gate.pipeline.yaml +12 -0
  191. package/skills/stageflow-author/assets/examples/branch-decision/run-tests.yaml +13 -0
  192. package/skills/stageflow-author/assets/examples/branch-decision/ship.yaml +10 -0
  193. package/skills/stageflow-author/assets/examples/linear-review/draft.yaml +9 -0
  194. package/skills/stageflow-author/assets/examples/linear-review/publish.yaml +10 -0
  195. package/skills/stageflow-author/assets/examples/linear-review/review-loop.pipeline.yaml +10 -0
  196. package/skills/stageflow-author/assets/examples/linear-review/review.yaml +15 -0
  197. package/skills/stageflow-author/assets/examples/non-sdlc-digest/gather.yaml +9 -0
  198. package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml +10 -0
  199. package/skills/stageflow-author/assets/examples/non-sdlc-digest/send.yaml +10 -0
  200. package/skills/stageflow-author/assets/examples/non-sdlc-digest/summarize.yaml +9 -0
  201. package/skills/stageflow-author/references/catalog-mapping.md +131 -0
  202. package/skills/stageflow-author/references/catalog-write-conventions.md +29 -0
  203. package/skills/stageflow-author/references/stage-prompt-template.md +55 -0
  204. package/skills/stageflow-author/references/validate-and-report.md +38 -0
  205. package/skills/stageflow-delegate/SKILL.md +18 -0
  206. package/skills/stageflow-delegate/references/authoring-or-run.md +15 -0
  207. package/skills/stageflow-delegate/references/example-walkthrough.md +30 -0
  208. package/skills/stageflow-delegate/references/pattern-detection.md +44 -0
  209. package/skills/stageflow-run/SKILL.md +151 -0
  210. package/skills/stageflow-run/references/mcp-call.md +17 -0
  211. package/skills/stageflow-run/references/task-and-pipeline-selection.md +52 -0
  212. package/skills/stageflow-run/scripts/mcp-call.mjs +299 -0
  213. package/skills/stageflow-run/scripts/mcp-call.test.mjs +271 -0
  214. package/skills/stageflow-session-capture/SKILL.md +94 -0
  215. package/skills/stageflow-session-capture/assets/example-pipeline/example.pipeline.yaml +7 -0
  216. package/skills/stageflow-session-capture/assets/example-pipeline/implement.yaml +8 -0
  217. package/skills/stageflow-session-capture/assets/example-pipeline/research.yaml +8 -0
  218. package/skills/stageflow-session-capture/references/catalog-authoring.md +40 -0
  219. package/skills/stageflow-session-capture/references/transcript-sources.md +25 -0
  220. package/skills/stageflow-session-capture/scripts/check-provider-gate.mjs +43 -0
  221. package/skills/stageflow-session-capture/scripts/locate-session-transcript.mjs +141 -0
  222. package/skills/stageflow-session-capture/scripts/resolve-catalog-id.mjs +119 -0
  223. package/skills/stageflow-setup/SKILL.md +110 -0
  224. package/dist/ui/assets/index-Cry0Tpfx.js +0 -118
package/dist/cli.js CHANGED
@@ -4,34 +4,61 @@ import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { PiAgentAdapter } from "./agent/piAdapter.js";
7
+ import { ARTIFACT_USAGE, runArtifactCommand } from "./cli/artifactCommand.js";
8
+ import { ENVELOPE_USAGE, runEnvelopeCommand, } from "./cli/envelopeCommand.js";
9
+ import { EXPORT_RUN_USAGE, runExportRunCommand, } from "./cli/exportRunCommand.js";
10
+ import { INIT_USAGE, runInitCommand } from "./cli/initCommand.js";
7
11
  import { PROVIDERS_USAGE, runProvidersCommand } from "./cli/providersCommand.js";
8
12
  import { RUN_USAGE, runRunCommand } from "./cli/runCommand.js";
13
+ import { resolveOperatorCatalog } from "./cli/operatorCatalog.js";
14
+ import { SKILLS_USAGE, runSkillsCommand } from "./cli/skillsCommand.js";
9
15
  import { VALIDATE_USAGE, runValidateCommand } from "./cli/validateCommand.js";
10
16
  import { createRunStore } from "./runstore/createStore.js";
17
+ import { resolveStageflowContext } from "./project/resolveStageflowContext.js";
11
18
  import { exitForOutcome, runStageWorker } from "./runtime/stageWorker.js";
12
19
  import { SF_STAGE_WORKER } from "./runtime/stageWorkerProtocol.js";
13
20
  import { DEFAULT_PORT, startUiServer } from "./server/http.js";
21
+ import { startMcpServer } from "./server/mcpHost.js";
22
+ import { resolveMcpStateless } from "./mcp/server.js";
14
23
  const USAGE = `Usage:
15
- sf run --task <path> --pipeline <name-or-path> [--checkout <path>] [--json] [--skip-gates] [--git-sha <sha>] [--ci-pr-url <url>] [--ci-job-url <url>]
16
- sf validate [--pipeline <name-or-path>] [--strict] [--json]
17
- sf ui [--port ${DEFAULT_PORT}]
24
+ sf init
25
+ 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>]
26
+ sf validate [--pipeline <path>] [--task <path>] [--strict] [--json]
27
+ sf artifact read --run <runId> --path <relPath> [--out <file>]
28
+ sf envelope get --run <runId> --stage <stageId> [--json] [--from <sf-run.json>] [--detect-stage <id>] [--format envelope|handoff]
29
+ sf export-run --run <runId> [--from <sf-run.json>] [--out <file>]
30
+ sf ui [--port ${DEFAULT_PORT}] [--mcp-stateless]
31
+ sf mcp [--port ${DEFAULT_PORT}] [--mcp-stateless]
18
32
  sf providers list
19
33
  sf providers status [--provider <id>]
20
34
  sf providers detect
21
35
  sf providers source [get | set <pi_home|sf_owned>]
22
36
  sf providers login <providerId> [--type api_key|oauth] [--api-key-env <VAR>]
23
37
  sf providers logout <providerId>
38
+ sf skills list
39
+ sf skills install --from-path <dir> [--skill-name <name>]
40
+ sf skills install --from-zip <url-or-path> [--skill-name <name>] [--checksum sha256:<hex>]
24
41
  sf --help
25
42
 
26
43
  Stageflow (sf) runs YAML-defined automatic stage pipelines.
27
44
 
28
45
  Store backend: SF_STORE=sqlite only. SF_STORE=disk is rejected; disk-era .stageflow/runs trees import when the SQLite store is empty. Data under .stageflow/.
29
46
 
47
+ ${INIT_USAGE}
48
+
30
49
  ${RUN_USAGE}
31
50
 
32
51
  ${VALIDATE_USAGE}
33
52
 
34
- ${PROVIDERS_USAGE}`;
53
+ ${ARTIFACT_USAGE}
54
+
55
+ ${ENVELOPE_USAGE}
56
+
57
+ ${EXPORT_RUN_USAGE}
58
+
59
+ ${PROVIDERS_USAGE}
60
+
61
+ ${SKILLS_USAGE}`;
35
62
  function parseArgs(argv) {
36
63
  const args = argv.slice(2);
37
64
  if (args.length === 0) {
@@ -44,7 +71,12 @@ function parseArgs(argv) {
44
71
  const command = args[0];
45
72
  if (command === "providers" ||
46
73
  command === "validate" ||
47
- command === "run") {
74
+ command === "run" ||
75
+ command === "init" ||
76
+ command === "artifact" ||
77
+ command === "envelope" ||
78
+ command === "export-run" ||
79
+ command === "skills") {
48
80
  return { help: false, command };
49
81
  }
50
82
  if (args.includes("--help") || args.includes("-h")) {
@@ -54,6 +86,7 @@ function parseArgs(argv) {
54
86
  let pipeline;
55
87
  let port;
56
88
  let checkout;
89
+ let mcpStateless = false;
57
90
  for (let i = 1; i < args.length; i++) {
58
91
  if (args[i] === "--task") {
59
92
  task = args[++i];
@@ -75,8 +108,11 @@ function parseArgs(argv) {
75
108
  throw new Error(`Invalid --port: ${raw}`);
76
109
  }
77
110
  }
111
+ else if (args[i] === "--mcp-stateless") {
112
+ mcpStateless = true;
113
+ }
78
114
  }
79
- return { help: false, command, task, pipeline, port, checkout };
115
+ return { help: false, command, task, pipeline, port, checkout, mcpStateless };
80
116
  }
81
117
  export function parseRunStageArgs(argv) {
82
118
  let runId;
@@ -85,6 +121,7 @@ export function parseRunStageArgs(argv) {
85
121
  let resumeAnswer;
86
122
  let attempt;
87
123
  let sessionFilePath;
124
+ let operatorCwd;
88
125
  let operatorAgentDir;
89
126
  let skipGates = false;
90
127
  for (let i = 0; i < argv.length; i++) {
@@ -130,6 +167,12 @@ export function parseRunStageArgs(argv) {
130
167
  throw new Error("Missing value for --session-file");
131
168
  }
132
169
  }
170
+ else if (argv[i] === "--operator-cwd") {
171
+ operatorCwd = argv[++i];
172
+ if (operatorCwd === undefined) {
173
+ throw new Error("Missing value for --operator-cwd");
174
+ }
175
+ }
133
176
  else if (argv[i] === "--operator-agent-dir") {
134
177
  operatorAgentDir = argv[++i];
135
178
  if (operatorAgentDir === undefined) {
@@ -143,6 +186,11 @@ export function parseRunStageArgs(argv) {
143
186
  if (!runId || !stageId) {
144
187
  throw new Error("Missing --run-id and/or --stage-id");
145
188
  }
189
+ const operatorCatalog = resolveOperatorCatalog({
190
+ flags: { operatorCwd, operatorAgentDir },
191
+ env: process.env,
192
+ defaultCwd: process.cwd(),
193
+ });
146
194
  return {
147
195
  runId,
148
196
  stageId,
@@ -151,9 +199,7 @@ export function parseRunStageArgs(argv) {
151
199
  attempt,
152
200
  sessionFilePath,
153
201
  skipGates,
154
- ...(operatorAgentDir !== undefined
155
- ? { operatorCatalog: { cwd: process.cwd(), agentDir: operatorAgentDir } }
156
- : {}),
202
+ operatorCatalog,
157
203
  };
158
204
  }
159
205
  async function handleInternalRunStage(argv) {
@@ -194,22 +240,59 @@ async function main(argv) {
194
240
  console.log(USAGE);
195
241
  return argv.slice(2).length === 0 ? 1 : 0;
196
242
  }
197
- const rootDir = process.cwd();
243
+ const ctx = await resolveStageflowContext(process.cwd());
244
+ if (parsed.command === "init") {
245
+ return runInitCommand(argv.slice(3), { cwd: ctx.invocationCwd });
246
+ }
198
247
  if (parsed.command === "validate") {
199
- return runValidateCommand(argv.slice(3), { cwd: rootDir });
248
+ return runValidateCommand(argv.slice(3), { cwd: ctx.invocationCwd });
200
249
  }
201
250
  if (parsed.command === "run") {
202
- return runRunCommand(argv.slice(3), { cwd: rootDir });
251
+ return runRunCommand(argv.slice(3), {
252
+ cwd: ctx.invocationCwd,
253
+ projectRoot: ctx.projectRoot,
254
+ isGitProject: ctx.isGitProject,
255
+ });
256
+ }
257
+ if (parsed.command === "artifact") {
258
+ return runArtifactCommand(argv.slice(3), {
259
+ cwd: ctx.invocationCwd,
260
+ projectRoot: ctx.projectRoot,
261
+ });
262
+ }
263
+ if (parsed.command === "envelope") {
264
+ return runEnvelopeCommand(argv.slice(3), {
265
+ cwd: ctx.invocationCwd,
266
+ projectRoot: ctx.projectRoot,
267
+ });
268
+ }
269
+ if (parsed.command === "export-run") {
270
+ return runExportRunCommand(argv.slice(3), {
271
+ cwd: ctx.invocationCwd,
272
+ projectRoot: ctx.projectRoot,
273
+ });
203
274
  }
204
275
  if (parsed.command === "providers") {
205
- return runProvidersCommand(argv.slice(3), rootDir);
276
+ return runProvidersCommand(argv.slice(3), ctx.invocationCwd);
277
+ }
278
+ if (parsed.command === "skills") {
279
+ return runSkillsCommand(argv.slice(3), {
280
+ cwd: ctx.invocationCwd,
281
+ projectRoot: ctx.projectRoot,
282
+ });
206
283
  }
207
- const store = createRunStore({ rootDir });
284
+ const store = createRunStore({ rootDir: ctx.projectRoot });
208
285
  if (parsed.command === "ui") {
286
+ const mcpStateless = resolveMcpStateless({
287
+ mcpStateless: parsed.mcpStateless,
288
+ });
209
289
  const { url, mcpUrl } = await startUiServer({
210
290
  agent: new PiAgentAdapter(),
211
291
  store,
292
+ cwd: ctx.invocationCwd,
293
+ rootDir: ctx.projectRoot,
212
294
  port: parsed.port,
295
+ mcpStateless,
213
296
  });
214
297
  console.log(`Operator console: ${url}`);
215
298
  console.log(`MCP endpoint: ${mcpUrl}`);
@@ -217,6 +300,22 @@ async function main(argv) {
217
300
  await new Promise(() => undefined);
218
301
  return 0;
219
302
  }
303
+ if (parsed.command === "mcp") {
304
+ const mcpStateless = resolveMcpStateless({
305
+ mcpStateless: parsed.mcpStateless,
306
+ });
307
+ const { mcpUrl } = await startMcpServer({
308
+ agent: new PiAgentAdapter(),
309
+ store,
310
+ cwd: ctx.invocationCwd,
311
+ rootDir: ctx.projectRoot,
312
+ port: parsed.port,
313
+ mcpStateless,
314
+ });
315
+ console.log(`MCP endpoint: ${mcpUrl}`);
316
+ await new Promise(() => undefined);
317
+ return 0;
318
+ }
220
319
  if (parsed.command === "internal") {
221
320
  const subArgs = argv.slice(3);
222
321
  const subcommand = subArgs[0];
@@ -235,16 +334,23 @@ async function main(argv) {
235
334
  return 1;
236
335
  }
237
336
  }
337
+ function normalizeCliEntry(filePath) {
338
+ const resolved = path.resolve(filePath);
339
+ let canonical;
340
+ try {
341
+ canonical = realpathSync(resolved);
342
+ }
343
+ catch {
344
+ canonical = resolved;
345
+ }
346
+ return canonical.replace(/\.(?:[cm]?[jt]s)$/i, "");
347
+ }
348
+ export function sameCliEntry(a, b) {
349
+ return normalizeCliEntry(a) === normalizeCliEntry(b);
350
+ }
238
351
  function isDirectCliInvocation() {
239
352
  const self = fileURLToPath(import.meta.url);
240
- return process.argv.slice(1).some((arg) => {
241
- try {
242
- return realpathSync(path.resolve(arg)) === realpathSync(self);
243
- }
244
- catch {
245
- return false;
246
- }
247
- });
353
+ return process.argv.slice(1).some((arg) => sameCliEntry(arg, self));
248
354
  }
249
355
  if (isDirectCliInvocation()) {
250
356
  main(process.argv)
@@ -0,0 +1,45 @@
1
+ import type { StageGateKind } from "../types/stage.js";
2
+ import type { LoadedManifest } from "../types/stageflowManifest.js";
3
+ import type { LoadIssue } from "./loadOutcome.js";
4
+ import type { CatalogContext } from "./resolveCatalogContext.js";
5
+ import { type CatalogManifestStatus, type StageflowContext } from "../project/resolveStageflowContext.js";
6
+ export type TaskListing = {
7
+ path: string;
8
+ id: string;
9
+ goal: string;
10
+ };
11
+ export type PipelineStageListing = {
12
+ id: string;
13
+ gate_kinds?: StageGateKind[];
14
+ uses_path?: string;
15
+ inline?: boolean;
16
+ };
17
+ export type PipelineListing = {
18
+ path: string;
19
+ id: string;
20
+ stages: PipelineStageListing[];
21
+ };
22
+ export type CatalogBrowseWarning = {
23
+ path: string;
24
+ kind: "pipeline" | "task";
25
+ error: string;
26
+ };
27
+ export type CatalogBrowseResult = {
28
+ projectRoot: string | null;
29
+ manifest: LoadedManifest | null;
30
+ manifestStatus: CatalogManifestStatus;
31
+ issues: LoadIssue[];
32
+ pipelines: PipelineListing[];
33
+ tasks: TaskListing[];
34
+ models: string[];
35
+ warnings: CatalogBrowseWarning[];
36
+ };
37
+ export type CatalogScanPaths = {
38
+ pipelinePaths: string[];
39
+ taskPaths: string[];
40
+ };
41
+ export declare function getCatalogScanPaths(ctx: CatalogContext): Promise<CatalogScanPaths | null>;
42
+ export declare function browseCatalog(invocationCwd: string | StageflowContext): Promise<CatalogBrowseResult>;
43
+ export declare function listPipelinesForContext(ctx: CatalogContext): Promise<PipelineListing[]>;
44
+ export declare function listTasksForContext(ctx: CatalogContext): Promise<TaskListing[]>;
45
+ export declare function listModelsForContext(ctx: CatalogContext): Promise<string[]>;
@@ -0,0 +1,170 @@
1
+ import path from "node:path";
2
+ import { loadPipeline } from "./loadPipeline.js";
3
+ import { loadTask } from "./loadTask.js";
4
+ import { resolveStageflowContext, } from "../project/resolveStageflowContext.js";
5
+ import { scanCatalogPaths } from "./scanCatalogPaths.js";
6
+ const BAKED_MODEL_IDS = [
7
+ "anthropic/claude-sonnet-4-5",
8
+ "cursor/auto",
9
+ "cursor/composer-2-5",
10
+ ];
11
+ function repoRelPath(projectRoot, absPath) {
12
+ return path.relative(projectRoot, absPath).replace(/\\/g, "/");
13
+ }
14
+ function mapStageListing(stage, source, projectRoot) {
15
+ const listing = {
16
+ id: stage.id,
17
+ ...(stage.gate_kinds ? { gate_kinds: stage.gate_kinds } : {}),
18
+ };
19
+ if (source?.kind === "inline") {
20
+ listing.inline = true;
21
+ }
22
+ else if (source?.kind === "file") {
23
+ listing.uses_path = repoRelPath(projectRoot, source.path);
24
+ }
25
+ return listing;
26
+ }
27
+ function bakedModels() {
28
+ return [...BAKED_MODEL_IDS].sort((a, b) => a.localeCompare(b));
29
+ }
30
+ function catalogReadyFromStageflow(ctx) {
31
+ return ctx.isGitProject && ctx.manifestStatus === "ok" && ctx.manifest !== null;
32
+ }
33
+ function catalogReady(ctx) {
34
+ return ctx.manifestStatus === "ok" && ctx.projectRoot !== null && ctx.manifest !== null;
35
+ }
36
+ export async function getCatalogScanPaths(ctx) {
37
+ if (!catalogReady(ctx)) {
38
+ return null;
39
+ }
40
+ const [pipelinePaths, taskPaths] = await Promise.all([
41
+ scanCatalogPaths(ctx.manifest, "pipeline"),
42
+ scanCatalogPaths(ctx.manifest, "task"),
43
+ ]);
44
+ return { pipelinePaths, taskPaths };
45
+ }
46
+ async function listTasksFromManifest(projectRoot, manifest, warnings) {
47
+ const filePaths = await scanCatalogPaths(manifest, "task");
48
+ const listings = [];
49
+ for (const filePath of filePaths) {
50
+ try {
51
+ const task = await loadTask(filePath);
52
+ listings.push({
53
+ path: repoRelPath(projectRoot, filePath),
54
+ id: task.id,
55
+ goal: task.goal,
56
+ });
57
+ }
58
+ catch (err) {
59
+ warnings.push({
60
+ path: repoRelPath(projectRoot, filePath),
61
+ kind: "task",
62
+ error: err instanceof Error ? err.message : String(err),
63
+ });
64
+ }
65
+ }
66
+ listings.sort((a, b) => {
67
+ const pathCmp = a.path.localeCompare(b.path);
68
+ if (pathCmp !== 0)
69
+ return pathCmp;
70
+ return a.id.localeCompare(b.id);
71
+ });
72
+ return listings;
73
+ }
74
+ async function listPipelinesFromManifest(projectRoot, manifest, warnings) {
75
+ const filePaths = await scanCatalogPaths(manifest, "pipeline");
76
+ const listings = [];
77
+ for (const filePath of filePaths) {
78
+ try {
79
+ const loaded = await loadPipeline(filePath, { cwd: projectRoot });
80
+ listings.push({
81
+ path: repoRelPath(projectRoot, filePath),
82
+ id: loaded.pipeline.id,
83
+ stages: loaded.stages.map((stage) => mapStageListing(stage, loaded.stageSources?.[stage.id], projectRoot)),
84
+ });
85
+ }
86
+ catch (err) {
87
+ warnings.push({
88
+ path: repoRelPath(projectRoot, filePath),
89
+ kind: "pipeline",
90
+ error: err instanceof Error ? err.message : String(err),
91
+ });
92
+ }
93
+ }
94
+ listings.sort((a, b) => {
95
+ const pathCmp = a.path.localeCompare(b.path);
96
+ if (pathCmp !== 0)
97
+ return pathCmp;
98
+ return a.id.localeCompare(b.id);
99
+ });
100
+ return listings;
101
+ }
102
+ async function listModelsFromManifest(projectRoot, manifest) {
103
+ const models = new Set(BAKED_MODEL_IDS);
104
+ const filePaths = await scanCatalogPaths(manifest, "pipeline");
105
+ for (const filePath of filePaths) {
106
+ try {
107
+ const loaded = await loadPipeline(filePath, { cwd: projectRoot });
108
+ for (const stage of loaded.stages) {
109
+ if (stage.model.trim()) {
110
+ models.add(stage.model);
111
+ }
112
+ }
113
+ }
114
+ catch {
115
+ // skip invalid pipelines
116
+ }
117
+ }
118
+ return [...models].sort((a, b) => a.localeCompare(b));
119
+ }
120
+ export async function browseCatalog(invocationCwd) {
121
+ const ctx = typeof invocationCwd === "string"
122
+ ? await resolveStageflowContext(invocationCwd)
123
+ : invocationCwd;
124
+ const base = {
125
+ projectRoot: ctx.isGitProject ? ctx.projectRoot : null,
126
+ manifest: ctx.manifest,
127
+ manifestStatus: ctx.manifestStatus,
128
+ issues: ctx.manifestIssues,
129
+ };
130
+ if (!catalogReadyFromStageflow(ctx)) {
131
+ return {
132
+ ...base,
133
+ pipelines: [],
134
+ tasks: [],
135
+ models: bakedModels(),
136
+ warnings: [],
137
+ };
138
+ }
139
+ const warnings = [];
140
+ const [pipelines, tasks, models] = await Promise.all([
141
+ listPipelinesFromManifest(ctx.projectRoot, ctx.manifest, warnings),
142
+ listTasksFromManifest(ctx.projectRoot, ctx.manifest, warnings),
143
+ listModelsFromManifest(ctx.projectRoot, ctx.manifest),
144
+ ]);
145
+ return {
146
+ ...base,
147
+ pipelines,
148
+ tasks,
149
+ models,
150
+ warnings,
151
+ };
152
+ }
153
+ export async function listPipelinesForContext(ctx) {
154
+ if (!catalogReady(ctx)) {
155
+ return [];
156
+ }
157
+ return listPipelinesFromManifest(ctx.projectRoot, ctx.manifest, []);
158
+ }
159
+ export async function listTasksForContext(ctx) {
160
+ if (!catalogReady(ctx)) {
161
+ return [];
162
+ }
163
+ return listTasksFromManifest(ctx.projectRoot, ctx.manifest, []);
164
+ }
165
+ export async function listModelsForContext(ctx) {
166
+ if (!catalogReady(ctx)) {
167
+ return bakedModels();
168
+ }
169
+ return listModelsFromManifest(ctx.projectRoot, ctx.manifest);
170
+ }
@@ -1,11 +1,20 @@
1
+ import type { StageGateKind } from "../types/stage.js";
1
2
  import type { PipelineListing } from "./listConfig.js";
3
+ export type CreatePipelineStageInline = {
4
+ system_prompt: string;
5
+ model: string;
6
+ gate_kinds?: StageGateKind[];
7
+ };
2
8
  export type CreatePipelineStageRef = {
3
9
  id: string;
4
10
  needs?: string;
11
+ uses?: string;
12
+ inline?: CreatePipelineStageInline;
5
13
  };
6
14
  export type CreatePipelineInput = {
15
+ directory: string;
7
16
  id: string;
8
- stages: CreatePipelineStageRef[] | string[];
17
+ stages: CreatePipelineStageRef[];
9
18
  };
10
19
  export type CreatePipelineParseError = {
11
20
  ok: false;
@@ -20,7 +29,7 @@ export type CreatePipelineResult = {
20
29
  status: 400 | 409 | 422 | 500;
21
30
  error: string;
22
31
  };
23
- export declare function normalizeCreatePipelineStages(stages: CreatePipelineStageRef[] | string[]): CreatePipelineStageRef[];
32
+ export declare function normalizeCreatePipelineStages(stages: CreatePipelineStageRef[]): CreatePipelineStageRef[];
24
33
  export declare function parseCreatePipelineBody(body: unknown): CreatePipelineInput | CreatePipelineParseError;
25
34
  export declare function pipelineConfigToYaml(pipeline: {
26
35
  id: string;
@@ -28,4 +37,4 @@ export declare function pipelineConfigToYaml(pipeline: {
28
37
  }, options: {
29
38
  format: "linear" | "dag";
30
39
  }): string;
31
- export declare function createPipeline(cwd: string, input: CreatePipelineInput): Promise<CreatePipelineResult>;
40
+ export declare function createPipeline(projectRoot: string, input: CreatePipelineInput): Promise<CreatePipelineResult>;