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
@@ -11,9 +11,10 @@
11
11
  </script>
12
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
13
13
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Figtree:wght@400;500;600;700&display=swap" />
14
+ <link rel="icon" type="image/svg+xml" href="/stageflow-icon.svg" />
14
15
  <title>Stageflow</title>
15
- <script type="module" crossorigin src="/assets/index-Cry0Tpfx.js"></script>
16
- <link rel="stylesheet" crossorigin href="/assets/index-DCsDopak.css">
16
+ <script type="module" crossorigin src="/assets/index-CSoGDA3A.js"></script>
17
+ <link rel="stylesheet" crossorigin href="/assets/index-C3N7MXAC.css">
17
18
  </head>
18
19
  <body>
19
20
  <div id="root"></div>
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" role="img" aria-label="Stageflow">
2
+ <path
3
+ d="M 12 20 C 28 20, 28 44, 52 44"
4
+ stroke="currentColor"
5
+ stroke-width="2.5"
6
+ stroke-linecap="round"
7
+ fill="none"
8
+ />
9
+ <circle cx="12" cy="20" r="5" fill="currentColor"/>
10
+ <circle cx="32" cy="32" r="5" fill="currentColor"/>
11
+ <circle cx="52" cy="44" r="5" fill="currentColor" opacity="0.45"/>
12
+ </svg>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stageflow",
3
- "version": "0.2.0",
4
- "description": "Stageflow — personal CLI pipeline runtime for configurable SDLC stages on Pi",
3
+ "version": "0.8.0",
4
+ "description": "Stageflow — CLI pipeline runtime for configurable stages on Pi",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "sf": "./dist/cli.js",
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
+ "skills",
12
13
  "README.md",
13
14
  "LICENSE"
14
15
  ],
@@ -16,7 +17,7 @@
16
17
  "type": "git",
17
18
  "url": "git+https://github.com/tejasghutukade/stageflow.git"
18
19
  },
19
- "homepage": "https://github.com/tejasghutukade/stageflow#readme",
20
+ "homepage": "https://tejasghutukade.github.io/stageflow/",
20
21
  "bugs": {
21
22
  "url": "https://github.com/tejasghutukade/stageflow/issues"
22
23
  },
@@ -24,8 +25,9 @@
24
25
  "cli",
25
26
  "pipeline",
26
27
  "pi",
27
- "sdlc",
28
- "agent"
28
+ "agent",
29
+ "workflow",
30
+ "stages"
29
31
  ],
30
32
  "workspaces": [
31
33
  "ui"
@@ -42,6 +44,7 @@
42
44
  "ui:astryx": "npm run astryx -w ui",
43
45
  "copy:ui-dist": "tsx scripts/copy-ui-dist.ts",
44
46
  "verify:pack": "tsx scripts/verify-pack.ts",
47
+ "validate:examples": "npm run build && tsx scripts/validate-examples.ts",
45
48
  "prepublishOnly": "npm run build && npm run ui:build && npm run copy:ui-dist",
46
49
  "providers:list-login-capable": "tsx scripts/list-login-capable-providers.ts"
47
50
  },
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ SOURCE_DIR="$SCRIPT_DIR"
6
+ DEST_ROOT="$(pwd)"
7
+
8
+ SKILLS=(
9
+ stageflow
10
+ stageflow-setup
11
+ stageflow-session-capture
12
+ stageflow-author
13
+ stageflow-run
14
+ stageflow-delegate
15
+ )
16
+
17
+ TARGETS=(
18
+ .cursor/skills
19
+ .claude/skills
20
+ .agents/skills
21
+ )
22
+
23
+ usage() {
24
+ cat <<'EOF'
25
+ Usage: install-suite.sh [--source-dir PATH] [--dest-cwd PATH]
26
+
27
+ Copy the Stageflow harness skills suite into a project's
28
+ .cursor/skills/, .claude/skills/, and .agents/skills/.
29
+
30
+ Options:
31
+ --source-dir PATH Canonical skills tree (default: this script's directory)
32
+ --dest-cwd PATH Project root to install into (default: current directory)
33
+ EOF
34
+ }
35
+
36
+ err() {
37
+ echo "install-suite: $*" >&2
38
+ }
39
+
40
+ parse_args() {
41
+ while [ $# -gt 0 ]; do
42
+ case "$1" in
43
+ --source-dir)
44
+ SOURCE_DIR="${2:?--source-dir requires a path}"
45
+ shift 2
46
+ ;;
47
+ --dest-cwd)
48
+ DEST_ROOT="${2:?--dest-cwd requires a path}"
49
+ shift 2
50
+ ;;
51
+ -h|--help)
52
+ usage
53
+ exit 0
54
+ ;;
55
+ *)
56
+ err "unknown argument: $1"
57
+ usage >&2
58
+ exit 1
59
+ ;;
60
+ esac
61
+ done
62
+ }
63
+
64
+ resolve_paths() {
65
+ if [ ! -d "$SOURCE_DIR" ]; then
66
+ err "source directory not found: $SOURCE_DIR"
67
+ exit 1
68
+ fi
69
+ SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd)"
70
+
71
+ if [ ! -d "$DEST_ROOT" ]; then
72
+ err "destination directory not found: $DEST_ROOT"
73
+ exit 1
74
+ fi
75
+ DEST_ROOT="$(cd "$DEST_ROOT" && pwd)"
76
+
77
+ local expected="${SOURCE_DIR}/stageflow/SKILL.md"
78
+ if [ ! -f "$expected" ]; then
79
+ err "source directory missing stageflow/SKILL.md: ${expected}"
80
+ exit 1
81
+ fi
82
+ }
83
+
84
+ copy_suite() {
85
+ local target skill
86
+ for target in "${TARGETS[@]}"; do
87
+ mkdir -p "${DEST_ROOT}/${target}"
88
+ for skill in "${SKILLS[@]}"; do
89
+ rm -rf "${DEST_ROOT}/${target}/${skill}"
90
+ cp -R "${SOURCE_DIR}/${skill}" "${DEST_ROOT}/${target}/${skill}"
91
+ done
92
+ done
93
+ }
94
+
95
+ main() {
96
+ parse_args "$@"
97
+ resolve_paths
98
+ copy_suite
99
+
100
+ echo "Installed Stageflow skills suite"
101
+ echo "Source: ${SOURCE_DIR}"
102
+ for target in "${TARGETS[@]}"; do
103
+ echo "${DEST_ROOT}/${target}"
104
+ done
105
+ }
106
+
107
+ main "$@"
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: stageflow
3
+ description: >-
4
+ Routes Stageflow work to one job: setup (install, catalog, or provider),
5
+ session-capture (reuse this chat or a past session), author (a loop the human
6
+ can explain), run (start, watch, or answer a pipeline), or delegate (a
7
+ repeating pattern). Use when the user mentions Stageflow, sf, a pipeline,
8
+ HITL, or a repeating Stageflow workflow.
9
+ compatibility: Requires the Stageflow CLI (sf). An MCP host (sf ui or sf mcp) is optional.
10
+ ---
11
+
12
+ # Stageflow
13
+
14
+ Read [references/control-surface.md](references/control-surface.md) before talking to a run. Probe with [scripts/detect-host.mjs](scripts/detect-host.mjs). Do not restate that policy here.
15
+
16
+ Read the matching job `SKILL.md` and follow it. Do not invent job behavior in this router.
17
+
18
+ | Reach this job when | Read |
19
+ |---|---|
20
+ | Install is missing, there is no catalog, or a provider is not logged in | [../stageflow-setup/SKILL.md](../stageflow-setup/SKILL.md) |
21
+ | The request should reuse a past session or this chat | [../stageflow-session-capture/SKILL.md](../stageflow-session-capture/SKILL.md) |
22
+ | The request describes a loop the human can explain | [../stageflow-author/SKILL.md](../stageflow-author/SKILL.md) |
23
+ | The request needs to start, watch, or answer a run | [../stageflow-run/SKILL.md](../stageflow-run/SKILL.md) |
24
+ | The request repeats a known pattern, or could become one | [../stageflow-delegate/SKILL.md](../stageflow-delegate/SKILL.md) |
25
+
26
+ If none of those fit, name the five jobs in one line and ask which.
@@ -0,0 +1,26 @@
1
+ # Control surface
2
+
3
+ Prefer MCP when a Stageflow host is up. Otherwise use the CLI. This file is the only copy of that rule; job skills cite it instead of restating it.
4
+
5
+ ## Probe
6
+
7
+ Run [../scripts/detect-host.mjs](../scripts/detect-host.mjs). Do not write a second probe.
8
+
9
+ ```bash
10
+ node ../scripts/detect-host.mjs
11
+ node ../scripts/detect-host.mjs --base-url http://127.0.0.1:3847
12
+ ```
13
+
14
+ The script `GET`s `{baseUrl}/api/health` (default `http://127.0.0.1:3847`, 1500 ms timeout). **up** means HTTP 200 and parseable JSON. Non-200, non-JSON, or timeout is **down**.
15
+
16
+ Stdout is one line: `up <baseUrl>` or `down <baseUrl>`. Exit `0` when up, `1` when down, `2` on usage error.
17
+
18
+ Start a host with `sf ui` or `sf mcp` when the user wants MCP. Do not auto-start one.
19
+
20
+ ## When the host is up
21
+
22
+ Use MCP tools over the Streamable HTTP endpoint at `{baseUrl}/mcp`. Tool names and payloads live in [docs/mcp.md](../../../docs/mcp.md). Typical talking-job tools: `list_pipelines`, `list_tasks`, `start_run`, `get_run`, `wait_run`, `list_waiting`, `answer_gate`, `get_envelope`, `read_artifact`, `validate`, `get_health`.
23
+
24
+ ## When the host is down
25
+
26
+ Use the `sf` CLI. Command names and flags live in [docs/cli-reference.md](../../../docs/cli-reference.md). Typical talking-job commands: `sf run`, `sf validate`, `sf envelope get`, `sf artifact read`, `sf providers`.
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ const DEFAULT_BASE_URL = "http://127.0.0.1:3847";
4
+ const TIMEOUT_MS = 1500;
5
+
6
+ function usage() {
7
+ return "Usage: detect-host.mjs [--base-url URL]";
8
+ }
9
+
10
+ function parseArgs(argv) {
11
+ let baseUrl = DEFAULT_BASE_URL;
12
+ for (let i = 0; i < argv.length; i += 1) {
13
+ const arg = argv[i];
14
+ if (arg === "-h" || arg === "--help") {
15
+ console.log(usage());
16
+ process.exit(0);
17
+ }
18
+ if (arg === "--base-url") {
19
+ const value = argv[i + 1];
20
+ if (!value) {
21
+ console.error("detect-host: --base-url requires a URL");
22
+ console.error(usage());
23
+ process.exit(2);
24
+ }
25
+ baseUrl = value.replace(/\/$/, "");
26
+ i += 1;
27
+ continue;
28
+ }
29
+ console.error(`detect-host: unknown argument: ${arg}`);
30
+ console.error(usage());
31
+ process.exit(2);
32
+ }
33
+ return { baseUrl };
34
+ }
35
+
36
+ async function probe(baseUrl) {
37
+ const ac = new AbortController();
38
+ const timer = setTimeout(() => ac.abort(), TIMEOUT_MS);
39
+ try {
40
+ const res = await fetch(`${baseUrl}/api/health`, { signal: ac.signal });
41
+ if (res.status !== 200) return "down";
42
+ JSON.parse(await res.text());
43
+ return "up";
44
+ } catch {
45
+ return "down";
46
+ } finally {
47
+ clearTimeout(timer);
48
+ }
49
+ }
50
+
51
+ const { baseUrl } = parseArgs(process.argv.slice(2));
52
+ const status = await probe(baseUrl);
53
+ console.log(`${status} ${baseUrl}`);
54
+ process.exit(status === "up" ? 0 : 1);
@@ -0,0 +1,97 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawn } from "node:child_process";
3
+ import { createServer } from "node:http";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { test } from "node:test";
7
+
8
+ const script = path.join(path.dirname(fileURLToPath(import.meta.url)), "detect-host.mjs");
9
+
10
+ function run(baseUrl) {
11
+ return new Promise((resolve) => {
12
+ const child = spawn(process.execPath, [script, "--base-url", baseUrl], {
13
+ stdio: ["ignore", "pipe", "pipe"],
14
+ });
15
+ let stdout = "";
16
+ let stderr = "";
17
+ child.stdout.setEncoding("utf8");
18
+ child.stderr.setEncoding("utf8");
19
+ child.stdout.on("data", (chunk) => {
20
+ stdout += chunk;
21
+ });
22
+ child.stderr.on("data", (chunk) => {
23
+ stderr += chunk;
24
+ });
25
+ child.on("close", (status) => {
26
+ resolve({ status, stdout, stderr });
27
+ });
28
+ });
29
+ }
30
+
31
+ function listen(handler) {
32
+ return new Promise((resolve) => {
33
+ const server = createServer(handler);
34
+ server.listen(0, "127.0.0.1", () => {
35
+ const addr = server.address();
36
+ resolve({ server, baseUrl: `http://127.0.0.1:${addr.port}` });
37
+ });
38
+ });
39
+ }
40
+
41
+ test("classifies reachable 200 JSON /api/health as up", async () => {
42
+ const { server, baseUrl } = await listen((req, res) => {
43
+ if (req.url === "/api/health") {
44
+ res.writeHead(200, { "content-type": "application/json" });
45
+ res.end(JSON.stringify({ ok: true }));
46
+ return;
47
+ }
48
+ res.writeHead(404);
49
+ res.end();
50
+ });
51
+ try {
52
+ const result = await run(baseUrl);
53
+ assert.equal(result.status, 0);
54
+ assert.equal(result.stdout.trim(), `up ${baseUrl}`);
55
+ } finally {
56
+ server.close();
57
+ }
58
+ });
59
+
60
+ test("classifies non-200 /api/health as down", async () => {
61
+ const { server, baseUrl } = await listen((_req, res) => {
62
+ res.writeHead(503, { "content-type": "application/json" });
63
+ res.end(JSON.stringify({ ok: false }));
64
+ });
65
+ try {
66
+ const result = await run(baseUrl);
67
+ assert.equal(result.status, 1);
68
+ assert.equal(result.stdout.trim(), `down ${baseUrl}`);
69
+ } finally {
70
+ server.close();
71
+ }
72
+ });
73
+
74
+ test("classifies 200 non-JSON /api/health as down", async () => {
75
+ const { server, baseUrl } = await listen((_req, res) => {
76
+ res.writeHead(200, { "content-type": "text/plain" });
77
+ res.end("ok");
78
+ });
79
+ try {
80
+ const result = await run(baseUrl);
81
+ assert.equal(result.status, 1);
82
+ assert.equal(result.stdout.trim(), `down ${baseUrl}`);
83
+ } finally {
84
+ server.close();
85
+ }
86
+ });
87
+
88
+ test("classifies a hung /api/health as down", async () => {
89
+ const { server, baseUrl } = await listen(() => {});
90
+ try {
91
+ const result = await run(baseUrl);
92
+ assert.equal(result.status, 1);
93
+ assert.equal(result.stdout.trim(), `down ${baseUrl}`);
94
+ } finally {
95
+ server.close();
96
+ }
97
+ });
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: stageflow-author
3
+ description: >-
4
+ Turns a described structure or repeatable loop into a reusable Stageflow
5
+ pipeline and one stage YAML per step in the project catalog. Use when a
6
+ human explains steps, sequencing, a decision point, or a review they want
7
+ to reuse.
8
+ compatibility: Requires the sf CLI on PATH
9
+ disable-model-invocation: true
10
+ ---
11
+
12
+ # Stageflow author
13
+
14
+ Turn a structure a human can explain into one pipeline YAML file and one stage YAML file per step. `stageflow-run` owns starting a run and any throwaway task.
15
+
16
+ Talking jobs cite [`../stageflow/references/control-surface.md`](../stageflow/references/control-surface.md). Probe with [`../stageflow/scripts/detect-host.mjs`](../stageflow/scripts/detect-host.mjs) only when choosing MCP `validate` — see [`references/validate-and-report.md`](references/validate-and-report.md). Do not write a second probe.
17
+
18
+ Shape reference: [`assets/examples/linear-review/`](assets/examples/linear-review/), [`assets/examples/branch-decision/`](assets/examples/branch-decision/), [`assets/examples/non-sdlc-digest/`](assets/examples/non-sdlc-digest/).
19
+
20
+ ## Provider gate
21
+
22
+ Run before any catalog write:
23
+
24
+ ```
25
+ sf providers status
26
+ ```
27
+
28
+ A provider counts when a row's second column is `configured`. **Done when** at least one row is `configured`. If none are, or the command fails, stop. Write nothing. Name `stageflow-setup`. Do not run `sf providers login`.
29
+
30
+ ## Elicit
31
+
32
+ Ask until you can name every step, how they sequence, any decision point, and any review or sign-off. Confirm that mapped summary with the human before writing.
33
+
34
+ **Done when** the human agrees the step list, sequencing, decisions, and review points.
35
+
36
+ ## Map
37
+
38
+ Read [`references/catalog-mapping.md`](references/catalog-mapping.md). Apply those rules to the confirmed structure. Read [`references/stage-prompt-template.md`](references/stage-prompt-template.md) for each stage's `system_prompt`, `model`, and `gate_kinds`.
39
+
40
+ **Done when** you have a pipeline id, one stage id per step, `needs` / `fork` wiring, and a prompt plan per stage.
41
+
42
+ ## Locate
43
+
44
+ Read [`references/catalog-write-conventions.md`](references/catalog-write-conventions.md). Resolve the write directory and check every candidate pipeline and stage id against files already there.
45
+
46
+ **Done when** every id is free, or the human has given a different id.
47
+
48
+ ## Write
49
+
50
+ Write one external stage YAML per step and one pipeline YAML that wires them with `uses: ./<id>.yaml`. Use the native Write tool. Do not call `createPipeline` or `createStage`. Do not write a `*.task.yaml`.
51
+
52
+ **Done when** the pipeline file and every stage file exist on disk.
53
+
54
+ ## Validate and report
55
+
56
+ Read [`references/validate-and-report.md`](references/validate-and-report.md). Follow it to the end.
57
+
58
+ **Done when** that file's success report is printed.
@@ -0,0 +1,10 @@
1
+ id: hotfix
2
+ system_prompt: |
3
+ Take the failing results from the prior envelope and repair the work they
4
+ describe.
5
+
6
+ Write the repair notes via write_stage_artifact (for example hotfix.md).
7
+
8
+ When finished, call emit_stage_envelope exactly once with status, summary,
9
+ artifacts, and a payload describing what you repaired.
10
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,12 @@
1
+ id: release-gate
2
+ stages:
3
+ - id: run-tests
4
+ uses: ./run-tests.yaml
5
+ fork:
6
+ select: one
7
+ - id: hotfix
8
+ uses: ./hotfix.yaml
9
+ needs: run-tests
10
+ - id: ship
11
+ uses: ./ship.yaml
12
+ needs: run-tests
@@ -0,0 +1,13 @@
1
+ id: run-tests
2
+ system_prompt: |
3
+ Assess whether the current work is ready to ship.
4
+
5
+ Write the results via write_stage_artifact (for example results.md).
6
+
7
+ When finished, call emit_stage_envelope exactly once with status, summary,
8
+ artifacts, and a payload the next stage can use.
9
+
10
+ On a success emit, include fork_choice naming immediate successor id(s) that
11
+ should run. Name only ids listed as this stage's children. select: one →
12
+ exactly one id: hotfix when the results fail, ship when they pass.
13
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,10 @@
1
+ id: ship
2
+ system_prompt: |
3
+ Take the passing results from the prior envelope and produce the shippable
4
+ package.
5
+
6
+ Write the package notes via write_stage_artifact (for example ship.md).
7
+
8
+ When finished, call emit_stage_envelope exactly once with status, summary,
9
+ artifacts, and a payload describing what you shipped.
10
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,9 @@
1
+ id: draft
2
+ system_prompt: |
3
+ Produce a concise draft of the document described in the task.
4
+
5
+ Write the draft via write_stage_artifact (for example draft.md).
6
+
7
+ When finished, call emit_stage_envelope exactly once with status, summary,
8
+ artifacts, and a payload the next stage can use.
9
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,10 @@
1
+ id: publish
2
+ system_prompt: |
3
+ Take the accepted draft and review from prior envelopes and produce the
4
+ version that goes out.
5
+
6
+ Write that version via write_stage_artifact (for example published.md).
7
+
8
+ When finished, call emit_stage_envelope exactly once with status, summary,
9
+ artifacts, and a payload describing what you produced.
10
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,10 @@
1
+ id: review-loop
2
+ stages:
3
+ - id: draft
4
+ uses: ./draft.yaml
5
+ - id: review
6
+ uses: ./review.yaml
7
+ needs: draft
8
+ - id: publish
9
+ uses: ./publish.yaml
10
+ needs: review
@@ -0,0 +1,15 @@
1
+ id: review
2
+ gate_kinds:
3
+ - artifact_backed
4
+ system_prompt: |
5
+ Review the draft from the prior stage and get operator acceptance before
6
+ completing this stage.
7
+
8
+ 1. Write a concise review via write_stage_artifact (for example review.md).
9
+ 2. Call ask_operator with kind artifact_backed referencing that artifact path
10
+ so the operator can review it.
11
+ 3. On reject or change text: revise the review artifact and call ask_operator
12
+ again with artifact_backed in this same stage. Do not complete yet.
13
+ 4. Call emit_stage_envelope with an advancing success status only after the
14
+ operator accepts. Never emit before accept.
15
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,9 @@
1
+ id: gather
2
+ system_prompt: |
3
+ Collect the sources named in the incoming goal for this week's digest.
4
+
5
+ Write the collected notes via write_stage_artifact (for example sources.md).
6
+
7
+ When finished, call emit_stage_envelope exactly once with status, summary,
8
+ artifacts, and a payload the next stage can use.
9
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,10 @@
1
+ id: research-digest
2
+ stages:
3
+ - id: gather
4
+ uses: ./gather.yaml
5
+ - id: summarize
6
+ uses: ./summarize.yaml
7
+ needs: gather
8
+ - id: send
9
+ uses: ./send.yaml
10
+ needs: summarize
@@ -0,0 +1,10 @@
1
+ id: send
2
+ system_prompt: |
3
+ Address the digest from the prior envelope to the named recipients and
4
+ record what went out.
5
+
6
+ Write that record via write_stage_artifact (for example sent.md).
7
+
8
+ When finished, call emit_stage_envelope exactly once with status, summary,
9
+ artifacts, and a payload describing who received the digest.
10
+ model: anthropic/claude-sonnet-4-5
@@ -0,0 +1,9 @@
1
+ id: summarize
2
+ system_prompt: |
3
+ Turn the gathered notes from the prior envelope into a short weekly digest.
4
+
5
+ Write the digest via write_stage_artifact (for example digest.md).
6
+
7
+ When finished, call emit_stage_envelope exactly once with status, summary,
8
+ artifacts, and a payload the next stage can use.
9
+ model: anthropic/claude-sonnet-4-5