@curdx/flow 2.0.0-beta.1 → 2.0.0-beta.11
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +3 -10
- package/CHANGELOG.md +61 -0
- package/README.zh.md +2 -2
- package/agent-preamble/preamble.md +81 -11
- package/agents/flow-adversary.md +40 -55
- package/agents/flow-architect.md +23 -10
- package/agents/flow-debugger.md +2 -2
- package/agents/flow-edge-hunter.md +20 -6
- package/agents/flow-executor.md +3 -3
- package/agents/flow-planner.md +51 -48
- package/agents/flow-product-designer.md +14 -1
- package/agents/flow-qa-engineer.md +1 -1
- package/agents/flow-researcher.md +17 -2
- package/agents/flow-reviewer.md +5 -1
- package/agents/flow-security-auditor.md +1 -1
- package/agents/flow-triage-analyst.md +1 -1
- package/agents/flow-ui-researcher.md +2 -2
- package/agents/flow-ux-designer.md +1 -1
- package/agents/flow-verifier.md +47 -14
- package/bin/curdx-flow.js +13 -1
- package/cli/doctor.js +73 -13
- package/cli/install.js +62 -36
- package/cli/protocols.js +63 -10
- package/cli/registry.js +73 -0
- package/cli/uninstall.js +9 -11
- package/cli/upgrade.js +6 -10
- package/cli/utils.js +150 -56
- package/commands/fast.md +1 -1
- package/commands/implement.md +4 -4
- package/commands/init.md +14 -3
- package/commands/review.md +14 -5
- package/commands/spec.md +26 -2
- package/commands/start.md +47 -17
- package/commands/verify.md +13 -0
- package/gates/adversarial-review-gate.md +19 -19
- package/gates/devex-gate.md +4 -5
- package/gates/edge-case-gate.md +1 -1
- package/hooks/hooks.json +0 -11
- package/hooks/scripts/quick-mode-guard.sh +12 -9
- package/hooks/scripts/session-start.sh +1 -1
- package/hooks/scripts/stop-watcher.sh +25 -15
- package/knowledge/execution-strategies.md +6 -5
- package/knowledge/spec-driven-development.md +8 -7
- package/knowledge/two-stage-review.md +4 -3
- package/package.json +4 -2
- package/skills/brownfield-index/SKILL.md +62 -0
- package/skills/browser-qa/SKILL.md +50 -0
- package/skills/epic/SKILL.md +68 -0
- package/skills/security-audit/SKILL.md +50 -0
- package/skills/ui-sketch/SKILL.md +49 -0
- package/templates/config.json.tmpl +1 -1
- package/templates/design.md.tmpl +32 -112
- package/templates/requirements.md.tmpl +25 -43
- package/templates/research.md.tmpl +37 -68
- package/templates/tasks.md.tmpl +27 -84
- package/hooks/scripts/fail-tracker.sh +0 -31
package/agents/flow-planner.md
CHANGED
|
@@ -27,18 +27,21 @@ Output:
|
|
|
27
27
|
|
|
28
28
|
## Mandatory Workflow (6 steps)
|
|
29
29
|
|
|
30
|
-
### Step 1: Load Prerequisites + Environment Probe
|
|
30
|
+
### Step 1: Load Prerequisites + Environment Probe (conditional)
|
|
31
|
+
|
|
32
|
+
Always read the spec inputs (`research.md`, `requirements.md`, `design.md`, `.flow/CONTEXT.md`).
|
|
33
|
+
|
|
34
|
+
For the environment probe, **check existence first — do not read files that don't exist**:
|
|
31
35
|
|
|
32
36
|
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
tsconfig.json → TypeScript strictness
|
|
37
|
-
.eslintrc.* → lint rules
|
|
38
|
-
vitest.config.* → test framework
|
|
37
|
+
For each of: package.json, tsconfig.json, .eslintrc.*, vitest.config.*
|
|
38
|
+
if Glob finds it → Read it to capture concrete test/lint/build commands
|
|
39
|
+
else → skip silently (this is a greenfield project or a non-JS stack)
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
For greenfield projects (no `package.json` yet), use the tech stack declared in `design.md` to infer commands. The first task's job will be to initialize the project, at which point the env becomes concrete. Do not fabricate `npm test` commands if there's no package.json yet — instead write the task as "initialize package.json and install vitest; `Verify`: `npm test --silent` produces 'no tests found'".
|
|
43
|
+
|
|
44
|
+
**Use actually detected commands** in each task's `Verify` field. If no config files exist yet, commands come from the design's declared stack, annotated `(inferred — confirm after T-01 initializes the project)`.
|
|
42
45
|
|
|
43
46
|
### Step 2: Break Down by POC-First 5 Phases
|
|
44
47
|
|
|
@@ -132,31 +135,23 @@ For each of the following sources, every item must be covered by tasks:
|
|
|
132
135
|
|
|
133
136
|
### Step 6: Write tasks.md + State
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
```markdown
|
|
140
|
-
## Coverage Audit
|
|
141
|
-
|
|
142
|
-
| Requirement ID | Corresponding Tasks | Status |
|
|
143
|
-
|--------|---------|------|
|
|
144
|
-
| FR-01 | 1.2, 3.1 | ✓ |
|
|
145
|
-
| FR-02 | 3.2 | ✓ |
|
|
146
|
-
| AC-1.1 | 3.1 | ✓ |
|
|
147
|
-
| AD-03 | 1.1, 2.1 | ✓ |
|
|
148
|
-
```
|
|
138
|
+
**CRITICAL (see L8 of the preamble — long-artifact handling):**
|
|
139
|
+
- Your FIRST action in this step must be a `Write` tool call with the full `tasks.md` content. Do NOT paste the file content as assistant text before writing.
|
|
140
|
+
- Do NOT preview the tasks list in the response. The file itself is the deliverable.
|
|
141
|
+
- If a single `Write` call would approach the sub-agent output-token budget (judge by section density, not line count — see preamble L8), split into `tasks-phase-<n>.md` files and make `tasks.md` a short index linking to them.
|
|
149
142
|
|
|
150
|
-
|
|
143
|
+
Based on `${CLAUDE_PLUGIN_ROOT}/templates/tasks.md.tmpl`. Must include a **coverage audit table** at the end (from Step 5).
|
|
151
144
|
|
|
152
|
-
|
|
153
|
-
.flow/specs/<name>/.state.json
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
After the `Write` succeeds:
|
|
146
|
+
1. Update `.flow/specs/<name>/.state.json`:
|
|
147
|
+
```
|
|
148
|
+
phase_status.tasks = "completed"
|
|
149
|
+
total_tasks = <N>
|
|
150
|
+
```
|
|
151
|
+
2. Append to `.flow/specs/<name>/.progress.md`:
|
|
152
|
+
`## tasks phase complete, total N tasks`
|
|
156
153
|
|
|
157
|
-
.
|
|
158
|
-
Append "## tasks phase complete, total N tasks"
|
|
159
|
-
```
|
|
154
|
+
Then emit the 5-line summary (see "Output to User" below). No inline task listing.
|
|
160
155
|
|
|
161
156
|
## Output Quality Bar (Self-Check)
|
|
162
157
|
|
|
@@ -175,30 +170,38 @@ Then:
|
|
|
175
170
|
- ✗ Skipping the coverage audit
|
|
176
171
|
- ✗ Proactively skipping some FRs in requirements for the sake of "simplification" (overreach)
|
|
177
172
|
|
|
178
|
-
## Task
|
|
173
|
+
## Task decomposition (as-needed, no numeric quota)
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
- **coarse**: 15-60 minutes per task. Total 10-20
|
|
175
|
+
**Stop condition, not task count.** Do not aim for a number of tasks. Produce tasks until these are true, then stop:
|
|
182
176
|
|
|
183
|
-
|
|
177
|
+
1. Every FR, AC, AD, and component in the spec is covered by at least one concrete, executable task.
|
|
178
|
+
2. Each task is one **cohesive unit of work** the executor can finish in a **single sub-agent dispatch** without needing to replan internally. If a task would require the executor to think "first I need to decide X, then do Y, then come back and do Z", that task is too big — split it.
|
|
179
|
+
3. No two tasks are inseparable. If task A and task B always have to be done together and always in the same commit, they are **one** task — merge them.
|
|
180
|
+
4. Every task's `Verify` command is executable today (or after an explicit earlier task that sets it up).
|
|
184
181
|
|
|
185
|
-
|
|
182
|
+
**Research reference**: this is the as-needed decomposition pattern from [ADaPT (Allen AI, NAACL 2024)](https://arxiv.org/abs/2311.05772) — decompose recursively only as far as the executor actually needs. Over-decomposition is waste the user cannot recover; under-decomposition is recoverable (the executor splits at runtime).
|
|
186
183
|
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
**Self-check before writing**: re-read your task list. For every adjacent pair, ask "could these be one task?" If yes, merge. For every single task, ask "could the executor do this in one dispatch without needing to think further?" If no, split. Iterate until neither question produces a change.
|
|
185
|
+
|
|
186
|
+
### Symptoms of over-decomposition (stop and merge)
|
|
189
187
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
Phase 3 (Testing): Z tasks
|
|
194
|
-
Phase 4 (Quality): W tasks
|
|
195
|
-
Phase 5 (PR): V tasks
|
|
188
|
+
- "Create file X" + "Add imports to X" + "Write function body in X" → one task.
|
|
189
|
+
- "Add field to schema" + "Run migration" → one task (schema change is atomic).
|
|
190
|
+
- "Write test" + "Make test pass" → this is TDD red+green; one task marked with TDD stage in commits, not two.
|
|
196
191
|
|
|
197
|
-
|
|
192
|
+
### Symptoms of under-decomposition (split)
|
|
198
193
|
|
|
199
|
-
|
|
194
|
+
- The executor's Verify command would be three separate `npm test` runs → three tasks.
|
|
195
|
+
- The task touches > ~3 unrelated files or modules → split by module.
|
|
196
|
+
- The task's `Do` field has numbered steps > 5 that each produce a distinct observable result → split.
|
|
200
197
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
## Output to User (5 lines max, after Write succeeds)
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
✓ Wrote .flow/specs/<name>/tasks.md
|
|
202
|
+
N tasks across 5 Phases (X/Y/Z/W/V)
|
|
203
|
+
Coverage: FR A/B | AC C/D | AD E/F
|
|
204
|
+
Next: /curdx-flow:implement
|
|
204
205
|
```
|
|
206
|
+
|
|
207
|
+
**Do not re-paste the tasks.md content inline. Do not list every task. Just the summary.**
|
|
@@ -56,7 +56,7 @@ AC-N.M: Given [precondition], when [action], then [expected result]
|
|
|
56
56
|
|
|
57
57
|
Must:
|
|
58
58
|
- **Be testable** (can be written as E2E or integration test)
|
|
59
|
-
- **Cover happy path +
|
|
59
|
+
- **Cover happy path + real edge cases that actually apply (omit categories that do not apply to this feature)**
|
|
60
60
|
- **Cover error handling** (when input is invalid / network breaks / permissions insufficient)
|
|
61
61
|
|
|
62
62
|
### Step 4: FR / NFR Extraction
|
|
@@ -144,3 +144,16 @@ Out of Scope: K items explicitly excluded
|
|
|
144
144
|
|
|
145
145
|
Next step: /curdx-flow:spec --phase=design
|
|
146
146
|
```
|
|
147
|
+
|
|
148
|
+
## Requirements discipline (stop-condition, not length-target)
|
|
149
|
+
|
|
150
|
+
Produce user stories and acceptance criteria that cover every distinct user-visible behavior ONCE. No target length. Stop when:
|
|
151
|
+
|
|
152
|
+
1. Every distinct user goal is expressed as one user story (US-NN). Stories that always happen together and share every AC → merge into one.
|
|
153
|
+
2. Every AC-N.N is **observable from outside the code** — a test can determine pass/fail without reading the implementation. If you cannot write the AC observably, delete it rather than ship it vague.
|
|
154
|
+
3. Every FR-NN is stated once, in the US block where it first appears; do not duplicate it in a separate FR section unless the FR genuinely spans multiple user stories.
|
|
155
|
+
4. NFRs are written ONLY for risks that actually apply to this feature's context. No "supports 10,000 users" for a localhost single-user Todo. If the feature has no real non-functional risk, NFR section collapses to one line: "standard for this domain".
|
|
156
|
+
|
|
157
|
+
Length emerges from real content: a 3-story CRUD produces a short document; a 20-story multi-role workflow a long one. The template structure is not a length target.
|
|
158
|
+
|
|
159
|
+
Forbidden padding: restating the goal, describing sections you are about to fill, repeating an AC under both US and FR, writing NFRs for imaginary risks.
|
|
@@ -239,7 +239,7 @@ s['qa']['issues_found'] = len(bugs)
|
|
|
239
239
|
## Quality Self-Check
|
|
240
240
|
|
|
241
241
|
- [ ] Ran every core AC?
|
|
242
|
-
- [ ] Covered
|
|
242
|
+
- [ ] Covered every edge category that genuinely applies to this feature (categories that do not apply are marked N/A)?
|
|
243
243
|
- [ ] Screenshots or logs saved?
|
|
244
244
|
- [ ] Performance data measured (not estimated)?
|
|
245
245
|
- [ ] Accessibility scanned at least once?
|
|
@@ -118,9 +118,9 @@ Before finalizing research.md, ask yourself:
|
|
|
118
118
|
|
|
119
119
|
- [ ] Are all assumptions explicitly listed? (Karpathy principle 1)
|
|
120
120
|
- [ ] Did every technical solution go through context7 / WebSearch? No relying on memory?
|
|
121
|
-
- [ ] Did the codebase scan cover
|
|
121
|
+
- [ ] Did the codebase scan cover every relevant keyword raised by the requirements?
|
|
122
122
|
- [ ] Does the feasibility judgment have evidence (not "should work" but "confirmed feasible based on XX")?
|
|
123
|
-
- [ ] Are there
|
|
123
|
+
- [ ] Are there any open questions for the user to answer? (If research is fully unambiguous, say so explicitly)
|
|
124
124
|
|
|
125
125
|
If any answer is "no", redo it before writing.
|
|
126
126
|
|
|
@@ -153,3 +153,18 @@ Open questions (please answer before entering requirements phase):
|
|
|
153
153
|
|
|
154
154
|
Next step: /curdx-flow:spec --phase=requirements
|
|
155
155
|
```
|
|
156
|
+
|
|
157
|
+
## Research discipline (stop-condition, not length-target)
|
|
158
|
+
|
|
159
|
+
Research answers the real questions for THIS feature. There is no target length. Stop when:
|
|
160
|
+
|
|
161
|
+
1. Every non-obvious technical question raised by the requirements has an answer with a concrete recommendation.
|
|
162
|
+
2. Every version-sensitive library or API you cite has at least one fact sourced from `context7` (or WebSearch), not from memory.
|
|
163
|
+
3. Every alternative you rejected has a one-line reason UNLESS the rejection turns on a subtle tradeoff worth documenting.
|
|
164
|
+
4. No section exists to restate the goal, describe the template, or pad for "thoroughness".
|
|
165
|
+
|
|
166
|
+
Length emerges naturally from real content. A well-known CRUD domain (Todo / blog / basic REST) produces sections that honestly compress to "standard stack, no novelty, no version risk"; anything longer is padding. A novel architecture with real library unknowns produces a much longer document because the information content is higher.
|
|
167
|
+
|
|
168
|
+
**Forbidden padding**: restating the goal in your own words, describing structure you are about to fill, copying upstream content, listing obviously-rejected alternatives.
|
|
169
|
+
|
|
170
|
+
Self-check before `Write`: for every paragraph, ask "does this change a reader's decision?" If no, delete. Iterate until deleting any more leaves a real question unanswered.
|
package/agents/flow-reviewer.md
CHANGED
|
@@ -187,7 +187,11 @@ else:
|
|
|
187
187
|
|
|
188
188
|
### Step 6: Generate review-report.md
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
**CRITICAL (see L8 of the preamble):** your FIRST action in this step must be a `Write` tool call with the **complete report content**. Do NOT paste the report as assistant text before writing. After the write succeeds, respond with a ≤ 5-line summary only (path, verdict, blocker count, next step). Do not re-paste the report.
|
|
191
|
+
|
|
192
|
+
If a single `Write` call would approach the sub-agent output-token budget (judge by section density, not line count), split into `review-report.md` (short index + verdict) and `review-details.md` (full findings) — two `Write` calls. See preamble L8.
|
|
193
|
+
|
|
194
|
+
Full structure (use this as the content passed to `Write`, not as preview text):
|
|
191
195
|
|
|
192
196
|
```markdown
|
|
193
197
|
# Review Report: <spec-name>
|
|
@@ -181,7 +181,7 @@ npm audit
|
|
|
181
181
|
|
|
182
182
|
### Step 4: Threat Modeling (sequential-thinking)
|
|
183
183
|
|
|
184
|
-
Use sequential-thinking
|
|
184
|
+
Use sequential-thinking on core entities proportional to real threat-model complexity:
|
|
185
185
|
|
|
186
186
|
```
|
|
187
187
|
Round 1: User — ask S/T/R/I/D/E each
|
|
@@ -44,7 +44,7 @@ Output: `.flow/_epics/<epic-name>/epic.md` + multiple `.flow/specs/<sub-name>/`
|
|
|
44
44
|
|
|
45
45
|
## Mandatory Workflow
|
|
46
46
|
|
|
47
|
-
### Step 1: Explore + Understand (sequential-thinking
|
|
47
|
+
### Step 1: Explore + Understand (sequential-thinking proportional to epic complexity)
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
Round 1: What does the user really want? What's the biggest goal?
|
|
@@ -185,13 +185,13 @@ Division of labor:
|
|
|
185
185
|
|
|
186
186
|
- ✗ Doing actual UI design (that's flow-ux-designer's job)
|
|
187
187
|
- ✗ Listing references from memory (must WebSearch or scan the codebase)
|
|
188
|
-
- ✗ Providing only one reference
|
|
188
|
+
- ✗ Providing only one reference — aim for enough breadth across reference categories that the user has genuine alternatives to pick from
|
|
189
189
|
- ✗ Ignoring CONTEXT.md preferences
|
|
190
190
|
|
|
191
191
|
## Quality Self-Check
|
|
192
192
|
|
|
193
193
|
- [ ] Scanned codebase for existing patterns?
|
|
194
|
-
- [ ] WebSearch covered
|
|
194
|
+
- [ ] WebSearch covered enough reference categories that the user has genuine design alternatives?
|
|
195
195
|
- [ ] sequential-thinking used to classify references?
|
|
196
196
|
- [ ] Recommendation considers CONTEXT.md?
|
|
197
197
|
- [ ] Asset files saved?
|
|
@@ -237,7 +237,7 @@ The sketch stage = HTML prototype. Convert to React/Vue/Svelte components only a
|
|
|
237
237
|
## Quality Self-Check
|
|
238
238
|
|
|
239
239
|
- [ ] Invoked the frontend-design skill (if available)?
|
|
240
|
-
- [ ]
|
|
240
|
+
- [ ] Enough variants for the user to pick meaningful alternatives (omit if the brief clearly calls for one direction only)?
|
|
241
241
|
- [ ] Each variant a single HTML file, zero dependencies?
|
|
242
242
|
- [ ] decisions.md explains rationale for choices?
|
|
243
243
|
- [ ] Considered CONTEXT.md user preferences?
|
package/agents/flow-verifier.md
CHANGED
|
@@ -85,33 +85,60 @@ for comp in design.components:
|
|
|
85
85
|
assertions.append(("Comp", comp.name, f"{comp.name} must exist"))
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
### Step 3:
|
|
88
|
+
### Step 3: Classify every AC — does it describe user-visible behavior?
|
|
89
|
+
|
|
90
|
+
**BEFORE searching for evidence, classify each AC as either UI-facing or code-only.**
|
|
91
|
+
|
|
92
|
+
An AC is **UI-facing** if any of these is true:
|
|
93
|
+
- Contains words: "user sees", "displays", "renders", "shown", "visible", "click", "type into", "press", "hover", "select"
|
|
94
|
+
- Names a UI element: "button", "input", "checkbox", "link", "list", "form", "label", "modal", "banner"
|
|
95
|
+
- Describes a user flow: "the user can do X", "after X the user sees Y"
|
|
96
|
+
- References a visual state: "strikethrough", "highlighted", "disabled", "focus ring"
|
|
97
|
+
|
|
98
|
+
An AC is **code-only** if it describes internal behavior:
|
|
99
|
+
- Schema shape, API response structure, data transformations
|
|
100
|
+
- Performance ("p95 < 50ms"), reliability, security properties
|
|
101
|
+
- Error-envelope shapes, database constraints
|
|
102
|
+
|
|
103
|
+
### Step 3a: Find evidence for code-only ACs
|
|
89
104
|
|
|
90
105
|
```python
|
|
91
|
-
for source, id, text in
|
|
106
|
+
for source, id, text in code_only_assertions:
|
|
92
107
|
evidence = []
|
|
93
|
-
|
|
94
|
-
# Evidence 1: code implementation
|
|
95
108
|
relevant_files = grep_codebase(extract_keywords(text))
|
|
96
109
|
if relevant_files:
|
|
97
110
|
evidence.append(("code", relevant_files))
|
|
98
|
-
|
|
99
|
-
# Evidence 2: tests
|
|
100
111
|
test_files = find_tests_mentioning(id)
|
|
101
112
|
if test_files:
|
|
102
113
|
evidence.append(("test", test_files))
|
|
103
|
-
|
|
104
|
-
# Evidence 3: commit references
|
|
105
114
|
commits = git_log_grep(id)
|
|
106
115
|
if commits:
|
|
107
116
|
evidence.append(("commit", commits))
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
status = "verified" if evidence and all_evidence_strong(evidence) else ("partial" if evidence else "missing")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 3b: UI-facing ACs REQUIRE browser verification (hard rule)
|
|
121
|
+
|
|
122
|
+
Code inspection + unit tests are **insufficient** evidence for a UI-facing AC. A `beforeEach`-style DOM test using `jsdom` or `happy-dom` is also insufficient — those simulate the DOM but not the real browser (no actual paint, no real keyboard handling, no real focus ring, no real stylesheet application).
|
|
123
|
+
|
|
124
|
+
For every UI-facing AC:
|
|
125
|
+
|
|
114
126
|
```
|
|
127
|
+
1. Check chrome-devtools MCP availability (mcp__chrome-devtools__*).
|
|
128
|
+
2. If available:
|
|
129
|
+
- Start the app (dev server or served build) in the current repo.
|
|
130
|
+
- Drive the flow described in the AC: click / type / navigate.
|
|
131
|
+
- Capture screenshot + list_console_messages + list_network_requests.
|
|
132
|
+
- Compare observed behavior against the AC text.
|
|
133
|
+
- Verdict: verified | partial | failed, with the screenshot as evidence.
|
|
134
|
+
3. If chrome-devtools MCP is NOT available:
|
|
135
|
+
- Mark the AC as "unverified — browser MCP missing".
|
|
136
|
+
- Add a CRITICAL section in verification-report.md listing the UI-facing ACs that could not be verified.
|
|
137
|
+
- Do NOT silently pass the AC based on code reading.
|
|
138
|
+
- Do NOT accept "manual smoke" as sufficient evidence unless the user explicitly logged a D-NN decision in STATE.md waiving automated browser verification.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Manual-smoke evidence (comments in tasks.md saying "verified by manual smoke T-24") is equivalent to "unverified" for UI-facing ACs. Flag it. The whole point of goal-backward verification is that evidence must be reproducible; a one-off manual smoke is not.
|
|
115
142
|
|
|
116
143
|
### Step 4: Run Actual Tests (Decisive)
|
|
117
144
|
|
|
@@ -145,6 +172,12 @@ For each match, check:
|
|
|
145
172
|
|
|
146
173
|
### Step 6: Generate verification-report.md
|
|
147
174
|
|
|
175
|
+
**CRITICAL (see L8 of the preamble):** your FIRST action in this step must be a `Write` tool call with the **complete report content**. Do NOT paste the report as assistant text before writing — doing so doubles output tokens and causes truncation inside the `Write` call. After the write succeeds, respond with a ≤ 5-line summary only (path, verdict counts, next step). Do not re-paste the report.
|
|
176
|
+
|
|
177
|
+
If a single `Write` call would approach the sub-agent output-token budget (judge by section density, not line count), split into `verification-report.md` (short index + verdict) and `verification-details.md` (full findings table) — two `Write` calls. See preamble L8.
|
|
178
|
+
|
|
179
|
+
Required structure (use this as the content passed to `Write`, not as preview text):
|
|
180
|
+
|
|
148
181
|
```markdown
|
|
149
182
|
# Verification Report: <spec-name>
|
|
150
183
|
|
package/bin/curdx-flow.js
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
* for the full command/workflow reference)
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { pathToFileURL } from "node:url";
|
|
24
|
+
|
|
23
25
|
import { install } from "../cli/install.js";
|
|
24
26
|
import { doctor } from "../cli/doctor.js";
|
|
25
27
|
import { upgrade } from "../cli/upgrade.js";
|
|
@@ -128,4 +130,14 @@ async function main() {
|
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
main()
|
|
133
|
+
// Only execute main() when invoked directly (`node bin/curdx-flow.js ...`
|
|
134
|
+
// or via the npm bin shim). When the file is imported by tests or tooling,
|
|
135
|
+
// we want the module graph to load without side-effects. This idiom is
|
|
136
|
+
// the ESM equivalent of Python's `if __name__ == "__main__"`.
|
|
137
|
+
const invokedDirectly =
|
|
138
|
+
process.argv[1] &&
|
|
139
|
+
import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
140
|
+
|
|
141
|
+
if (invokedDirectly) {
|
|
142
|
+
main();
|
|
143
|
+
}
|
package/cli/doctor.js
CHANGED
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
listPlugins,
|
|
13
13
|
listMcps,
|
|
14
14
|
ensureClaudeMemRuntimes,
|
|
15
|
+
readUserMcpConfig,
|
|
16
|
+
findDuplicateMcps,
|
|
15
17
|
} from "./utils.js";
|
|
18
|
+
import { RECOMMENDED_PLUGINS } from "./registry.js";
|
|
16
19
|
|
|
17
20
|
export async function doctor(args = []) {
|
|
18
21
|
const verbose = args.includes("--verbose") || args.includes("-v");
|
|
@@ -50,13 +53,28 @@ export async function doctor(args = []) {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
// ---------- MCPs ----------
|
|
56
|
+
// Bundled by curdx-flow plugin via .claude-plugin/plugin.json mcpServers.
|
|
57
|
+
// chrome-devtools is NOT here anymore — it was extracted into its own
|
|
58
|
+
// recommended plugin (see below) to align with the "each MCP owned by one
|
|
59
|
+
// plugin" model and avoid double-spawning the chrome-devtools-mcp process.
|
|
53
60
|
console.log(`\n${color.bold("MCP Servers:")}`);
|
|
54
61
|
const mcps = cv ? listMcps() : [];
|
|
55
|
-
const expectedMcps = ["context7", "sequential-thinking"
|
|
62
|
+
const expectedMcps = ["context7", "sequential-thinking"];
|
|
56
63
|
for (const m of expectedMcps) {
|
|
57
|
-
|
|
64
|
+
// `claude mcp list` reports plugin-bundled MCPs as
|
|
65
|
+
// "plugin:curdx-flow:<name>" and standalone MCPs as "<name>". Accept
|
|
66
|
+
// either form — previously this was a bare .name === m check, so a
|
|
67
|
+
// plugin MCP named "plugin:curdx-flow:context7" would silently report
|
|
68
|
+
// as not-installed even though it was running (the same class of bug
|
|
69
|
+
// that bit chrome-devtools in beta.7).
|
|
70
|
+
const found = mcps.find(
|
|
71
|
+
(x) =>
|
|
72
|
+
x.name === m &&
|
|
73
|
+
(x.plugin === null || x.plugin === "curdx-flow")
|
|
74
|
+
);
|
|
58
75
|
if (found) {
|
|
59
|
-
|
|
76
|
+
const via = found.plugin ? `via plugin:${found.plugin}` : "standalone";
|
|
77
|
+
log.ok(`${m.padEnd(22)} ${color.dim(`auto-loaded (${via})`)}`);
|
|
60
78
|
} else {
|
|
61
79
|
if (curdx) {
|
|
62
80
|
log.warn(`${m.padEnd(22)} not shown in claude mcp list (restart Claude Code may fix)`);
|
|
@@ -67,28 +85,68 @@ export async function doctor(args = []) {
|
|
|
67
85
|
}
|
|
68
86
|
}
|
|
69
87
|
|
|
70
|
-
// ---------- Recommended plugins ----------
|
|
88
|
+
// ---------- Recommended plugins (single registry; see cli/registry.js) ----------
|
|
71
89
|
console.log(`\n${color.bold("Recommended plugins:")}`);
|
|
72
|
-
const recommended = [
|
|
73
|
-
{ name: "pua", installCmd: "claude plugin install pua@pua-skills" },
|
|
74
|
-
{ name: "claude-mem", installCmd: "claude plugin install claude-mem@thedotmack" },
|
|
75
|
-
{ name: "frontend-design", installCmd: "claude plugin install frontend-design@claude-plugins-official" },
|
|
76
|
-
];
|
|
77
90
|
let claudeMemEnabled = false;
|
|
78
|
-
for (const r of
|
|
91
|
+
for (const r of RECOMMENDED_PLUGINS) {
|
|
79
92
|
const p = plugins.find((x) => x.name === r.name);
|
|
80
93
|
if (p && p.status === "enabled") {
|
|
81
94
|
log.ok(`${r.name.padEnd(22)} ${color.dim(`v${p.version}`)}`);
|
|
82
|
-
if (r.
|
|
95
|
+
if (r.postInstall === "claude-mem-runtimes") claudeMemEnabled = true;
|
|
83
96
|
} else if (p && p.status === "failed") {
|
|
84
97
|
log.err(`${r.name.padEnd(22)} load failed`);
|
|
85
98
|
errors++;
|
|
86
99
|
} else {
|
|
87
|
-
log.warn(
|
|
100
|
+
log.warn(
|
|
101
|
+
`${r.name.padEnd(22)} not installed ${color.dim(`(run: claude plugin install ${r.installSpec})`)}`
|
|
102
|
+
);
|
|
88
103
|
warnings++;
|
|
89
104
|
}
|
|
90
105
|
}
|
|
91
106
|
|
|
107
|
+
// ---------- Duplicate user-level / plugin-level MCPs ----------
|
|
108
|
+
// Context: the bundled context7 + sequential-thinking MCPs (registered
|
|
109
|
+
// via plugin.json) show up as `plugin:curdx-flow:<name>`. If the user
|
|
110
|
+
// also added `<name>` manually via `claude mcp add …` at some earlier
|
|
111
|
+
// point (common with context7 + a personal API key), both instances
|
|
112
|
+
// run side-by-side. That's not a correctness bug — tool namespaces
|
|
113
|
+
// differ — but it doubles MCP processes and makes API-key routing
|
|
114
|
+
// unpredictable. Surface the duplicates + concrete remediation.
|
|
115
|
+
if (cv) {
|
|
116
|
+
const userCfg = readUserMcpConfig();
|
|
117
|
+
const duplicates = findDuplicateMcps(mcps, userCfg);
|
|
118
|
+
if (duplicates.length > 0) {
|
|
119
|
+
console.log(`\n${color.bold("Duplicate MCP servers (user-level vs plugin-bundled):")}`);
|
|
120
|
+
for (const d of duplicates) {
|
|
121
|
+
const userArgs = (d.userConfig.args || []).join(" ");
|
|
122
|
+
const hasApiKey = userArgs.includes("api-key") || userArgs.includes("ctx7sk");
|
|
123
|
+
log.warn(
|
|
124
|
+
`${d.name.padEnd(22)} registered BOTH in ~/.claude.json AND via plugin:${d.pluginEntry.plugin}`
|
|
125
|
+
);
|
|
126
|
+
console.log(
|
|
127
|
+
color.dim(` user-level : ${d.userConfig.command || "?"} ${userArgs}`)
|
|
128
|
+
);
|
|
129
|
+
console.log(
|
|
130
|
+
color.dim(` plugin : ${d.pluginEntry.command || "?"}`)
|
|
131
|
+
);
|
|
132
|
+
if (hasApiKey && d.name === "context7") {
|
|
133
|
+
console.log(
|
|
134
|
+
color.dim(
|
|
135
|
+
` → Fix: export CONTEXT7_API_KEY=<your-key> in your shell rc,\n` +
|
|
136
|
+
` then: claude mcp remove ${d.name}\n` +
|
|
137
|
+
` (plugin MCP will inherit the env var — no key is lost)`
|
|
138
|
+
)
|
|
139
|
+
);
|
|
140
|
+
} else {
|
|
141
|
+
console.log(
|
|
142
|
+
color.dim(` → Fix: claude mcp remove ${d.name}`)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
warnings++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
92
150
|
// ---------- Runtime PATH guards (only if claude-mem is installed) ----------
|
|
93
151
|
if (claudeMemEnabled) {
|
|
94
152
|
console.log(`\n${color.bold("Runtime (claude-mem dependencies):")}`);
|
|
@@ -147,7 +205,9 @@ export async function doctor(args = []) {
|
|
|
147
205
|
console.log(color.green("Summary: all healthy ✓"));
|
|
148
206
|
}
|
|
149
207
|
|
|
150
|
-
if (verbose) {
|
|
208
|
+
if (verbose && cv) {
|
|
209
|
+
// Only call claude when it is actually on PATH; otherwise we spawn a
|
|
210
|
+
// child that fails silently and print a blank block.
|
|
151
211
|
console.log(`\n${color.bold("Details:")}`);
|
|
152
212
|
console.log(color.dim(` Plugins raw:`));
|
|
153
213
|
console.log(runSync("claude", ["plugin", "list"]).stdout);
|