@curdx/flow 2.0.21 → 2.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.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Install required Claude Code companion plugins (today: context7-plugin).
3
+ * Post-install, dispatches Context7 API-key configuration if applicable.
4
+ */
5
+
6
+ import { addPluginMarketplace, installPlugin } from "./lib/claude-ops.js";
7
+ import { REQUIRED_PLUGINS } from "./registry.js";
8
+ import { color, log, resultLastLine } from "./utils.js";
9
+ import { installContext7Config } from "./install-context7-config.js";
10
+
11
+ export async function installRequiredPlugins({ yes, language, config }) {
12
+ log.blank();
13
+ log.info("Installing required Claude Code plugins...");
14
+ for (const plugin of REQUIRED_PLUGINS) {
15
+ console.log(` ${color.cyan("▸")} Installing ${color.bold(plugin.name)}...`);
16
+ const ma = await addPluginMarketplace(plugin);
17
+ if (ma.code !== 0 && !ma.stderr.includes("already")) {
18
+ log.warn(` marketplace add warning: ${ma.stderr.trim().split("\n")[0]}`);
19
+ }
20
+
21
+ const ir = await installPlugin(plugin);
22
+ if (ir.code === 0) {
23
+ console.log(` ${color.green("✓")} ${plugin.name} installed`);
24
+
25
+ if (plugin.requiresConfig && plugin.configType === "apiKey" && !yes) {
26
+ await installContext7Config(plugin, language, config);
27
+ }
28
+ } else {
29
+ console.log(
30
+ ` ${color.red("✗")} ${plugin.name} install failed: ${resultLastLine(ir)}`
31
+ );
32
+ console.log(
33
+ color.dim(
34
+ ` Run manually: claude plugin marketplace add --scope ${plugin.scope} ${plugin.marketplaceSource}`
35
+ )
36
+ );
37
+ console.log(
38
+ color.dim(
39
+ ` Then: claude plugin install --scope ${plugin.scope} ${plugin.installSpec}`
40
+ )
41
+ );
42
+ }
43
+ }
44
+ }
@@ -3,10 +3,11 @@
3
3
  All operations MUST strictly follow these system constraints:
4
4
 
5
5
  ### Language separation
6
- - **Tool / persistence layer = English**: commit messages, code, comments, file names, function names, PR descriptions, CLI log output, error messages thrown by code, and any artifact persisted to the repository or shown in a developer terminal.
6
+ - **Tool / persistence layer = English**: commit messages, code, comments, file names, function names, PR descriptions, error messages thrown by code, and any artifact persisted to the repository or consumed by agents / skills / hooks at runtime.
7
7
  - **Conversational layer = Simplified Chinese**: chat replies, explanations and reasoning shown directly to the human in a conversation interface (e.g. Claude Code chat).
8
+ - **Installer UX (`cli/` only, narrow carve-out)**: interactive menus printed by the npm-published installer under `cli/**` may present localized Chinese options because they serve a human operator at install time. This carve-out does NOT apply to `agents/`, `skills/`, `commands/`, `gates/`, `hooks/`, `knowledge/`, documentation, or any prose consumed by agents at runtime — those stay English.
8
9
 
9
- Rationale: English in the persistence/tool layer aligns with developer-tool industry norms (npm/git/cargo are all English) and keeps the codebase internationally collaborable. Chinese in the conversational layer matches the user's language preference. Mixing the two (e.g. Chinese commit messages, Chinese CLI log output) is a violation.
10
+ Rationale: English in the persistence / tool / agent-input layer aligns with developer-tool industry norms (npm/git/cargo are all English) and keeps AI / agent adaptation reliable. Chinese in the conversational layer matches the user's language preference. The installer carve-out reflects the fact that installer menus are a human-to-human interaction surface, not agent input. Mixing the two (e.g. Chinese commit messages, Chinese strings inside agent prompts) is a violation.
10
11
 
11
12
  ### Discovery & reasoning
12
13
  - **Library / framework / API questions**: query `context7` MCP first. Do not rely on training memory.
@@ -32,9 +32,12 @@ if [ "$LAST_CHECK" != "$TODAY" ]; then
32
32
  if command -v claude >/dev/null 2>&1; then
33
33
  INSTALLED="$(claude plugin list 2>/dev/null || true)"
34
34
 
35
- echo "$INSTALLED" | grep -q 'pua' || MISSING+=("pua")
36
- echo "$INSTALLED" | grep -q 'claude-mem' || MISSING+=("claude-mem")
37
- echo "$INSTALLED" | grep -q 'frontend-design' || MISSING+=("frontend-design")
35
+ # Names must stay in lockstep with cli/registry.js RECOMMENDED_PLUGINS.
36
+ # Drift is guarded by test/registry-session-start-parity.test.js.
37
+ echo "$INSTALLED" | grep -q 'pua' || MISSING+=("pua")
38
+ echo "$INSTALLED" | grep -q 'claude-mem' || MISSING+=("claude-mem")
39
+ echo "$INSTALLED" | grep -q 'frontend-design' || MISSING+=("frontend-design")
40
+ echo "$INSTALLED" | grep -q 'chrome-devtools-mcp' || MISSING+=("chrome-devtools-mcp")
38
41
  fi
39
42
 
40
43
  if [ "${#MISSING[@]}" -gt 0 ]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curdx/flow",
3
- "version": "2.0.21",
3
+ "version": "2.1.0",
4
4
  "description": "CLI installer for CurdX-Flow — AI engineering workflow meta-framework for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,6 @@
16
16
  ".claude-plugin/",
17
17
  "agents/",
18
18
  "gates/",
19
- "commands/",
20
19
  "hooks/",
21
20
  "knowledge/",
22
21
  "agent-preamble/",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "mode": {
15
15
  "type": "string",
16
- "enum": ["sketch", "fast", "standard", "enterprise", "autonomous"],
16
+ "enum": ["fast", "standard", "enterprise"],
17
17
  "description": "Default workflow depth for this project"
18
18
  },
19
19
  "execution": {
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "mode": {
23
23
  "type": "string",
24
- "enum": ["sketch", "fast", "standard", "enterprise", "autonomous"],
24
+ "enum": ["fast", "standard", "enterprise"],
25
25
  "default": "standard"
26
26
  },
27
27
  "strategy": {
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: debug
3
+ description: Systematic debugging — 4-phase methodology (root cause → pattern → hypothesis → fix); three failures trigger architectural questioning. Routes to flow-debugger.
4
+ argument-hint: "\"<bug description>\""
5
+ context: fork
6
+ agent: flow-debugger
7
+ ---
8
+
9
+ # Systematic Debug
10
+
11
+ Debug the bug described below using the 4-phase methodology in
12
+ `@${CLAUDE_PLUGIN_ROOT}/knowledge/systematic-debugging.md`. This is NOT
13
+ "retry until green" — each phase has a stop condition.
14
+
15
+ **Bug description**: `$ARGUMENTS`
16
+
17
+ If `$ARGUMENTS` is empty, print `Usage: /curdx-flow:debug "<bug description>"` and stop.
18
+
19
+ ## Context to gather before diagnosing
20
+
21
+ - Recent commits: `git log --oneline -20`
22
+ - Uncommitted changes: `git status --short`, `git diff --stat`
23
+ - Active spec (if any): read `.flow/.active-spec`; if set, read
24
+ `.flow/specs/<active>/.progress.md` for related history.
25
+
26
+ ## Phase 1 — Root-cause investigation
27
+
28
+ - Read the error carefully (stack trace + message + location).
29
+ - Build a minimal reproduction.
30
+ - Check recent changes that could have introduced the bug.
31
+ - Trace the data flow from cause to symptom.
32
+ - **Exit condition**: state the root cause in **one sentence**.
33
+ "maybe it's..." is not allowed.
34
+
35
+ ## Phase 2 — Pattern analysis
36
+
37
+ - Find a working counter-example in the codebase (same path, different
38
+ input or neighboring module that behaves correctly).
39
+ - Pinpoint the difference from the failing case.
40
+ - Classify: **isolated case** (one location) vs. **systemic pattern**
41
+ (multiple siblings). If systemic, Phase 4 must sweep for siblings.
42
+
43
+ ## Phase 3 — Hypothesis and test
44
+
45
+ - State ONE hypothesis.
46
+ - Write the smallest test that distinguishes confirm vs. disprove.
47
+ - Run the test in-memory (do not commit yet).
48
+ - If disproved, return to Phase 1 with the new signal.
49
+
50
+ ## Phase 4 — Implement the fix
51
+
52
+ 1. Write a failing test; confirm it fails. Commit `test(<scope>): red - ...`.
53
+ 2. Fix the root cause (not the symptom). Confirm the failing test now
54
+ passes. Commit `fix(<scope>): green - ...`.
55
+ 3. Run the full regression suite; no regressions allowed.
56
+ 4. If Phase 2 classified as systemic, sweep for sibling occurrences and
57
+ fix them in the same stage. Optional third commit
58
+ `fix(<scope>): sweep - N similar cases`.
59
+
60
+ ## Three-failure guard (hard stop)
61
+
62
+ If Phase 4 has tried 3 genuinely different approaches and all failed,
63
+ **stop**. Do not try a 4th. Output the structured failure report:
64
+
65
+ ```
66
+ ⚠ Systematic debug halted after 3 attempts
67
+
68
+ Attempts:
69
+ 1. <approach 1>: <why it failed>
70
+ 2. <approach 2>: <why it failed>
71
+ 3. <approach 3>: <why it failed>
72
+
73
+ Root-issue hypothesis: architecture | dependency | data | unknown
74
+ Recommended next step: <user action — review architecture, ship a
75
+ STATE.md D-NN deferral with @ts-expect-error,
76
+ or request pairing>
77
+ ```
78
+
79
+ ## Forbidden
80
+
81
+ - Prayer-driven programming (retry without a new hypothesis each round)
82
+ - "Maybe it's ..." as a Phase 1 conclusion
83
+ - A fix commit without a corresponding failing-test commit
84
+ - Masking the root cause with null checks / try-catch
85
+ - Fixing multiple unrelated things in one commit (one task = one commit)
86
+
87
+ ## Output to user (on success, ≤ 15 lines)
88
+
89
+ ```
90
+ ✓ Debug complete
91
+
92
+ Root cause: <Phase 1 — one sentence>
93
+ Pattern: <Phase 2 — isolated or systemic>
94
+
95
+ Fix commits:
96
+ - <sha>: test(<scope>): red - failing test
97
+ - <sha>: fix(<scope>): green - root-cause fix
98
+ - <sha>: fix(<scope>): sweep - N sibling cases (if systemic)
99
+
100
+ Verification: failing test now PASS ✓; full suite green ✓
101
+
102
+ Learnings (candidate for .progress.md):
103
+ - <lesson>
104
+ ```
@@ -48,15 +48,24 @@ Show the 9 core slash commands + 5 auto-invoked skills. Keep the table compact,
48
48
 
49
49
  ## `<command-name>` — command detail
50
50
 
51
- When the argument matches one of the 9 commands, read the corresponding `commands/<name>.md` from the plugin cache and present it cleanly:
51
+ When the argument matches a slash name — one of the 9 primary workflows or one of the 5 auto-invoked skills — read the corresponding body and present it cleanly. The lookup tries the `skills/` layout first and falls back to the legacy `commands/` layout, which keeps help correct throughout the Phase 3 migration window:
52
52
 
53
53
  ```bash
54
- PLUGIN=$(ls -dt "$HOME/.claude/plugins/cache/curdx-flow-marketplace/curdx-flow/"*/ 2>/dev/null | head -1)
55
- CMD="$1"
56
- cat "$PLUGIN/commands/$CMD.md"
54
+ CMD="$ARGUMENTS"
55
+ [ -z "$CMD" ] && { echo "Usage: /curdx-flow:help <name>"; exit 1; }
56
+ if [ -f "${CLAUDE_PLUGIN_ROOT}/skills/${CMD}/SKILL.md" ]; then
57
+ cat "${CLAUDE_PLUGIN_ROOT}/skills/${CMD}/SKILL.md"
58
+ elif [ -f "${CLAUDE_PLUGIN_ROOT}/commands/${CMD}.md" ]; then
59
+ cat "${CLAUDE_PLUGIN_ROOT}/commands/${CMD}.md"
60
+ else
61
+ echo "Unknown: ${CMD}"
62
+ echo "Workflows: init start spec implement verify review fast debug help"
63
+ echo "Skills: epic browser-qa ui-sketch security-audit brownfield-index"
64
+ exit 1
65
+ fi
57
66
  ```
58
67
 
59
- If the argument isn't a known command, list the 9 candidates and the 5 skill names.
68
+ If the argument isn't a known slash name, the block above prints the 14 candidates.
60
69
 
61
70
  ## `workflow` — standard workflow
62
71
 
@@ -159,160 +159,19 @@ After the agent completes, read the output marker:
159
159
 
160
160
  ### Strategy: wave
161
161
 
162
- @${CLAUDE_PLUGIN_ROOT}/knowledge/wave-execution.md
162
+ See `skills/implement/references/wave-execution.md` for the full walkthrough.
163
+ Knowledge-layer canonical algorithm: `@${CLAUDE_PLUGIN_ROOT}/knowledge/wave-execution.md`.
163
164
 
164
- **Core**: consecutive `[P]` tasks form a wave, dispatch multiple Tasks in parallel within a single message, serial across waves.
165
+ **Core**: consecutive `[P]` tasks form a wave; dispatch multiple Tasks in parallel within a single response; serial across waves. The execution loop is:
165
166
 
166
- #### Step 1: DAG Analysis
167
+ 1. **DAG analysis** — group remaining `[ ]` tasks by `[P]` / `[SEQUENTIAL]` / `[VERIFY]` tags; conflicting `Files` sets split into a new wave.
168
+ 2. **Pre-conflict detection** — within each wave, assert per-task `Files` are disjoint; auto-split if not.
169
+ 3. **Dispatch** — list multiple `Task(...)` tool calls in a single main-agent response (splitting across responses = serial degradation; nested `Task` dispatches forbidden). Each Task prompt follows the subagent strategy's uniform format (see `references/wave-execution.md` Step 3).
170
+ 4. **Aggregate** — parse each result for `TASK_COMPLETE` / `TASK_FAILED`; run post-hoc conflict detection via git diff to confirm executors only touched declared files.
171
+ 5. **Failure handling** — 0 failed → next wave; 1 failed → `config.wave_fail_policy` (`continue-on-single` or `stop-on-any`); ≥2 failed → likely environment issue, stop immediately; cumulative `failed_attempts >= 3` → stop, user intervention.
172
+ 6. **Progress feedback** — print a wave summary after each wave (see `references/wave-execution.md` Step 6).
167
173
 
168
- Read remaining `[ ]` tasks from tasks.md and group per the rules:
169
-
170
- ```
171
- for task in remaining tasks:
172
- if task has [SEQUENTIAL] or [VERIFY]:
173
- → own wave (breaks parallelism)
174
- elif task has [P]:
175
- → check whether Files conflict with current_wave
176
- conflict → start a new wave
177
- no conflict → add to current_wave
178
- else:
179
- → own wave (no [P] = serial)
180
- ```
181
-
182
- Output wave list:
183
- ```
184
- Wave 1 [P×3]: 1.1 1.2 1.3
185
- Wave 2 [VERIFY]: 1.4
186
- Wave 3: 1.5
187
- Wave 4 [P×2]: 1.6 1.7
188
- ```
189
-
190
- #### Step 2: Pre-Conflict Detection
191
-
192
- For each wave, verify that Files across all tasks are **disjoint**:
193
-
194
- ```python
195
- for wave in waves:
196
- all_files = []
197
- for task in wave:
198
- if set(task.files) & set(all_files):
199
- warn(f"Within wave, {task.id} modifies the same file as a prior task")
200
- # split into the next wave
201
- all_files.extend(task.files)
202
- ```
203
-
204
- If the planner mis-tagged `[P]` (modifies the same file), split the wave automatically at execution time rather than failing outright.
205
-
206
- #### Step 3: Dispatch a Single Wave (**key: within a single response**)
207
-
208
- ```
209
- # List multiple Task tool calls in one response of the main agent:
210
- Task(description="Execute 1.1", prompt=<...flow-executor + task_id=1.1...>)
211
- Task(description="Execute 1.2", prompt=<...flow-executor + task_id=1.2...>)
212
- Task(description="Execute 1.3", prompt=<...flow-executor + task_id=1.3...>)
213
- ```
214
-
215
- Each Task prompt follows a uniform format (similar to subagent strategy):
216
-
217
- ```
218
- You are the flow-executor agent. Full definition:
219
- ${CLAUDE_PLUGIN_ROOT}/agents/flow-executor.md
220
-
221
- Execute a single task:
222
- spec_name: $SPEC_NAME
223
- task_id: <specific ID, e.g., 1.2>
224
- quick_mode: $QUICK
225
-
226
- **You may only modify the following files** (touching anything else is disallowed):
227
- <task.files>
228
-
229
- Required reading:
230
- - .flow/specs/$SPEC_NAME/tasks.md
231
- - .flow/specs/$SPEC_NAME/.state.json
232
- - .flow/specs/$SPEC_NAME/design.md (if referencing AD-NN)
233
-
234
- Output:
235
- - TASK_COMPLETE: <task_id> or
236
- - TASK_FAILED: <task_id> + reason
237
- ```
238
-
239
- **Not allowed**:
240
- - Splitting multiple Task calls across multiple responses (that is serial degradation)
241
- - Nesting another Task dispatch inside a Task
242
-
243
- #### Step 4: Aggregate Wave Results
244
-
245
- Wait for all Tasks to return:
246
-
247
- ```python
248
- completed = []; failed = []
249
- for task, result in zip(wave, results):
250
- if "TASK_COMPLETE" in result:
251
- completed.append(task)
252
- elif "TASK_FAILED" in result:
253
- failed.append(task)
254
-
255
- # Post-hoc conflict detection (verify executors did not touch out-of-scope files)
256
- for task in completed:
257
- actual_files = git_diff_files_touched_by(task)
258
- declared = set(task.files)
259
- unexpected = actual_files - declared
260
- if unexpected:
261
- warn(f"Task {task.id} modified undeclared files: {unexpected}")
262
- ```
263
-
264
- #### Step 5: Wave Failure Handling
265
-
266
- ```
267
- len(failed) == 0:
268
- → continue to the next wave
269
-
270
- len(failed) == 1:
271
- → failed_attempts += 1
272
- → based on config.wave_fail_policy:
273
- "continue-on-single": continue to the next wave, report failure at the end
274
- "stop-on-any": stop immediately
275
-
276
- len(failed) >= 2:
277
- → likely environment issue (missing deps/tsc error/permissions)
278
- → stop immediately, suggest npx @curdx/flow doctor
279
-
280
- failed_attempts >= 3 (cumulative):
281
- → stop, user intervention required
282
- ```
283
-
284
- #### Step 6: Progress Feedback
285
-
286
- ```
287
- ▶ Wave 2/5 complete
288
- ✓ 1.1 feat(auth): create module skeleton (abc123)
289
- ✓ 1.2 feat(user): create user types (def456)
290
- ✓ 1.3 feat(session): init token module (ghi789)
291
-
292
- ▶ Wave 3/5 starting (VERIFY)...
293
- ```
294
-
295
- #### Configuration
296
-
297
- `.flow/config.json`:
298
- ```json
299
- {
300
- "execution": {
301
- "strategy": "wave",
302
- "max_parallel": 5,
303
- "wave_fail_policy": "continue-on-single"
304
- }
305
- }
306
- ```
307
-
308
- - `max_parallel`: max N parallel within a wave (to avoid API rate limits, default 5)
309
- - `wave_fail_policy`: single-task failure behavior
310
-
311
- #### Pitfalls (see knowledge/wave-execution.md for the detailed version)
312
-
313
- - Stray `[P]` → conflict detection as a safety net
314
- - Wave too large → max_parallel auto-splits
315
- - Implicit read-write dependencies → planner should avoid this kind of `[P]`
174
+ Configuration under `.flow/config.json.execution`: `strategy: "wave"`, `max_parallel: 5` (wave-parallel ceiling), `wave_fail_policy: "continue-on-single" | "stop-on-any"`.
316
175
 
317
176
  ### Strategy: stop-hook
318
177
 
@@ -0,0 +1,162 @@
1
+ # Wave Execution Strategy — Detailed Walkthrough
2
+
3
+ Skill-scoped reference for `skills/implement/SKILL.md`. Loaded only when the
4
+ implement skill routes to the `wave` strategy. The knowledge-layer canonical
5
+ algorithm lives in `@${CLAUDE_PLUGIN_ROOT}/knowledge/wave-execution.md`;
6
+ this file is the walkthrough the skill itself embeds for implementers.
7
+
8
+ **Core**: consecutive `[P]` tasks form a wave, dispatch multiple Tasks in
9
+ parallel within a single message, serial across waves.
10
+
11
+ ## Step 1: DAG Analysis
12
+
13
+ Read remaining `[ ]` tasks from tasks.md and group per the rules:
14
+
15
+ ```
16
+ for task in remaining tasks:
17
+ if task has [SEQUENTIAL] or [VERIFY]:
18
+ → own wave (breaks parallelism)
19
+ elif task has [P]:
20
+ → check whether Files conflict with current_wave
21
+ conflict → start a new wave
22
+ no conflict → add to current_wave
23
+ else:
24
+ → own wave (no [P] = serial)
25
+ ```
26
+
27
+ Output wave list:
28
+ ```
29
+ Wave 1 [P×3]: 1.1 1.2 1.3
30
+ Wave 2 [VERIFY]: 1.4
31
+ Wave 3: 1.5
32
+ Wave 4 [P×2]: 1.6 1.7
33
+ ```
34
+
35
+ ## Step 2: Pre-Conflict Detection
36
+
37
+ For each wave, verify that Files across all tasks are **disjoint**:
38
+
39
+ ```python
40
+ for wave in waves:
41
+ all_files = []
42
+ for task in wave:
43
+ if set(task.files) & set(all_files):
44
+ warn(f"Within wave, {task.id} modifies the same file as a prior task")
45
+ # split into the next wave
46
+ all_files.extend(task.files)
47
+ ```
48
+
49
+ If the planner mis-tagged `[P]` (modifies the same file), split the wave automatically at execution time rather than failing outright.
50
+
51
+ ## Step 3: Dispatch a Single Wave (key: within a single response)
52
+
53
+ ```
54
+ # List multiple Task tool calls in one response of the main agent:
55
+ Task(description="Execute 1.1", prompt=<...flow-executor + task_id=1.1...>)
56
+ Task(description="Execute 1.2", prompt=<...flow-executor + task_id=1.2...>)
57
+ Task(description="Execute 1.3", prompt=<...flow-executor + task_id=1.3...>)
58
+ ```
59
+
60
+ Each Task prompt follows a uniform format (similar to subagent strategy):
61
+
62
+ ```
63
+ You are the flow-executor agent. Full definition:
64
+ ${CLAUDE_PLUGIN_ROOT}/agents/flow-executor.md
65
+
66
+ Execute a single task:
67
+ spec_name: $SPEC_NAME
68
+ task_id: <specific ID, e.g., 1.2>
69
+ quick_mode: $QUICK
70
+
71
+ **You may only modify the following files** (touching anything else is disallowed):
72
+ <task.files>
73
+
74
+ Required reading:
75
+ - .flow/specs/$SPEC_NAME/tasks.md
76
+ - .flow/specs/$SPEC_NAME/.state.json
77
+ - .flow/specs/$SPEC_NAME/design.md (if referencing AD-NN)
78
+
79
+ Output:
80
+ - TASK_COMPLETE: <task_id> or
81
+ - TASK_FAILED: <task_id> + reason
82
+ ```
83
+
84
+ **Not allowed**:
85
+ - Splitting multiple Task calls across multiple responses (that is serial degradation)
86
+ - Nesting another Task dispatch inside a Task
87
+
88
+ ## Step 4: Aggregate Wave Results
89
+
90
+ Wait for all Tasks to return:
91
+
92
+ ```python
93
+ completed = []; failed = []
94
+ for task, result in zip(wave, results):
95
+ if "TASK_COMPLETE" in result:
96
+ completed.append(task)
97
+ elif "TASK_FAILED" in result:
98
+ failed.append(task)
99
+
100
+ # Post-hoc conflict detection (verify executors did not touch out-of-scope files)
101
+ for task in completed:
102
+ actual_files = git_diff_files_touched_by(task)
103
+ declared = set(task.files)
104
+ unexpected = actual_files - declared
105
+ if unexpected:
106
+ warn(f"Task {task.id} modified undeclared files: {unexpected}")
107
+ ```
108
+
109
+ ## Step 5: Wave Failure Handling
110
+
111
+ ```
112
+ len(failed) == 0:
113
+ → continue to the next wave
114
+
115
+ len(failed) == 1:
116
+ → failed_attempts += 1
117
+ → based on config.wave_fail_policy:
118
+ "continue-on-single": continue to the next wave, report failure at the end
119
+ "stop-on-any": stop immediately
120
+
121
+ len(failed) >= 2:
122
+ → likely environment issue (missing deps/tsc error/permissions)
123
+ → stop immediately, suggest npx @curdx/flow doctor
124
+
125
+ failed_attempts >= 3 (cumulative):
126
+ → stop, user intervention required
127
+ ```
128
+
129
+ ## Step 6: Progress Feedback
130
+
131
+ ```
132
+ ▶ Wave 2/5 complete
133
+ ✓ 1.1 feat(auth): create module skeleton (abc123)
134
+ ✓ 1.2 feat(user): create user types (def456)
135
+ ✓ 1.3 feat(session): init token module (ghi789)
136
+
137
+ ▶ Wave 3/5 starting (VERIFY)...
138
+ ```
139
+
140
+ ## Configuration
141
+
142
+ `.flow/config.json`:
143
+ ```json
144
+ {
145
+ "execution": {
146
+ "strategy": "wave",
147
+ "max_parallel": 5,
148
+ "wave_fail_policy": "continue-on-single"
149
+ }
150
+ }
151
+ ```
152
+
153
+ - `max_parallel`: max N parallel within a wave (to avoid API rate limits, default 5)
154
+ - `wave_fail_policy`: single-task failure behavior
155
+
156
+ ## Pitfalls
157
+
158
+ See `@${CLAUDE_PLUGIN_ROOT}/knowledge/wave-execution.md` for the detailed version.
159
+
160
+ - Stray `[P]` → conflict detection as a safety net
161
+ - Wave too large → max_parallel auto-splits
162
+ - Implicit read-write dependencies → planner should avoid this kind of `[P]`
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: review
3
- description: Two-stage code review — Stage 1 spec compliance, Stage 2 code quality. Optional flags add adversarial review or edge-case hunting.
4
- argument-hint: "[--stage=<1|2|both>] [--adversarial] [--edge-case]"
3
+ description: Two-stage code review — Stage 1 spec compliance, Stage 2 code quality. Optional flags add adversarial review, edge-case hunting, or developer-experience audit.
4
+ argument-hint: "[--stage=<1|2|both>] [--adversarial] [--edge-case] [--devex]"
5
5
  allowed-tools: [Read, Bash, Task, Grep, Glob]
6
6
  ---
7
7
 
@@ -18,6 +18,7 @@ Distinct from `/curdx-flow:verify`:
18
18
  | `--stage=<1\|2\|both>` | `both` | Stage 1 = spec compliance only. Stage 2 = code quality only. `both` = sequential. |
19
19
  | `--adversarial` | off | Add an adversarial review pass across applicable categories (zero findings requires proof-of-checking, not fabrication). |
20
20
  | `--edge-case` | off | Add edge-case hunting across applicable categories. Produces a test-gap checklist. |
21
+ | `--devex` | off | Apply the DevEx audit: naming, comments, structure, error handling, setup, types, tests, and developer loop. Gate: `@${CLAUDE_PLUGIN_ROOT}/gates/devex-gate.md`. |
21
22
 
22
23
  ## Preflight
23
24
 
@@ -38,6 +39,7 @@ done
38
39
  FLAG_STAGE=$(echo "$ARGUMENTS" | grep -oP -- '--stage=\K[^\s]+' || echo "both")
39
40
  FLAG_ADV=$(echo "$ARGUMENTS" | grep -q -- '--adversarial' && echo 1 || echo 0)
40
41
  FLAG_EDGE=$(echo "$ARGUMENTS" | grep -q -- '--edge-case' && echo 1 || echo 0)
42
+ FLAG_DEVEX=$(echo "$ARGUMENTS" | grep -q -- '--devex' && echo 1 || echo 0)
41
43
  ```
42
44
 
43
45
  ## Stage 1 — Spec compliance
@@ -89,6 +91,27 @@ Dispatch `flow-edge-hunter` across the applicable categories (skip N/A with one-
89
91
 
90
92
  Output: test-gap checklist with suggested test cases.
91
93
 
94
+ ## Optional: DevEx audit
95
+
96
+ If `--devex`:
97
+ Pass the DevEx gate at `@${CLAUDE_PLUGIN_ROOT}/gates/devex-gate.md` as
98
+ additional context to `flow-reviewer`. The gate adds these dimensions to
99
+ Stage 2:
100
+
101
+ 1. **Naming** — identifier clarity, consistency across modules.
102
+ 2. **Comments** — only non-obvious WHY; no redundant WHAT.
103
+ 3. **Structure** — file and function sizes, colocation of related code.
104
+ 4. **Error handling** — at system boundaries only; no defensive guards inside trusted paths.
105
+ 5. **Setup** — `npm install && npm test` green on a fresh clone.
106
+ 6. **Types** — strictness, no unexplained `any` / `unknown`.
107
+ 7. **Tests** — failure messages, fixture clarity, no flake.
108
+ 8. **Dev loop** — time from code-change to feedback.
109
+
110
+ `flow-reviewer` is NOT edited for `--devex` — the gate file is injected
111
+ into the reviewer dispatch prompt as reference context, so the agent
112
+ stays generic. Output: a "DevEx" section in the review report with
113
+ per-dimension verdicts.
114
+
92
115
  ## Report
93
116
 
94
117
  **Landing check**: sub-agent responses can be truncated. After dispatching review agents, verify the report actually landed on disk:
@@ -121,6 +144,15 @@ Consolidated output: `.flow/specs/$SPEC_NAME/review-report.md`:
121
144
  ## Edge Cases (if run)
122
145
  ...
123
146
 
147
+ ## DevEx (if run)
148
+ - Naming: <verdict>
149
+ - Structure: <verdict>
150
+ - Error handling: <verdict>
151
+ - Setup: <verdict>
152
+ - Types: <verdict>
153
+ - Tests: <verdict>
154
+ - Dev loop: <verdict>
155
+
124
156
  ## Verdict
125
157
  - [ ] APPROVED
126
158
  - [X] CHANGES REQUIRED — <n> blockers
@@ -135,6 +167,7 @@ Consolidated output: `.flow/specs/$SPEC_NAME/review-report.md`:
135
167
  Stage 2 findings: <n>
136
168
  Adversarial findings: <n> (if --adversarial)
137
169
  Edge-case gaps: <n> (if --edge-case)
170
+ DevEx findings: <n> (if --devex)
138
171
  Verdict: CHANGES REQUIRED
139
172
 
140
173
  Report: .flow/specs/<name>/review-report.md
@@ -149,4 +182,5 @@ Next: address blockers, then re-run /curdx-flow:review.
149
182
  - `flow-edge-hunter` agent: `@${CLAUDE_PLUGIN_ROOT}/agents/flow-edge-hunter.md`
150
183
  - `adversarial-review-gate`: `@${CLAUDE_PLUGIN_ROOT}/gates/adversarial-review-gate.md`
151
184
  - `edge-case-gate`: `@${CLAUDE_PLUGIN_ROOT}/gates/edge-case-gate.md`
185
+ - `devex-gate`: `@${CLAUDE_PLUGIN_ROOT}/gates/devex-gate.md`
152
186
  - Knowledge: `@${CLAUDE_PLUGIN_ROOT}/knowledge/two-stage-review.md`