@curdx/flow 2.3.11 → 3.1.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 (210) hide show
  1. package/CHANGELOG.md +21 -34
  2. package/LICENSE +1 -1
  3. package/README.md +28 -79
  4. package/dist/index.mjs +995 -0
  5. package/package.json +33 -42
  6. package/.claude-plugin/marketplace.json +0 -48
  7. package/.claude-plugin/plugin.json +0 -70
  8. package/agent-preamble/preamble.md +0 -314
  9. package/agents/flow-adversary.md +0 -202
  10. package/agents/flow-architect.md +0 -197
  11. package/agents/flow-brownfield-analyst.md +0 -142
  12. package/agents/flow-debugger.md +0 -321
  13. package/agents/flow-edge-hunter.md +0 -288
  14. package/agents/flow-executor.md +0 -269
  15. package/agents/flow-orchestrator.md +0 -145
  16. package/agents/flow-planner.md +0 -246
  17. package/agents/flow-product-designer.md +0 -159
  18. package/agents/flow-qa-engineer.md +0 -282
  19. package/agents/flow-researcher.md +0 -165
  20. package/agents/flow-reviewer.md +0 -303
  21. package/agents/flow-security-auditor.md +0 -401
  22. package/agents/flow-triage-analyst.md +0 -272
  23. package/agents/flow-ui-researcher.md +0 -229
  24. package/agents/flow-ux-designer.md +0 -221
  25. package/agents/flow-verifier.md +0 -349
  26. package/bin/curdx-flow +0 -5
  27. package/bin/curdx-flow.js +0 -54
  28. package/cli/README.md +0 -104
  29. package/cli/doctor-workflow.js +0 -483
  30. package/cli/doctor.js +0 -73
  31. package/cli/help.js +0 -59
  32. package/cli/install-bundled-mcps.js +0 -37
  33. package/cli/install-companions.js +0 -19
  34. package/cli/install-context7-config.js +0 -80
  35. package/cli/install-curdx-plugin.js +0 -96
  36. package/cli/install-language.js +0 -35
  37. package/cli/install-next-steps.js +0 -29
  38. package/cli/install-options.js +0 -9
  39. package/cli/install-paths.js +0 -52
  40. package/cli/install-recommended-plugins.js +0 -104
  41. package/cli/install-required-plugins.js +0 -57
  42. package/cli/install-self-update.js +0 -62
  43. package/cli/install-workflow.js +0 -209
  44. package/cli/install.js +0 -101
  45. package/cli/lib/claude-commands.js +0 -41
  46. package/cli/lib/claude-ops.js +0 -47
  47. package/cli/lib/claude.js +0 -183
  48. package/cli/lib/config.js +0 -24
  49. package/cli/lib/doctor-claude-settings.js +0 -1186
  50. package/cli/lib/doctor-report.js +0 -978
  51. package/cli/lib/doctor-runtime-environment.js +0 -196
  52. package/cli/lib/frontmatter.js +0 -44
  53. package/cli/lib/json-schema.js +0 -57
  54. package/cli/lib/logging.js +0 -25
  55. package/cli/lib/process.js +0 -60
  56. package/cli/lib/prompts.js +0 -135
  57. package/cli/lib/runtime.js +0 -107
  58. package/cli/lib/semver.js +0 -109
  59. package/cli/lib/version.js +0 -12
  60. package/cli/protocols-body.md +0 -22
  61. package/cli/protocols.js +0 -162
  62. package/cli/registry.js +0 -123
  63. package/cli/router.js +0 -49
  64. package/cli/uninstall-actions.js +0 -360
  65. package/cli/uninstall-workflow.js +0 -146
  66. package/cli/uninstall.js +0 -42
  67. package/cli/upgrade-workflow.js +0 -80
  68. package/cli/upgrade.js +0 -91
  69. package/cli/utils.js +0 -40
  70. package/gates/adversarial-review-gate.md +0 -219
  71. package/gates/coverage-audit-gate.md +0 -182
  72. package/gates/devex-gate.md +0 -254
  73. package/gates/edge-case-gate.md +0 -194
  74. package/gates/karpathy-gate.md +0 -130
  75. package/gates/security-gate.md +0 -218
  76. package/gates/tdd-gate.md +0 -182
  77. package/gates/test-quality-gate.md +0 -59
  78. package/gates/verification-gate.md +0 -179
  79. package/hooks/hooks.json +0 -58
  80. package/hooks/scripts/common.sh +0 -46
  81. package/hooks/scripts/inject-karpathy.sh +0 -53
  82. package/hooks/scripts/quick-mode-guard.sh +0 -68
  83. package/hooks/scripts/session-start.sh +0 -90
  84. package/hooks/scripts/stop-watcher.sh +0 -230
  85. package/hooks/scripts/subagent-artifact-guard.sh +0 -159
  86. package/hooks/scripts/subagent-statusline.sh +0 -105
  87. package/knowledge/artifact-output-discipline.md +0 -24
  88. package/knowledge/artifact-summary-contracts.md +0 -50
  89. package/knowledge/atomic-commits.md +0 -262
  90. package/knowledge/claude-code-runtime-contracts.md +0 -219
  91. package/knowledge/epic-decomposition.md +0 -307
  92. package/knowledge/execution-strategies.md +0 -303
  93. package/knowledge/karpathy-guidelines.md +0 -219
  94. package/knowledge/planning-reviews.md +0 -211
  95. package/knowledge/poc-first-workflow.md +0 -223
  96. package/knowledge/review-feedback-intake.md +0 -57
  97. package/knowledge/spec-driven-development.md +0 -180
  98. package/knowledge/systematic-debugging.md +0 -378
  99. package/knowledge/two-stage-review.md +0 -249
  100. package/knowledge/wave-execution.md +0 -403
  101. package/monitors/monitors.json +0 -8
  102. package/monitors/scripts/flow-state-monitor.sh +0 -99
  103. package/output-styles/curdx-evidence-first.md +0 -34
  104. package/schemas/agent-frontmatter.schema.json +0 -63
  105. package/schemas/config.schema.json +0 -134
  106. package/schemas/gate-frontmatter.schema.json +0 -30
  107. package/schemas/hooks.schema.json +0 -115
  108. package/schemas/output-style-frontmatter.schema.json +0 -22
  109. package/schemas/plugin-manifest.schema.json +0 -436
  110. package/schemas/plugin-settings.schema.json +0 -29
  111. package/schemas/skill-frontmatter.schema.json +0 -177
  112. package/schemas/spec-frontmatter.schema.json +0 -42
  113. package/schemas/spec-state.schema.json +0 -147
  114. package/settings.json +0 -7
  115. package/skills/brownfield-index/SKILL.md +0 -53
  116. package/skills/brownfield-index/references/applicability.md +0 -12
  117. package/skills/brownfield-index/references/handoff.md +0 -8
  118. package/skills/brownfield-index/references/index-contract.md +0 -10
  119. package/skills/browser-qa/SKILL.md +0 -39
  120. package/skills/browser-qa/references/handoff.md +0 -6
  121. package/skills/browser-qa/references/prerequisites.md +0 -10
  122. package/skills/browser-qa/references/qa-contract.md +0 -20
  123. package/skills/cancel/SKILL.md +0 -41
  124. package/skills/cancel/references/destructive-mode.md +0 -17
  125. package/skills/cancel/references/reporting.md +0 -18
  126. package/skills/cancel/references/state-recovery.md +0 -30
  127. package/skills/cancel/references/target-resolution.md +0 -7
  128. package/skills/debug/SKILL.md +0 -45
  129. package/skills/debug/references/context-gathering.md +0 -11
  130. package/skills/debug/references/failure-guard.md +0 -25
  131. package/skills/debug/references/intake.md +0 -12
  132. package/skills/debug/references/phase-workflow.md +0 -34
  133. package/skills/debug/references/reporting.md +0 -20
  134. package/skills/epic/SKILL.md +0 -39
  135. package/skills/epic/references/epic-artifacts.md +0 -20
  136. package/skills/epic/references/epic-intake.md +0 -9
  137. package/skills/epic/references/slice-handoff.md +0 -16
  138. package/skills/fast/SKILL.md +0 -62
  139. package/skills/fast/references/applicability.md +0 -25
  140. package/skills/fast/references/clarification.md +0 -20
  141. package/skills/fast/references/execution-contract.md +0 -56
  142. package/skills/help/SKILL.md +0 -55
  143. package/skills/help/references/dispatch.md +0 -20
  144. package/skills/help/references/overview.md +0 -39
  145. package/skills/help/references/troubleshoot.md +0 -47
  146. package/skills/help/references/workflow.md +0 -37
  147. package/skills/implement/SKILL.md +0 -96
  148. package/skills/implement/references/error-recovery.md +0 -36
  149. package/skills/implement/references/linear-execution.md +0 -32
  150. package/skills/implement/references/preflight.md +0 -43
  151. package/skills/implement/references/progress-contract.md +0 -32
  152. package/skills/implement/references/state-init.md +0 -33
  153. package/skills/implement/references/stop-hook-execution.md +0 -36
  154. package/skills/implement/references/strategy-router.md +0 -38
  155. package/skills/implement/references/subagent-execution.md +0 -43
  156. package/skills/implement/references/wave-execution.md +0 -162
  157. package/skills/init/SKILL.md +0 -49
  158. package/skills/init/references/gitignore-and-health.md +0 -26
  159. package/skills/init/references/next-steps.md +0 -22
  160. package/skills/init/references/preflight.md +0 -15
  161. package/skills/init/references/scaffold-contract.md +0 -27
  162. package/skills/review/SKILL.md +0 -82
  163. package/skills/review/references/optional-passes.md +0 -48
  164. package/skills/review/references/preflight.md +0 -38
  165. package/skills/review/references/report-contract.md +0 -49
  166. package/skills/review/references/reporting.md +0 -20
  167. package/skills/review/references/stage-execution.md +0 -32
  168. package/skills/security-audit/SKILL.md +0 -47
  169. package/skills/security-audit/references/audit-contract.md +0 -21
  170. package/skills/security-audit/references/gate-handoff.md +0 -8
  171. package/skills/security-audit/references/scope-and-depth.md +0 -9
  172. package/skills/spec/SKILL.md +0 -100
  173. package/skills/spec/references/artifact-landing.md +0 -31
  174. package/skills/spec/references/phase-execution.md +0 -50
  175. package/skills/spec/references/planning-review.md +0 -31
  176. package/skills/spec/references/preflight-and-routing.md +0 -46
  177. package/skills/spec/references/reporting.md +0 -21
  178. package/skills/start/SKILL.md +0 -84
  179. package/skills/start/references/branch-routing.md +0 -51
  180. package/skills/start/references/mode-semantics.md +0 -12
  181. package/skills/start/references/preflight.md +0 -13
  182. package/skills/start/references/reporting.md +0 -20
  183. package/skills/start/references/state-seeding.md +0 -44
  184. package/skills/start/references/workflow-handoff.md +0 -26
  185. package/skills/status/SKILL.md +0 -41
  186. package/skills/status/references/gather-contract.md +0 -27
  187. package/skills/status/references/health-rules.md +0 -27
  188. package/skills/status/references/output-contract.md +0 -24
  189. package/skills/status/references/preflight.md +0 -10
  190. package/skills/status/references/recovery-hints.md +0 -18
  191. package/skills/ui-sketch/SKILL.md +0 -39
  192. package/skills/ui-sketch/references/brief-intake.md +0 -10
  193. package/skills/ui-sketch/references/iteration-handoff.md +0 -5
  194. package/skills/ui-sketch/references/variant-contract.md +0 -15
  195. package/skills/verify/SKILL.md +0 -56
  196. package/skills/verify/references/evidence-workflow.md +0 -39
  197. package/skills/verify/references/output-contract.md +0 -23
  198. package/skills/verify/references/preflight.md +0 -11
  199. package/skills/verify/references/report-handoff.md +0 -35
  200. package/skills/verify/references/strict-mode.md +0 -12
  201. package/templates/CONTEXT.md.tmpl +0 -53
  202. package/templates/PROJECT.md.tmpl +0 -59
  203. package/templates/ROADMAP.md.tmpl +0 -50
  204. package/templates/STATE.md.tmpl +0 -49
  205. package/templates/config.json.tmpl +0 -51
  206. package/templates/design.md.tmpl +0 -83
  207. package/templates/progress.md.tmpl +0 -77
  208. package/templates/requirements.md.tmpl +0 -76
  209. package/templates/research.md.tmpl +0 -83
  210. package/templates/tasks.md.tmpl +0 -107
@@ -1,230 +0,0 @@
1
- #!/usr/bin/env bash
2
- # CurDX-Flow Stop Hook — StopHookLoop strategy implementation
3
- #
4
- # Fires when Claude's turn ends. Decides whether to block (force continue)
5
- # or allow the session to stop.
6
- #
7
- # Decision logic:
8
- # 1. Not a flow project? → allow stop
9
- # 2. No active spec? → allow stop
10
- # 3. Strategy is not "stop-hook"? → allow stop
11
- # 4. Phase != "execute"? → allow stop
12
- # 5. All tasks done OR "ALL_TASKS_COMPLETE" in transcript? → cleanup + allow stop
13
- # 6. Too many rounds (>100) or too many failures (>3)? → stop + warn
14
- # 7. Otherwise → block and force continue next task
15
-
16
- set -u
17
-
18
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
- . "$SCRIPT_DIR/common.sh"
20
-
21
- DATA_DIR="${CLAUDE_PLUGIN_DATA:-$HOME/.claude/plugins/data/curdx-flow}"
22
-
23
- # ---------- helper: exit with "allow stop" ----------
24
- allow_stop() {
25
- # No output = allow stop normally
26
- exit 0
27
- }
28
-
29
- autonomous_blocking_enabled() {
30
- env_flag_enabled "${CLAUDE_PLUGIN_OPTION_AUTONOMOUS_BLOCKING:-1}"
31
- }
32
-
33
- # ---------- helper: block and inject continuation ----------
34
- block_continue() {
35
- local reason="$1"
36
- emit_stop_block "$reason"
37
- exit 0
38
- }
39
-
40
- # ---------- 1. Must be a flow project ----------
41
- [ ! -d ".flow" ] && allow_stop
42
-
43
- # ---------- 2. Must have active spec ----------
44
- ACTIVE=$(cat .flow/.active-spec 2>/dev/null)
45
- [ -z "$ACTIVE" ] && allow_stop
46
- SPEC_DIR=".flow/specs/$ACTIVE"
47
- [ ! -d "$SPEC_DIR" ] && allow_stop
48
-
49
- STATE_FILE="$SPEC_DIR/.state.json"
50
- [ ! -f "$STATE_FILE" ] && allow_stop
51
-
52
- # ---------- 3-4. Strategy + phase check (use python3 for JSON parsing) ----------
53
- if ! command -v python3 >/dev/null 2>&1; then
54
- # Without python3 we can't safely parse JSON. Allow stop.
55
- allow_stop
56
- fi
57
-
58
- # Export STATE_FILE BEFORE invoking python3 — the heredoc-based parser reads
59
- # os.environ["STATE_FILE"]. Previously the export was placed after the
60
- # heredoc, so python3 always got None, json.load(None) silently failed, and
61
- # the stop-hook strategy never activated.
62
- export STATE_FILE
63
-
64
- read STRATEGY PHASE TASK_INDEX TOTAL_TASKS FAILED ROUNDS RECOVERY_MODE MAX_FIX_TASKS <<EOF
65
- $(python3 <<'PY'
66
- import json, os, sys
67
- p = os.environ.get("STATE_FILE")
68
- try:
69
- s = json.load(open(p))
70
- except Exception:
71
- sys.exit(0)
72
- strategy = s.get("strategy", "auto")
73
- phase = s.get("phase", "")
74
- ex = s.get("execute_state", {}) or {}
75
- ti = ex.get("task_index", 0)
76
- tt = ex.get("total_tasks", 0)
77
- failed = ex.get("failed_attempts", 0)
78
- rounds = ex.get("global_iteration", 0)
79
- recovery_mode = ex.get("recovery_mode", "manual")
80
- max_fix_tasks = ex.get("max_fix_tasks_per_original", 2)
81
- print(strategy, phase, ti, tt, failed, rounds, recovery_mode, max_fix_tasks)
82
- PY
83
- )
84
- EOF
85
-
86
- # Only activate for stop-hook strategy + execute phase
87
- [ "$STRATEGY" != "stop-hook" ] && allow_stop
88
- [ "$PHASE" != "execute" ] && allow_stop
89
-
90
- if ! autonomous_blocking_enabled; then
91
- allow_stop
92
- fi
93
-
94
- # ---------- 5. Check hook input + completion signal in transcript ----------
95
- # Claude Code passes transcript path via stdin as JSON: {"transcript_path": "/path/..."}
96
- # We read stdin to detect ALL_TASKS_COMPLETE or TASK_FAILED
97
- INPUT=$(cat 2>/dev/null || echo "{}")
98
- TRANSCRIPT_PATH=$(echo "$INPUT" | python3 -c 'import json,sys;
99
- try: print(json.load(sys.stdin).get("transcript_path",""))
100
- except: print("")' 2>/dev/null)
101
-
102
- STOP_HOOK_ACTIVE=$(echo "$INPUT" | python3 -c 'import json,sys;
103
- try: print("true" if json.load(sys.stdin).get("stop_hook_active", False) else "false")
104
- except: print("false")' 2>/dev/null)
105
-
106
- if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
107
- # Claude Code sets stop_hook_active during a stop-hook continuation.
108
- # Treat it as context only: the final decision still comes from transcript
109
- # signals, state-file progress, and tasks.md parity. Unconditionally allowing
110
- # stop here can terminate an in-flight stop-hook loop after the first
111
- # continuation, leaving remaining tasks stranded.
112
- echo "[CurDX-Flow stop-hook] stop_hook_active=true; evaluating transcript/state before deciding" >&2
113
- fi
114
-
115
- TRANSCRIPT_TAIL=""
116
- if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
117
- # Read last 50KB only (efficiency)
118
- TRANSCRIPT_TAIL=$(tail -c 51200 "$TRANSCRIPT_PATH" 2>/dev/null || echo "")
119
- fi
120
-
121
- # Python state-file updates: use quoted heredocs (<<'PY') + os.environ so
122
- # the spec-name-derived STATE_FILE path is NEVER interpolated into the
123
- # python source text. Previously a spec name containing single quotes or
124
- # $-signs could break the script or inject arbitrary code.
125
-
126
- # Helper: count unchecked tasks in tasks.md. If tasks.md is absent, return 0
127
- # to avoid blocking recovery for partially-initialized specs.
128
- unchecked_task_count() {
129
- local tasks_file="$SPEC_DIR/tasks.md"
130
- [ ! -f "$tasks_file" ] && { echo 0; return; }
131
- grep -Ec '^- \[ \] \*\*[0-9]+(\.[0-9]+|\.VF|\.X|\.X\+1)*\*\*' "$tasks_file" 2>/dev/null || echo 0
132
- }
133
-
134
- last_task_signal() {
135
- local msg="${1:-}"
136
- printf '%s' "$msg" \
137
- | grep -Eo 'ALL_TASKS_COMPLETE|TASK_(COMPLETE|FAILED):[[:space:]]*[0-9]+(\.([0-9]+|VF|X(\+[0-9]+)?))*' \
138
- | tail -1
139
- }
140
-
141
- failed_task_id() {
142
- local msg="${1:-}"
143
- printf '%s' "$msg" | sed -nE 's/.*TASK_FAILED:[[:space:]]*([0-9]+(\.([0-9]+|VF|X(\+[0-9]+)?))*).*/\1/p' | tail -1
144
- }
145
-
146
- mark_execute_complete() {
147
- python3 <<'PY' 2>/dev/null
148
- import json, os
149
- p = os.environ["STATE_FILE"]
150
- s = json.load(open(p))
151
- s.setdefault("phase_status", {})["execute"] = "completed"
152
- s["phase"] = "verify"
153
- json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
154
- PY
155
- }
156
-
157
- # Check for explicit completion signals
158
- LAST_TASK_SIGNAL="$(last_task_signal "$TRANSCRIPT_TAIL")"
159
-
160
- if [ "$LAST_TASK_SIGNAL" = "ALL_TASKS_COMPLETE" ]; then
161
- UNCHECKED="$(unchecked_task_count)"
162
- if [ "${UNCHECKED:-0}" -gt 0 ]; then
163
- block_continue "[CurDX-Flow stop-hook] ALL_TASKS_COMPLETE was emitted, but tasks.md still has ${UNCHECKED} unchecked task(s). Read .flow/specs/${ACTIVE}/tasks.md, complete only the remaining unchecked tasks, update tasks.md, then emit ALL_TASKS_COMPLETE again."
164
- fi
165
- mark_execute_complete
166
- allow_stop
167
- fi
168
-
169
- # Check for the latest fail signal (accumulate; actual stop decision below)
170
- if printf '%s' "$LAST_TASK_SIGNAL" | grep -q "^TASK_FAILED"; then
171
- FAILED_TASK="$(failed_task_id "$LAST_TASK_SIGNAL")"
172
- [ -z "$FAILED_TASK" ] && FAILED_TASK="the current task"
173
-
174
- # Increment failed_attempts
175
- python3 <<'PY' 2>/dev/null
176
- import json, os
177
- p = os.environ["STATE_FILE"]
178
- s = json.load(open(p))
179
- s.setdefault("execute_state", {})
180
- s["execute_state"]["failed_attempts"] = s["execute_state"].get("failed_attempts", 0) + 1
181
- json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
182
- PY
183
- # Re-read — again via os.environ, no shell interpolation into python.
184
- FAILED=$(python3 -c 'import json, os; print(json.load(open(os.environ["STATE_FILE"]))["execute_state"]["failed_attempts"])' 2>/dev/null || echo 0)
185
-
186
- if [ "${FAILED:-0}" -lt 3 ]; then
187
- if [ "${RECOVERY_MODE:-manual}" = "fix-task" ]; then
188
- block_continue "[CurDX-Flow stop-hook] TASK_FAILED observed for ${FAILED_TASK}. Do not skip it. Recovery mode is fix-task: insert one targeted [FIX ${FAILED_TASK}] task immediately after the failed task in tasks.md (max ${MAX_FIX_TASKS:-2} fix task(s) per original), update .state.json execute_state.fix_task_map, then execute the fix task before retrying ${FAILED_TASK}. The fix task must include Do, Files, Done when, Verify, and Commit fields."
189
- fi
190
-
191
- block_continue "[CurDX-Flow stop-hook] TASK_FAILED observed for ${FAILED_TASK}. Do not advance past the failed task. Re-read tasks.md, perform root-cause analysis, retry the first unchecked task, and emit TASK_COMPLETE only after its Verify command passes. failed_attempts=${FAILED}/3."
192
- fi
193
- fi
194
-
195
- # ---------- 6. Safety brakes ----------
196
- if [ "$FAILED" -ge 3 ]; then
197
- # Too many failures — stop and surface
198
- allow_stop
199
- fi
200
-
201
- if [ "$ROUNDS" -ge 100 ]; then
202
- # Runaway loop protection
203
- allow_stop
204
- fi
205
-
206
- # Check if all tasks done
207
- if [ "$TASK_INDEX" -ge "$TOTAL_TASKS" ] && [ "$TOTAL_TASKS" -gt 0 ]; then
208
- UNCHECKED="$(unchecked_task_count)"
209
- if [ "${UNCHECKED:-0}" -gt 0 ]; then
210
- block_continue "[CurDX-Flow stop-hook] State says execute is complete (${TASK_INDEX}/${TOTAL_TASKS}), but tasks.md still has ${UNCHECKED} unchecked task(s). Continue with the first unchecked task; do not add new tasks."
211
- fi
212
- mark_execute_complete
213
- allow_stop
214
- fi
215
-
216
- # ---------- 7. Block and continue ----------
217
- # Increment round counter
218
- python3 <<'PY' 2>/dev/null
219
- import json, os
220
- p = os.environ["STATE_FILE"]
221
- s = json.load(open(p))
222
- s.setdefault("execute_state", {})
223
- s["execute_state"]["global_iteration"] = s["execute_state"].get("global_iteration", 0) + 1
224
- json.dump(s, open(p, "w"), indent=2, ensure_ascii=False)
225
- PY
226
-
227
- NEXT_INDEX=$((TASK_INDEX + 1))
228
- REASON="[CurDX-Flow stop-hook] Spec '$ACTIVE' has tasks remaining ($TASK_INDEX/$TOTAL_TASKS). Continue to the next task. Dispatch flow-executor for task_id=next. On completion, emit TASK_COMPLETE or TASK_FAILED. When all tasks are done, emit ALL_TASKS_COMPLETE."
229
-
230
- block_continue "$REASON"
@@ -1,159 +0,0 @@
1
- #!/usr/bin/env bash
2
- # CurDX-Flow SubagentStop Hook
3
- # Blocks successful subagent completion if the expected artifact never landed on disk.
4
- #
5
- # Why:
6
- # - long markdown/report-writing agents can truncate near the end of a run
7
- # - users then see a cheerful success summary but the actual file is missing or tiny
8
- # - latest Claude Code hooks expose SubagentStop with agent_type + last_assistant_message,
9
- # which lets us guard only "success-looking" exits while allowing genuine precondition failures
10
-
11
- set -u
12
-
13
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
- . "$SCRIPT_DIR/common.sh"
15
-
16
- INPUT="$(cat 2>/dev/null || echo "{}")"
17
-
18
- if ! has_python3; then
19
- # Without JSON parsing, fail open rather than blocking subagents blindly.
20
- exit 0
21
- fi
22
-
23
- export SUBAGENT_GUARD_INPUT="$INPUT"
24
-
25
- AGENT_TYPE="$(python3 -c 'import json, os
26
- try:
27
- data = json.loads(os.environ["SUBAGENT_GUARD_INPUT"])
28
- print(data.get("agent_type", ""))
29
- except Exception:
30
- print("")
31
- ' 2>/dev/null)"
32
-
33
- LAST_MESSAGE="$(python3 -c 'import json, os
34
- try:
35
- data = json.loads(os.environ["SUBAGENT_GUARD_INPUT"])
36
- print((data.get("last_assistant_message") or "").strip())
37
- except Exception:
38
- print("")
39
- ' 2>/dev/null)"
40
-
41
- looks_like_success() {
42
- local msg="${1:-}"
43
- printf '%s' "$msg" | grep -Eq '(^✓| generated$| generated\n|Wrote |Review complete|Requirements done|Research complete|UI Sketch generation complete|Report:|Next:|TASK_COMPLETE|ALL_TASKS_COMPLETE)'
44
- }
45
-
46
- active_spec_path() {
47
- local file_name="$1"
48
-
49
- [ ! -d ".flow" ] && return 1
50
-
51
- local active
52
- active="$(cat .flow/.active-spec 2>/dev/null)"
53
- [ -z "$active" ] && return 1
54
-
55
- printf '.flow/specs/%s/%s\n' "$active" "$file_name"
56
- }
57
-
58
- completed_task_id() {
59
- local msg="${1:-}"
60
- printf '%s' "$msg" | sed -nE 's/.*TASK_COMPLETE:[[:space:]]*([0-9]+(\.([0-9]+|VF|X(\+[0-9]+)?))*).*/\1/p' | head -1
61
- }
62
-
63
- artifact_target=""
64
- minimum_size=200
65
-
66
- case "$AGENT_TYPE" in
67
- flow-researcher)
68
- artifact_target="$(active_spec_path research.md)" || exit 0
69
- minimum_size=400
70
- ;;
71
- flow-product-designer)
72
- artifact_target="$(active_spec_path requirements.md)" || exit 0
73
- minimum_size=400
74
- ;;
75
- flow-architect)
76
- artifact_target="$(active_spec_path design.md)" || exit 0
77
- minimum_size=400
78
- ;;
79
- flow-planner)
80
- artifact_target="$(active_spec_path tasks.md)" || exit 0
81
- minimum_size=400
82
- ;;
83
- flow-executor)
84
- artifact_target="$(active_spec_path tasks.md)" || exit 0
85
- if printf '%s' "$LAST_MESSAGE" | grep -q 'ALL_TASKS_COMPLETE'; then
86
- exit 0
87
- fi
88
- task_id="$(completed_task_id "$LAST_MESSAGE")"
89
- [ -z "$task_id" ] && exit 0
90
- if grep -Eq "^- \\[x\\] \\*\\*${task_id//./\\.}\\*\\*" "$artifact_target" 2>/dev/null; then
91
- exit 0
92
- fi
93
- emit_subagentstop_block "[CurDX-Flow subagent-artifact-guard] flow-executor emitted TASK_COMPLETE: ${task_id}, but ${artifact_target} does not mark that task as [x]. Update tasks.md and the spec progress/state before stopping."
94
- exit 0
95
- ;;
96
- flow-debugger)
97
- artifact_target="$(active_spec_path debug-report.md)" || exit 0
98
- minimum_size=250
99
- ;;
100
- flow-triage-analyst)
101
- artifact_target="$(active_spec_path triage-report.md)" || exit 0
102
- minimum_size=250
103
- ;;
104
- flow-ux-designer)
105
- artifact_target="$(active_spec_path ui-sketch.md)" || exit 0
106
- minimum_size=250
107
- ;;
108
- flow-reviewer)
109
- artifact_target="$(active_spec_path review-report.md)" || exit 0
110
- minimum_size=300
111
- ;;
112
- flow-verifier)
113
- artifact_target="$(active_spec_path verification-report.md)" || exit 0
114
- minimum_size=300
115
- ;;
116
- flow-security-auditor)
117
- artifact_target="$(active_spec_path security-audit.md)" || exit 0
118
- minimum_size=250
119
- ;;
120
- flow-qa-engineer)
121
- artifact_target="$(active_spec_path qa-report.md)" || exit 0
122
- minimum_size=250
123
- ;;
124
- flow-edge-hunter)
125
- artifact_target="$(active_spec_path edge-cases.md)" || exit 0
126
- minimum_size=250
127
- ;;
128
- flow-adversary)
129
- artifact_target="$(active_spec_path adversarial-review.md)" || exit 0
130
- minimum_size=250
131
- ;;
132
- flow-ui-researcher)
133
- artifact_target="$(active_spec_path ui-research.md)" || exit 0
134
- minimum_size=250
135
- ;;
136
- flow-brownfield-analyst)
137
- artifact_target=".flow/codebase-index.md"
138
- minimum_size=250
139
- ;;
140
- *)
141
- exit 0
142
- ;;
143
- esac
144
-
145
- if [ -f "$artifact_target" ]; then
146
- size="$(wc -c < "$artifact_target" 2>/dev/null | tr -d ' ')"
147
- if [ "${size:-0}" -ge "$minimum_size" ]; then
148
- exit 0
149
- fi
150
- fi
151
-
152
- if ! looks_like_success "$LAST_MESSAGE"; then
153
- # The subagent appears to be stopping because of a real precondition failure,
154
- # clarification request, or other non-success path. Let that response through.
155
- exit 0
156
- fi
157
-
158
- emit_subagentstop_block "[CurDX-Flow subagent-artifact-guard] ${AGENT_TYPE} is stopping with a success summary, but ${artifact_target} is missing or too small. Write the full artifact to disk first, then respond with the minimal completion summary only."
159
- exit 0
@@ -1,105 +0,0 @@
1
- #!/usr/bin/env bash
2
- # CurDX-Flow subagentStatusLine command.
3
- # Reads the official subagent status-line JSON payload from stdin and emits
4
- # one JSON line per CurDX-Flow subagent row that should be overridden.
5
-
6
- set -u
7
-
8
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
- . "$SCRIPT_DIR/common.sh"
10
-
11
- INPUT="$(cat 2>/dev/null || echo "{}")"
12
-
13
- if ! has_python3; then
14
- exit 0
15
- fi
16
-
17
- export CURDX_SUBAGENT_STATUSLINE_INPUT="$INPUT"
18
-
19
- python3 <<'PY'
20
- import json
21
- import os
22
- from pathlib import Path
23
-
24
- try:
25
- data = json.loads(os.environ.get("CURDX_SUBAGENT_STATUSLINE_INPUT", "{}"))
26
- except Exception:
27
- raise SystemExit(0)
28
-
29
- columns = data.get("columns")
30
- try:
31
- columns = int(columns)
32
- except Exception:
33
- columns = 100
34
- columns = max(40, columns)
35
-
36
-
37
- def flow_type(task):
38
- raw = str(task.get("type") or task.get("name") or task.get("label") or "")
39
- if raw.startswith("curdx-flow:"):
40
- raw = raw.split(":", 1)[1]
41
- return raw
42
-
43
-
44
- def is_flow_task(task):
45
- values = [
46
- task.get("type"),
47
- task.get("name"),
48
- task.get("label"),
49
- task.get("description"),
50
- ]
51
- return any(str(value or "").startswith(("flow-", "curdx-flow:flow-")) for value in values)
52
-
53
-
54
- def active_spec(cwd):
55
- if not cwd:
56
- return ""
57
- try:
58
- value = (Path(cwd) / ".flow" / ".active-spec").read_text(encoding="utf-8").strip()
59
- except Exception:
60
- return ""
61
- return value[:40]
62
-
63
-
64
- def token_label(value):
65
- try:
66
- count = int(value)
67
- except Exception:
68
- return ""
69
- if count >= 1000:
70
- return f"{count / 1000:.1f}k tok"
71
- return f"{count} tok"
72
-
73
-
74
- def clamp(text):
75
- if len(text) <= columns:
76
- return text
77
- if columns <= 4:
78
- return text[:columns]
79
- return text[: columns - 3] + "..."
80
-
81
-
82
- for task in data.get("tasks") or []:
83
- if not isinstance(task, dict) or not is_flow_task(task):
84
- continue
85
-
86
- task_id = task.get("id")
87
- if not task_id:
88
- continue
89
-
90
- parts = ["[curdx-flow]", flow_type(task) or "flow-agent"]
91
-
92
- status = str(task.get("status") or "").strip()
93
- if status:
94
- parts.append(status)
95
-
96
- spec = active_spec(task.get("cwd"))
97
- if spec:
98
- parts.append(f"spec:{spec}")
99
-
100
- tokens = token_label(task.get("tokenCount"))
101
- if tokens:
102
- parts.append(tokens)
103
-
104
- print(json.dumps({"id": str(task_id), "content": clamp(" | ".join(parts))}, ensure_ascii=True))
105
- PY
@@ -1,24 +0,0 @@
1
- # Artifact Output Discipline
2
-
3
- Use this discipline for artifact-producing agents that write canonical files
4
- such as `research.md`, `requirements.md`, `design.md`, `tasks.md`, or
5
- `codebase-index.md`.
6
-
7
- ## Core Rules
8
-
9
- 1. Write the artifact first. The first substantive action should be the `Write`
10
- tool call for the final file content.
11
- 2. Do not preview or paraphrase the artifact inline. The file is the
12
- deliverable.
13
- 3. Keep status updates minimal: short bullets or fixed summary lines only.
14
- 4. End with the exact compact output contract defined by the agent-specific
15
- section. No extra explanation before or after it.
16
- 5. If something blocks the write, report the blocker directly instead of
17
- emitting a fake success summary.
18
-
19
- ## Why
20
-
21
- - Prevents context waste from duplicating the artifact in chat
22
- - Makes the written file the canonical output surface
23
- - Keeps artifact-producing subagents consistent across research, product,
24
- architecture, planning, and brownfield mapping
@@ -1,50 +0,0 @@
1
- # Artifact Summary Contracts
2
-
3
- Use these compact summary contracts after an artifact lands successfully. Pair
4
- them with `artifact-output-discipline.md`: write first, no preview, then emit
5
- the exact contract below and stop.
6
-
7
- ## research.md
8
-
9
- ```text
10
- ✓ research.md generated
11
- Recommendations: N
12
- Next: /curdx-flow:spec --phase=requirements
13
- ```
14
-
15
- ## requirements.md
16
-
17
- ```text
18
- ✓ requirements.md generated
19
- User stories: N
20
- Functional requirements: N
21
- Next: /curdx-flow:spec --phase=design
22
- ```
23
-
24
- ## design.md
25
-
26
- ```text
27
- ✓ design.md generated
28
- Architecture decisions: N
29
- Components: N
30
- Next: /curdx-flow:spec --phase=tasks
31
- ```
32
-
33
- ## tasks.md
34
-
35
- ```text
36
- ✓ tasks.md generated
37
- Total tasks: N
38
- Coverage audit: PASS
39
- Phases: 1-5
40
- Next: /curdx-flow:implement
41
- ```
42
-
43
- ## codebase-index.md
44
-
45
- ```text
46
- ✓ codebase-index.md generated
47
- Modules: N
48
- Entry points: N
49
- Next: /curdx-flow:start <feature-name>
50
- ```