@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.
- package/CHANGELOG.md +21 -34
- package/LICENSE +1 -1
- package/README.md +28 -79
- package/dist/index.mjs +995 -0
- package/package.json +33 -42
- package/.claude-plugin/marketplace.json +0 -48
- package/.claude-plugin/plugin.json +0 -70
- package/agent-preamble/preamble.md +0 -314
- package/agents/flow-adversary.md +0 -202
- package/agents/flow-architect.md +0 -197
- package/agents/flow-brownfield-analyst.md +0 -142
- package/agents/flow-debugger.md +0 -321
- package/agents/flow-edge-hunter.md +0 -288
- package/agents/flow-executor.md +0 -269
- package/agents/flow-orchestrator.md +0 -145
- package/agents/flow-planner.md +0 -246
- package/agents/flow-product-designer.md +0 -159
- package/agents/flow-qa-engineer.md +0 -282
- package/agents/flow-researcher.md +0 -165
- package/agents/flow-reviewer.md +0 -303
- package/agents/flow-security-auditor.md +0 -401
- package/agents/flow-triage-analyst.md +0 -272
- package/agents/flow-ui-researcher.md +0 -229
- package/agents/flow-ux-designer.md +0 -221
- package/agents/flow-verifier.md +0 -349
- package/bin/curdx-flow +0 -5
- package/bin/curdx-flow.js +0 -54
- package/cli/README.md +0 -104
- package/cli/doctor-workflow.js +0 -483
- package/cli/doctor.js +0 -73
- package/cli/help.js +0 -59
- package/cli/install-bundled-mcps.js +0 -37
- package/cli/install-companions.js +0 -19
- package/cli/install-context7-config.js +0 -80
- package/cli/install-curdx-plugin.js +0 -96
- package/cli/install-language.js +0 -35
- package/cli/install-next-steps.js +0 -29
- package/cli/install-options.js +0 -9
- package/cli/install-paths.js +0 -52
- package/cli/install-recommended-plugins.js +0 -104
- package/cli/install-required-plugins.js +0 -57
- package/cli/install-self-update.js +0 -62
- package/cli/install-workflow.js +0 -209
- package/cli/install.js +0 -101
- package/cli/lib/claude-commands.js +0 -41
- package/cli/lib/claude-ops.js +0 -47
- package/cli/lib/claude.js +0 -183
- package/cli/lib/config.js +0 -24
- package/cli/lib/doctor-claude-settings.js +0 -1186
- package/cli/lib/doctor-report.js +0 -978
- package/cli/lib/doctor-runtime-environment.js +0 -196
- package/cli/lib/frontmatter.js +0 -44
- package/cli/lib/json-schema.js +0 -57
- package/cli/lib/logging.js +0 -25
- package/cli/lib/process.js +0 -60
- package/cli/lib/prompts.js +0 -135
- package/cli/lib/runtime.js +0 -107
- package/cli/lib/semver.js +0 -109
- package/cli/lib/version.js +0 -12
- package/cli/protocols-body.md +0 -22
- package/cli/protocols.js +0 -162
- package/cli/registry.js +0 -123
- package/cli/router.js +0 -49
- package/cli/uninstall-actions.js +0 -360
- package/cli/uninstall-workflow.js +0 -146
- package/cli/uninstall.js +0 -42
- package/cli/upgrade-workflow.js +0 -80
- package/cli/upgrade.js +0 -91
- package/cli/utils.js +0 -40
- package/gates/adversarial-review-gate.md +0 -219
- package/gates/coverage-audit-gate.md +0 -182
- package/gates/devex-gate.md +0 -254
- package/gates/edge-case-gate.md +0 -194
- package/gates/karpathy-gate.md +0 -130
- package/gates/security-gate.md +0 -218
- package/gates/tdd-gate.md +0 -182
- package/gates/test-quality-gate.md +0 -59
- package/gates/verification-gate.md +0 -179
- package/hooks/hooks.json +0 -58
- package/hooks/scripts/common.sh +0 -46
- package/hooks/scripts/inject-karpathy.sh +0 -53
- package/hooks/scripts/quick-mode-guard.sh +0 -68
- package/hooks/scripts/session-start.sh +0 -90
- package/hooks/scripts/stop-watcher.sh +0 -230
- package/hooks/scripts/subagent-artifact-guard.sh +0 -159
- package/hooks/scripts/subagent-statusline.sh +0 -105
- package/knowledge/artifact-output-discipline.md +0 -24
- package/knowledge/artifact-summary-contracts.md +0 -50
- package/knowledge/atomic-commits.md +0 -262
- package/knowledge/claude-code-runtime-contracts.md +0 -219
- package/knowledge/epic-decomposition.md +0 -307
- package/knowledge/execution-strategies.md +0 -303
- package/knowledge/karpathy-guidelines.md +0 -219
- package/knowledge/planning-reviews.md +0 -211
- package/knowledge/poc-first-workflow.md +0 -223
- package/knowledge/review-feedback-intake.md +0 -57
- package/knowledge/spec-driven-development.md +0 -180
- package/knowledge/systematic-debugging.md +0 -378
- package/knowledge/two-stage-review.md +0 -249
- package/knowledge/wave-execution.md +0 -403
- package/monitors/monitors.json +0 -8
- package/monitors/scripts/flow-state-monitor.sh +0 -99
- package/output-styles/curdx-evidence-first.md +0 -34
- package/schemas/agent-frontmatter.schema.json +0 -63
- package/schemas/config.schema.json +0 -134
- package/schemas/gate-frontmatter.schema.json +0 -30
- package/schemas/hooks.schema.json +0 -115
- package/schemas/output-style-frontmatter.schema.json +0 -22
- package/schemas/plugin-manifest.schema.json +0 -436
- package/schemas/plugin-settings.schema.json +0 -29
- package/schemas/skill-frontmatter.schema.json +0 -177
- package/schemas/spec-frontmatter.schema.json +0 -42
- package/schemas/spec-state.schema.json +0 -147
- package/settings.json +0 -7
- package/skills/brownfield-index/SKILL.md +0 -53
- package/skills/brownfield-index/references/applicability.md +0 -12
- package/skills/brownfield-index/references/handoff.md +0 -8
- package/skills/brownfield-index/references/index-contract.md +0 -10
- package/skills/browser-qa/SKILL.md +0 -39
- package/skills/browser-qa/references/handoff.md +0 -6
- package/skills/browser-qa/references/prerequisites.md +0 -10
- package/skills/browser-qa/references/qa-contract.md +0 -20
- package/skills/cancel/SKILL.md +0 -41
- package/skills/cancel/references/destructive-mode.md +0 -17
- package/skills/cancel/references/reporting.md +0 -18
- package/skills/cancel/references/state-recovery.md +0 -30
- package/skills/cancel/references/target-resolution.md +0 -7
- package/skills/debug/SKILL.md +0 -45
- package/skills/debug/references/context-gathering.md +0 -11
- package/skills/debug/references/failure-guard.md +0 -25
- package/skills/debug/references/intake.md +0 -12
- package/skills/debug/references/phase-workflow.md +0 -34
- package/skills/debug/references/reporting.md +0 -20
- package/skills/epic/SKILL.md +0 -39
- package/skills/epic/references/epic-artifacts.md +0 -20
- package/skills/epic/references/epic-intake.md +0 -9
- package/skills/epic/references/slice-handoff.md +0 -16
- package/skills/fast/SKILL.md +0 -62
- package/skills/fast/references/applicability.md +0 -25
- package/skills/fast/references/clarification.md +0 -20
- package/skills/fast/references/execution-contract.md +0 -56
- package/skills/help/SKILL.md +0 -55
- package/skills/help/references/dispatch.md +0 -20
- package/skills/help/references/overview.md +0 -39
- package/skills/help/references/troubleshoot.md +0 -47
- package/skills/help/references/workflow.md +0 -37
- package/skills/implement/SKILL.md +0 -96
- package/skills/implement/references/error-recovery.md +0 -36
- package/skills/implement/references/linear-execution.md +0 -32
- package/skills/implement/references/preflight.md +0 -43
- package/skills/implement/references/progress-contract.md +0 -32
- package/skills/implement/references/state-init.md +0 -33
- package/skills/implement/references/stop-hook-execution.md +0 -36
- package/skills/implement/references/strategy-router.md +0 -38
- package/skills/implement/references/subagent-execution.md +0 -43
- package/skills/implement/references/wave-execution.md +0 -162
- package/skills/init/SKILL.md +0 -49
- package/skills/init/references/gitignore-and-health.md +0 -26
- package/skills/init/references/next-steps.md +0 -22
- package/skills/init/references/preflight.md +0 -15
- package/skills/init/references/scaffold-contract.md +0 -27
- package/skills/review/SKILL.md +0 -82
- package/skills/review/references/optional-passes.md +0 -48
- package/skills/review/references/preflight.md +0 -38
- package/skills/review/references/report-contract.md +0 -49
- package/skills/review/references/reporting.md +0 -20
- package/skills/review/references/stage-execution.md +0 -32
- package/skills/security-audit/SKILL.md +0 -47
- package/skills/security-audit/references/audit-contract.md +0 -21
- package/skills/security-audit/references/gate-handoff.md +0 -8
- package/skills/security-audit/references/scope-and-depth.md +0 -9
- package/skills/spec/SKILL.md +0 -100
- package/skills/spec/references/artifact-landing.md +0 -31
- package/skills/spec/references/phase-execution.md +0 -50
- package/skills/spec/references/planning-review.md +0 -31
- package/skills/spec/references/preflight-and-routing.md +0 -46
- package/skills/spec/references/reporting.md +0 -21
- package/skills/start/SKILL.md +0 -84
- package/skills/start/references/branch-routing.md +0 -51
- package/skills/start/references/mode-semantics.md +0 -12
- package/skills/start/references/preflight.md +0 -13
- package/skills/start/references/reporting.md +0 -20
- package/skills/start/references/state-seeding.md +0 -44
- package/skills/start/references/workflow-handoff.md +0 -26
- package/skills/status/SKILL.md +0 -41
- package/skills/status/references/gather-contract.md +0 -27
- package/skills/status/references/health-rules.md +0 -27
- package/skills/status/references/output-contract.md +0 -24
- package/skills/status/references/preflight.md +0 -10
- package/skills/status/references/recovery-hints.md +0 -18
- package/skills/ui-sketch/SKILL.md +0 -39
- package/skills/ui-sketch/references/brief-intake.md +0 -10
- package/skills/ui-sketch/references/iteration-handoff.md +0 -5
- package/skills/ui-sketch/references/variant-contract.md +0 -15
- package/skills/verify/SKILL.md +0 -56
- package/skills/verify/references/evidence-workflow.md +0 -39
- package/skills/verify/references/output-contract.md +0 -23
- package/skills/verify/references/preflight.md +0 -11
- package/skills/verify/references/report-handoff.md +0 -35
- package/skills/verify/references/strict-mode.md +0 -12
- package/templates/CONTEXT.md.tmpl +0 -53
- package/templates/PROJECT.md.tmpl +0 -59
- package/templates/ROADMAP.md.tmpl +0 -50
- package/templates/STATE.md.tmpl +0 -49
- package/templates/config.json.tmpl +0 -51
- package/templates/design.md.tmpl +0 -83
- package/templates/progress.md.tmpl +0 -77
- package/templates/requirements.md.tmpl +0 -76
- package/templates/research.md.tmpl +0 -83
- 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
|
-
```
|