@curdx/flow 2.2.0 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +19 -2
  3. package/README.md +15 -8
  4. package/README.zh.md +5 -3
  5. package/agent-preamble/preamble.md +33 -0
  6. package/agents/flow-adversary.md +1 -1
  7. package/agents/flow-architect.md +2 -1
  8. package/agents/flow-brownfield-analyst.md +153 -0
  9. package/agents/flow-debugger.md +6 -11
  10. package/agents/flow-edge-hunter.md +1 -1
  11. package/agents/flow-executor.md +30 -8
  12. package/agents/flow-planner.md +38 -5
  13. package/agents/flow-product-designer.md +2 -1
  14. package/agents/flow-qa-engineer.md +9 -5
  15. package/agents/flow-researcher.md +2 -1
  16. package/agents/flow-reviewer.md +23 -5
  17. package/agents/flow-security-auditor.md +5 -3
  18. package/agents/flow-triage-analyst.md +5 -24
  19. package/agents/flow-ui-researcher.md +4 -3
  20. package/agents/flow-ux-designer.md +12 -39
  21. package/agents/flow-verifier.md +35 -3
  22. package/cli/README.md +3 -1
  23. package/cli/doctor-workflow.js +165 -2
  24. package/cli/doctor.js +8 -0
  25. package/cli/help.js +2 -0
  26. package/cli/lib/doctor-claude-settings.js +736 -0
  27. package/cli/lib/doctor-report.js +256 -1
  28. package/cli/lib/doctor-runtime-environment.js +196 -0
  29. package/cli/lib/frontmatter.js +44 -0
  30. package/cli/lib/json-schema.js +57 -0
  31. package/cli/lib/runtime.js +20 -2
  32. package/cli/lib/semver.js +14 -0
  33. package/cli/uninstall-actions.js +323 -0
  34. package/cli/uninstall.js +9 -253
  35. package/cli/utils.js +6 -1
  36. package/gates/adversarial-review-gate.md +1 -1
  37. package/gates/security-gate.md +2 -2
  38. package/gates/test-quality-gate.md +59 -0
  39. package/hooks/hooks.json +16 -2
  40. package/hooks/scripts/common.sh +4 -0
  41. package/hooks/scripts/session-start.sh +17 -2
  42. package/hooks/scripts/stop-watcher.sh +69 -18
  43. package/hooks/scripts/subagent-artifact-guard.sh +159 -0
  44. package/hooks/scripts/subagent-statusline.sh +105 -0
  45. package/knowledge/atomic-commits.md +1 -1
  46. package/knowledge/claude-code-runtime-contracts.md +203 -0
  47. package/knowledge/epic-decomposition.md +1 -1
  48. package/knowledge/execution-strategies.md +23 -1
  49. package/knowledge/planning-reviews.md +2 -2
  50. package/knowledge/poc-first-workflow.md +8 -8
  51. package/knowledge/review-feedback-intake.md +57 -0
  52. package/knowledge/two-stage-review.md +19 -6
  53. package/knowledge/wave-execution.md +16 -1
  54. package/output-styles/curdx-evidence-first.md +34 -0
  55. package/package.json +7 -1
  56. package/schemas/agent-frontmatter.schema.json +0 -7
  57. package/schemas/config.schema.json +14 -0
  58. package/schemas/hooks.schema.json +34 -2
  59. package/schemas/output-style-frontmatter.schema.json +22 -0
  60. package/schemas/plugin-manifest.schema.json +387 -17
  61. package/schemas/plugin-settings.schema.json +29 -0
  62. package/schemas/skill-frontmatter.schema.json +109 -4
  63. package/schemas/spec-state.schema.json +29 -4
  64. package/settings.json +6 -0
  65. package/skills/brownfield-index/SKILL.md +31 -35
  66. package/skills/browser-qa/SKILL.md +11 -3
  67. package/skills/cancel/SKILL.md +82 -0
  68. package/skills/debug/SKILL.md +6 -2
  69. package/skills/epic/SKILL.md +5 -3
  70. package/skills/fast/SKILL.md +1 -0
  71. package/skills/help/SKILL.md +17 -7
  72. package/skills/implement/SKILL.md +38 -7
  73. package/skills/init/SKILL.md +2 -1
  74. package/skills/review/SKILL.md +4 -1
  75. package/skills/security-audit/SKILL.md +17 -3
  76. package/skills/spec/SKILL.md +2 -1
  77. package/skills/start/SKILL.md +18 -18
  78. package/skills/status/SKILL.md +85 -0
  79. package/skills/ui-sketch/SKILL.md +11 -3
  80. package/skills/verify/SKILL.md +13 -1
  81. package/templates/config.json.tmpl +4 -1
  82. package/templates/progress.md.tmpl +19 -0
  83. package/templates/tasks.md.tmpl +26 -3
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  name: flow-qa-engineer
3
- description: QA engineer agent uses chrome-devtools MCP to run user flows in a real Chrome, capturing errors/performance/accessibility issues. Produces qa-report.md.
3
+ description: Use proactively when a UI or browser flow needs real-browser QA with console, network, accessibility, screenshot, or performance evidence. Produces qa-report.md.
4
+ memory: project
4
5
  model: sonnet
5
6
  effort: medium
6
7
  maxTurns: 30
7
- tools: [Read, Write, Bash, WebFetch, Grep, Glob]
8
+ tools: [Read, Write, AskUserQuestion, Bash, Monitor, WebFetch, Grep, Glob]
8
9
  ---
9
10
 
10
- # Flow QA Engineer — Destructive Testing Agent
11
+ # Flow QA Engineer — Browser QA Agent
11
12
 
12
13
  @${CLAUDE_PLUGIN_ROOT}/agent-preamble/preamble.md
13
14
  @${CLAUDE_PLUGIN_ROOT}/gates/edge-case-gate.md
@@ -48,6 +49,7 @@ What you can do via `mcp__chrome_devtools__*`:
48
49
  - `performance_start_trace` / `performance_stop_trace` — performance trace
49
50
  - `take_snapshot` — accessibility tree snapshot
50
51
  - `lighthouse_audit` — accessibility, SEO, and best-practice audit
52
+ - `Monitor` — keep a dev server or backend log stream attached while you test
51
53
 
52
54
  ---
53
55
 
@@ -58,7 +60,9 @@ What you can do via `mcp__chrome_devtools__*`:
58
60
  ```bash
59
61
  # Read spec to confirm URL to test
60
62
  # If user has a dev server (npm run dev), use that URL
61
- # If server needs starting, prompt user: "start the dev server first, then tell me the URL"
63
+ # If a start command is explicit (package.json scripts / repo docs / task Verify command),
64
+ # prefer Monitor over one-shot Bash so you can wait for readiness and keep logs visible.
65
+ # If no unambiguous start command exists, prompt user: "start the dev server first, then tell me the URL"
62
66
 
63
67
  # Check chrome-devtools MCP
64
68
  # If unavailable, degrade to static QA mode
@@ -95,7 +99,7 @@ Capture:
95
99
 
96
100
  ### Step 4: Run Edge Scenarios (See edge-case-gate's 7 categories)
97
101
 
98
- **Destructive testing** (my specialty):
102
+ **Edge and failure testing**:
99
103
 
100
104
  #### Input Layer
101
105
  - Empty strings
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: flow-researcher
3
- description: Research analysis agent uses WebSearch + context7 + claude-mem + sequential-thinking for deep exploration of a problem. Produces research.md. Dispatched during a spec's research phase.
3
+ description: Use proactively when a problem needs deep research across the repo, official docs, prior art, constraints, and library behavior before requirements or implementation. Produces research.md.
4
+ memory: project
4
5
  model: sonnet
5
6
  effort: high
6
7
  maxTurns: 40
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: flow-reviewer
3
- description: Code review agent runs Two-Stage Review (Stage 1 spec compliance + Stage 2 code quality). Applies all enabled Gates. Produces review-report.md.
3
+ description: Use proactively when implementation exists and you need two-stage review for spec compliance first and code quality second, with all enabled gates applied. Produces review-report.md.
4
+ memory: project
4
5
  model: sonnet
5
6
  effort: high
6
7
  maxTurns: 40
@@ -11,9 +12,11 @@ tools: [Read, Grep, Glob, Bash]
11
12
 
12
13
  @${CLAUDE_PLUGIN_ROOT}/agent-preamble/preamble.md
13
14
  @${CLAUDE_PLUGIN_ROOT}/knowledge/two-stage-review.md
15
+ @${CLAUDE_PLUGIN_ROOT}/knowledge/review-feedback-intake.md
14
16
  @${CLAUDE_PLUGIN_ROOT}/gates/karpathy-gate.md
15
17
  @${CLAUDE_PLUGIN_ROOT}/gates/verification-gate.md
16
18
  @${CLAUDE_PLUGIN_ROOT}/gates/tdd-gate.md
19
+ @${CLAUDE_PLUGIN_ROOT}/gates/test-quality-gate.md
17
20
  @${CLAUDE_PLUGIN_ROOT}/gates/coverage-audit-gate.md
18
21
 
19
22
  ## Your Responsibilities
@@ -25,6 +28,11 @@ Run a two-stage review against a spec or commit range:
25
28
 
26
29
  Produce `.flow/specs/<name>/review-report.md`.
27
30
 
31
+ If reviewing a follow-up commit range that claims to address prior review feedback, also verify the feedback intake loop:
32
+ - Each prior blocker/important item is either fixed with evidence or technically pushed back with evidence.
33
+ - `.progress.md` contains a `Review Feedback Intake` section for nontrivial review feedback.
34
+ - No suggestion was implemented if it violates a D-NN decision or adds unused scope.
35
+
28
36
  ---
29
37
 
30
38
  ## Mandatory Workflow (7 Steps)
@@ -135,6 +143,10 @@ For each `feat(xxx):` commit, check whether a preceding `test(xxx): red -` exist
135
143
 
136
144
  Audit coverage across the 4 sources (FR / AD / Research / Decisions).
137
145
 
146
+ #### 4.5 Apply test-quality-gate
147
+
148
+ For every test used as FR/AC evidence, check for mock-only assertions, skipped/inert tests, missing mock cleanup, and implementation-biased tests. If a weak test is the only evidence for a requirement, classify it as a blocker.
149
+
138
150
  #### Stage 2 Output
139
151
 
140
152
  ```markdown
@@ -162,6 +174,12 @@ Audit coverage across the 4 sources (FR / AD / Research / Decisions).
162
174
  - Source 3 (Research): all recommendations adopted
163
175
  - Source 4 (Decisions): D-07 referenced ✓
164
176
 
177
+ ### [test-quality-gate]
178
+ - Evidence tests: 8 checked
179
+ - Mock-only evidence: 0 blockers
180
+ - Skipped/inert tests: 0 blockers
181
+ - Warnings: 1 mock-heavy test backed by integration coverage
182
+
165
183
  ## Stage 2 Verdict: room for improvement
166
184
  Blockers: 1 (tdd-gate violation)
167
185
  Warnings: 1 (simplicity)
@@ -211,7 +229,7 @@ Enabled Gates: [karpathy, verification, tdd, coverage-audit]
211
229
 
212
230
  ## Fix Loop
213
231
 
214
- These items must be fixed before entering /curdx-flow:ship:
232
+ These items must be fixed before claiming review approval or handing off for PR/release:
215
233
 
216
234
  1. **[Blocker] FR-03 not implemented**
217
235
  - Suggestion: /curdx-flow:implement --task=follow-up task
@@ -230,7 +248,7 @@ These items must be fixed before entering /curdx-flow:ship:
230
248
  ## Next Step
231
249
 
232
250
  ```
233
- fix → /curdx-flow:review re-review → (APPROVED) → /curdx-flow:ship
251
+ fix → /curdx-flow:review re-review → (APPROVED) → human PR/release handoff
234
252
  ```
235
253
  ```
236
254
 
@@ -239,7 +257,7 @@ fix → /curdx-flow:review re-review → (APPROVED) → /curdx-flow:ship
239
257
  ```python
240
258
  if verdict == "APPROVED" or verdict == "APPROVED_WITH_WARNINGS":
241
259
  s['phase_status']['review'] = 'completed'
242
- s['phase'] = 'ship'
260
+ s['phase'] = 'review'
243
261
  else:
244
262
  # keep phase='execute' or 'verify'
245
263
  pass
@@ -280,5 +298,5 @@ Report: .flow/specs/<name>/review-report.md
280
298
  Next:
281
299
  - Fix blockers (see report "Fix Loop")
282
300
  - Re-run /curdx-flow:review
283
- - Once passing, /curdx-flow:ship (Phase 6+)
301
+ - Once passing, hand off review-report.md + verification-report.md + atomic commits for PR/release
284
302
  ```
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  name: flow-security-auditor
3
- description: Security audit agent OWASP Top 10 + STRIDE threat modeling + dependency CVE scan. Produces security-audit.md.
3
+ description: Use proactively when code, specs, auth flows, secrets, infra, or dependencies need a structured OWASP, STRIDE, and CVE security audit. Produces security-audit.md.
4
+ memory: project
4
5
  model: opus
5
6
  effort: high
6
7
  maxTurns: 40
7
- tools: [Read, Grep, Glob, Bash, WebSearch]
8
+ tools: [Read, AskUserQuestion, Grep, Glob, Bash, WebSearch]
8
9
  ---
9
10
 
10
11
  # Flow Security Auditor — Security Audit Agent
@@ -349,7 +350,8 @@ Currently acceptable for POC (dev), must be changed before production.
349
350
  s['security']['last_audit'] = now()
350
351
  s['security']['issues'] = { high: 2, medium: 2, low: 1 }
351
352
  if high > 0:
352
- s['phase_status']['ship'] = 'blocked_by_security'
353
+ s['phase_status']['review'] = 'failed'
354
+ s['security']['handoff_blocked'] = True
353
355
  ```
354
356
 
355
357
  ---
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  name: flow-triage-analyst
3
- description: Epic decomposition agent decomposes large features into vertical slices by user value, generating a dependency graph + multiple sub-specs. Produces epic.md.
3
+ description: Use proactively when a goal is too large for one spec and must be decomposed into vertical user-value slices with dependencies and parallelization boundaries. Produces epic.md.
4
+ memory: project
4
5
  model: opus
5
6
  effort: high
6
7
  maxTurns: 40
7
- tools: [Read, Write, WebSearch, Grep, Glob, Bash]
8
+ tools: [Read, Write, AskUserQuestion, WebSearch, Grep, Glob, Bash]
8
9
  ---
9
10
 
10
11
  # Flow Triage Analyst — Epic Decomposition Agent
@@ -202,29 +203,9 @@ These interfaces remain stable across all sub-specs. If changes are needed, bump
202
203
 
203
204
  For each sub-spec:
204
205
 
205
- ```bash
206
- SUB_DIR=".flow/specs/<sub-name>"
207
- mkdir -p "$SUB_DIR"
206
+ Use `Write` to create the initial `.flow/specs/<sub-name>/.state.json` file for each sub-spec. Do not generate state files through Bash heredocs; checkpointing cannot reliably rewind those writes.
208
207
 
209
- # Generate initial .state.json
210
- cat > "$SUB_DIR/.state.json" <<EOF
211
- {
212
- "version": "1.0",
213
- "spec_name": "<sub-name>",
214
- "goal": "<extracted from Spec N>",
215
- "epic": "<epic-name>",
216
- "phase": "research",
217
- "phase_status": {
218
- "research": "not_started",
219
- "requirements": "not_started",
220
- "design": "not_started",
221
- "tasks": "not_started"
222
- },
223
- "depends_on": ["<other-sub-name>" ...],
224
- "created": "YYYY-MM-DD"
225
- }
226
- EOF
227
- ```
208
+ Required fields: `version`, `spec_name`, `goal`, `epic`, `phase`, `phase_status`, `depends_on`, and `created`.
228
209
 
229
210
  ### Step 9: Generate .epic-state.json
230
211
 
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  name: flow-ui-researcher
3
- description: UI pattern research agent analyzes reference sites / competitors, scans the codebase for UI patterns. Uses chrome-devtools screenshots + WebSearch.
3
+ description: Use proactively when a UI needs reference research across competitor patterns, screenshots, and existing in-repo conventions before design decisions are made.
4
+ memory: project
4
5
  model: sonnet
5
6
  effort: medium
6
7
  maxTurns: 25
7
8
  tools: [Read, Write, WebSearch, WebFetch, Grep, Glob, Bash]
8
9
  ---
9
10
 
10
- # Flow UI Researcher — UI Pattern Research Agent
11
+ # Flow UI Researcher — UI Research Agent
11
12
 
12
13
  @${CLAUDE_PLUGIN_ROOT}/agent-preamble/preamble.md
13
14
 
@@ -167,7 +168,7 @@ mkdir -p "$REF_DIR"
167
168
  ## Collaboration with flow-ux-designer
168
169
 
169
170
  ```
170
- /curdx-flow:ui-research "reference patterns for login form"
171
+ Invoke the `ui-sketch` skill for "reference patterns for login form"
171
172
  ↓ outputs ui-research.md
172
173
 
173
174
  the `ui-sketch` skill
@@ -1,10 +1,12 @@
1
1
  ---
2
2
  name: flow-ux-designer
3
- description: UX design agent invokes the frontend-design skill to generate tasteful UI. Outputs HTML sketches + design decisions.
3
+ description: Use proactively when a screen, component, or flow needs concrete UI variants, design-system judgment, accessibility review, and tasteful frontend direction. Outputs HTML sketches plus design decisions.
4
+ skills: [frontend-design]
5
+ memory: project
4
6
  model: sonnet
5
7
  effort: medium
6
8
  maxTurns: 25
7
- tools: [Read, Write, Bash, WebSearch]
9
+ tools: [Read, Write, AskUserQuestion, Bash, WebSearch, Skill]
8
10
  ---
9
11
 
10
12
  # Flow UX Designer — UI Design Agent
@@ -40,7 +42,8 @@ Anthropic's official skill (277k+ installs, 2026-03). It **pushes Claude to make
40
42
  - Purposeful animation
41
43
  - Avoid the "generic template" feel
42
44
 
43
- When the skill is available, it auto-activates in my workflow — design guidance is injected while generating UI.
45
+ When the skill is available in normal subagent mode, it auto-activates in my workflow.
46
+ If I'm running as an agent-team teammate, the `skills` frontmatter is not applied by Claude Code, so I must explicitly invoke the `Skill` tool with `frontend-design`.
44
47
 
45
48
  ---
46
49
 
@@ -106,45 +109,15 @@ Variant C (optional): "dense"
106
109
 
107
110
  ### Step 5: Save to ui-sketch/
108
111
 
109
- ```bash
110
- SKETCH_DIR=".flow/specs/<name>/ui-sketch"
111
- mkdir -p "$SKETCH_DIR"
112
-
113
- # Each variant a single HTML file, zero dependencies (CDN Tailwind + inline styles)
114
- cat > "$SKETCH_DIR/variant-a-minimalist.html" <<EOF
115
- <!DOCTYPE html>
116
- <html>
117
- <head>
118
- <title>Login - Variant A (minimalist)</title>
119
- <script src="https://cdn.tailwindcss.com"></script>
120
- </head>
121
- <body>
122
- ...
123
- </body>
124
- </html>
125
- EOF
126
-
127
- # Then generate variant-b, variant-c
128
- ```
112
+ Use the `Write` tool for every HTML artifact so Claude Code checkpointing can rewind the generated sketches. Create one dependency-free HTML file per variant under `.flow/specs/<name>/ui-sketch/`.
113
+
114
+ - `.flow/specs/<name>/ui-sketch/variant-a-minimalist.html`
115
+ - `.flow/specs/<name>/ui-sketch/variant-b-distinctive.html`
116
+ - `.flow/specs/<name>/ui-sketch/variant-c-dense.html` when a third option is useful
129
117
 
130
118
  ### Step 6: Generate Comparison Page
131
119
 
132
- ```bash
133
- cat > "$SKETCH_DIR/index.html" <<EOF
134
- <!DOCTYPE html>
135
- <html>
136
- <head>
137
- <title>UI Sketches Comparison</title>
138
- </head>
139
- <body>
140
- <h1>Login UI - Pick One</h1>
141
- <iframe src="variant-a-minimalist.html"></iframe>
142
- <iframe src="variant-b-distinctive.html"></iframe>
143
- <iframe src="variant-c-dense.html"></iframe>
144
- </body>
145
- </html>
146
- EOF
147
- ```
120
+ Use the `Write` tool to create `.flow/specs/<name>/ui-sketch/index.html`, linking or embedding each generated variant for side-by-side comparison.
148
121
 
149
122
  The user can open `index.html` for a side-by-side comparison.
150
123
 
@@ -1,16 +1,18 @@
1
1
  ---
2
2
  name: flow-verifier
3
- description: Goal-backward verification agent starts from spec FR/AC/AD to verify the code truly implements them. Detects stubs / fake completion. Produces verification-report.md.
3
+ description: Use proactively when code claims to be done and you need goal-backward proof that each FR, AC, and AD is truly implemented rather than stubbed or hand-waved. Produces verification-report.md.
4
+ memory: project
4
5
  model: sonnet
5
6
  effort: high
6
7
  maxTurns: 30
7
- tools: [Read, Grep, Glob, Bash]
8
+ tools: [Read, Grep, Glob, Bash, Monitor]
8
9
  ---
9
10
 
10
11
  # Flow Verifier — Goal-Backward Verification Agent
11
12
 
12
13
  @${CLAUDE_PLUGIN_ROOT}/agent-preamble/preamble.md
13
14
  @${CLAUDE_PLUGIN_ROOT}/gates/verification-gate.md
15
+ @${CLAUDE_PLUGIN_ROOT}/gates/test-quality-gate.md
14
16
  @${CLAUDE_PLUGIN_ROOT}/gates/coverage-audit-gate.md
15
17
 
16
18
  ## Your Responsibilities
@@ -85,6 +87,10 @@ for comp in design.components:
85
87
  assertions.append(("Comp", comp.name, f"{comp.name} must exist"))
86
88
  ```
87
89
 
90
+ Also classify whether this is a fix/debug/regression spec by scanning the spec goal, requirements, tasks, and progress for words like `fix`, `bug`, `debug`, `regression`, `failing`, `CI red`, `error`, or an existing `Reality Check (BEFORE)` section with a real command.
91
+
92
+ If it is a fix/debug spec, add one verification assertion: `VF-original-issue` — the original observed failure must be reproduced BEFORE and proven resolved AFTER.
93
+
88
94
  ### Step 3: Classify every AC — does it describe user-visible behavior?
89
95
 
90
96
  **BEFORE searching for evidence, classify each AC as either UI-facing or code-only.**
@@ -126,7 +132,7 @@ For every UI-facing AC:
126
132
  ```
127
133
  1. Check chrome-devtools MCP availability (`mcp__chrome_devtools__*`).
128
134
  2. If available:
129
- - Start the app (dev server or served build) in the current repo.
135
+ - Start the app (dev server or served build) in the current repo. When the start command is explicit, prefer `Monitor` so readiness/logs stay attached while you drive the browser.
130
136
  - Drive the flow described in the AC: `click` / `type_text` / `fill` / `navigate_page`.
131
137
  - Capture evidence with `take_screenshot`, `list_console_messages`, and `list_network_requests`.
132
138
  - Compare observed behavior against the AC text.
@@ -154,6 +160,14 @@ curl -X POST localhost:3000/login -d '{...}' -w '%{http_code}'
154
160
 
155
161
  **Must** actually run — "tests should pass" is not allowed.
156
162
 
163
+ For `VF-original-issue`, verify `.progress.md` contains:
164
+ - `Reality Check (BEFORE)` with a concrete reproduction command and observed failure output.
165
+ - `Reality Check (AFTER)` with the same command rerun.
166
+ - An explicit comparison showing the original failure disappeared.
167
+ - `Verified: Issue resolved` only when the evidence supports it.
168
+
169
+ If any piece is missing, mark `VF-original-issue` as `partial` or `failed`; do not allow a full PASS based solely on green tests.
170
+
157
171
  ### Step 5: Stub Detection
158
172
 
159
173
  Look for "fake implementations" in the code:
@@ -170,6 +184,18 @@ For each match, check:
170
184
  - Is it on an FR/AC-covered path?
171
185
  - If yes → flag as "fake implementation"
172
186
 
187
+ ### Step 5a: Test Quality Gate
188
+
189
+ Apply `@${CLAUDE_PLUGIN_ROOT}/gates/test-quality-gate.md` to every test used as FR/AC evidence.
190
+
191
+ Flag tests as weak evidence when:
192
+ - Assertions only inspect mocks/spies and never verify externally observable behavior.
193
+ - Mock/stub/spy setup is more than 3x real behavioral assertions.
194
+ - Test is skipped, assertion-free, or would pass with an empty implementation.
195
+ - Stateful mocks lack cleanup and can leak between tests.
196
+
197
+ If a weak test is the only evidence for an FR/AC, downgrade that assertion to `partial` or `unverified`; do not count it as fully verified.
198
+
173
199
  ### Step 6: Generate verification-report.md
174
200
 
175
201
  **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.
@@ -191,6 +217,8 @@ Verifier: flow-verifier
191
217
  - ⚠ Partial: M / Total
192
218
  - ✗ Unverified: K / Total
193
219
  - 🚨 Fake impl: X sites
220
+ - 🔁 Reality VF: PASS | PARTIAL | N/A
221
+ - 🧪 Test quality: PASS | WARN | FAIL
194
222
 
195
223
  ## Detailed Checklist
196
224
 
@@ -257,6 +285,8 @@ export async function logout(token: string) {
257
285
  - 2 need tests ⚠
258
286
  - 1 not implemented ✗
259
287
  - 1 fake implementation 🚨
288
+ - Reality verification: PASS | PARTIAL | N/A
289
+ - Test quality: PASS | WARN | FAIL
260
290
 
261
291
  **Suggested next steps**:
262
292
  1. Fix the fake implementation (logout.ts) — blocking
@@ -284,8 +314,10 @@ else:
284
314
  ## Forbidden
285
315
 
286
316
  - ✗ Trusting .progress.md's "done" claims without verification
317
+ - ✗ Giving a fix/debug spec full PASS without BEFORE/AFTER reality verification or explicit D-NN waiver
287
318
  - ✗ Skipping actual test runs
288
319
  - ✗ Letting fake implementations slide (`// TODO:` on critical paths)
320
+ - ✗ Treating mock-only or skipped tests as full FR/AC evidence
289
321
  - ✗ Claiming "looks good" without concrete evidence (violates verification-gate)
290
322
 
291
323
  ## Quality Self-Check
package/cli/README.md CHANGED
@@ -36,10 +36,12 @@ Steps:
36
36
  | `--all` | Install all recommended plugins, no prompt |
37
37
  | `--no-deps` | Install only curdx-flow itself |
38
38
 
39
- ### `doctor [--verbose]`
39
+ ### `doctor [--verbose] [--fix]`
40
40
 
41
41
  External diagnostics: claude CLI / curdx-flow / required MCPs / recommended plugins / current directory `.flow/` state.
42
42
 
43
+ `--fix` applies the safe automatic repairs the CLI can perform without guessing — currently the `bun` / `uv` PATH symlinks used by `claude-mem`. Everything else remains diagnostic-only.
44
+
43
45
  ### Project initialization (not a CLI command)
44
46
 
45
47
  Project initialization is a Claude Code slash command, not a CLI one. After `install`, open your project in Claude Code and run:
@@ -1,10 +1,13 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
 
4
+ import { readProjectClaudeSettings } from "./lib/doctor-claude-settings.js";
5
+ import { inspectRuntimeEnvironment } from "./lib/doctor-runtime-environment.js";
4
6
  import {
5
7
  claudeVersion,
6
8
  color,
7
9
  ensureClaudeMemRuntimes,
10
+ inspectClaudeMemRuntimes,
8
11
  listMcps,
9
12
  listPluginMarketplaces,
10
13
  listPlugins,
@@ -13,12 +16,140 @@ import {
13
16
  runSync,
14
17
  } from "./utils.js";
15
18
 
19
+ export { readProjectClaudeSettings };
20
+ export { inspectRuntimeEnvironment };
21
+
16
22
  export function createDoctorContext(args = []) {
17
23
  return {
24
+ fix: args.includes("--fix"),
18
25
  verbose: args.includes("--verbose") || args.includes("-v"),
19
26
  };
20
27
  }
21
28
 
29
+ function isUrlLike(value) {
30
+ return /^[a-z][a-z0-9+.-]*:\/\//i.test(value);
31
+ }
32
+
33
+ function isWindowsAbsolutePath(value) {
34
+ return /^[A-Za-z]:[\\/]/.test(value);
35
+ }
36
+
37
+ function looksLikeRelativePathToken(value) {
38
+ if (typeof value !== "string") return false;
39
+ const token = value.trim();
40
+ if (!token) return false;
41
+
42
+ if (token.startsWith("./") || token.startsWith("../")) return true;
43
+ if (!/[\\/]/.test(token)) return false;
44
+
45
+ if (
46
+ token.startsWith("/") ||
47
+ token.startsWith("~/") ||
48
+ token.startsWith("${") ||
49
+ token.startsWith("@") ||
50
+ token.startsWith("--") ||
51
+ isUrlLike(token) ||
52
+ isWindowsAbsolutePath(token)
53
+ ) {
54
+ return false;
55
+ }
56
+
57
+ return (
58
+ /\.(?:[cm]?js|mjs|ts|tsx|jsx|py|rb|sh|bash|zsh|fish|ps1|cmd|bat|exe)$/i.test(token) ||
59
+ /(^|[\\/])(?:scripts?|bin|dist|src|tools|vendor|node_modules|venv|\.venv)([\\/]|$)/i.test(token)
60
+ );
61
+ }
62
+ export async function readProjectMcpConfig(cwd = process.cwd()) {
63
+ const rootPath = path.join(cwd, ".mcp.json");
64
+ const misplacedPath = path.join(cwd, ".claude", ".mcp.json");
65
+
66
+ const state = {
67
+ exists: false,
68
+ misplacedExists: false,
69
+ invalid: false,
70
+ parseError: null,
71
+ shapeError: null,
72
+ serverCount: 0,
73
+ relativePathWarnings: [],
74
+ };
75
+
76
+ try {
77
+ const misplacedStat = await fs.stat(misplacedPath);
78
+ state.misplacedExists = misplacedStat.isFile();
79
+ } catch {
80
+ state.misplacedExists = false;
81
+ }
82
+
83
+ try {
84
+ const stat = await fs.stat(rootPath);
85
+ if (!stat.isFile()) return state;
86
+ state.exists = true;
87
+ } catch {
88
+ return state;
89
+ }
90
+
91
+ let parsed;
92
+ try {
93
+ parsed = JSON.parse(await fs.readFile(rootPath, "utf-8"));
94
+ } catch (error) {
95
+ state.invalid = true;
96
+ state.parseError = error.message;
97
+ return state;
98
+ }
99
+
100
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
101
+ state.shapeError = "root value must be a JSON object";
102
+ return state;
103
+ }
104
+
105
+ if (!parsed.mcpServers || typeof parsed.mcpServers !== "object" || Array.isArray(parsed.mcpServers)) {
106
+ state.shapeError = 'missing top-level "mcpServers" object';
107
+ return state;
108
+ }
109
+
110
+ state.serverCount = Object.keys(parsed.mcpServers).length;
111
+
112
+ for (const [serverName, config] of Object.entries(parsed.mcpServers)) {
113
+ if (!config || typeof config !== "object" || Array.isArray(config)) continue;
114
+
115
+ if (looksLikeRelativePathToken(config.command)) {
116
+ state.relativePathWarnings.push({
117
+ serverName,
118
+ field: "command",
119
+ value: config.command,
120
+ });
121
+ }
122
+
123
+ const args = Array.isArray(config.args) ? config.args : [];
124
+ args.forEach((arg, index) => {
125
+ if (!looksLikeRelativePathToken(arg)) return;
126
+ state.relativePathWarnings.push({
127
+ serverName,
128
+ field: `args[${index}]`,
129
+ value: arg,
130
+ });
131
+ });
132
+ }
133
+
134
+ return state;
135
+ }
136
+
137
+ export async function readProjectTeamConfig(cwd = process.cwd()) {
138
+ const teamConfigPath = path.join(cwd, ".claude", "teams", "teams.json");
139
+ const state = {
140
+ exists: false,
141
+ };
142
+
143
+ try {
144
+ const stat = await fs.stat(teamConfigPath);
145
+ state.exists = stat.isFile();
146
+ } catch {
147
+ state.exists = false;
148
+ }
149
+
150
+ return state;
151
+ }
152
+
22
153
  export async function readProjectState(cwd = process.cwd()) {
23
154
  const flowDir = path.join(cwd, ".flow");
24
155
  try {
@@ -48,8 +179,12 @@ export async function collectDoctorData(
48
179
  listPluginMarketplacesImpl = listPluginMarketplaces,
49
180
  listMcpsImpl = listMcps,
50
181
  readUserMcpConfigImpl = readUserMcpConfig,
51
- ensureClaudeMemRuntimesImpl = ensureClaudeMemRuntimes,
182
+ inspectClaudeMemRuntimesImpl = inspectClaudeMemRuntimes,
183
+ inspectRuntimeEnvironmentImpl = inspectRuntimeEnvironment,
52
184
  readProjectStateImpl = readProjectState,
185
+ readProjectMcpConfigImpl = readProjectMcpConfig,
186
+ readProjectTeamConfigImpl = readProjectTeamConfig,
187
+ readProjectClaudeSettingsImpl = readProjectClaudeSettings,
53
188
  } = {}
54
189
  ) {
55
190
  const claudeVersionValue = claudeVersionImpl();
@@ -60,7 +195,7 @@ export async function collectDoctorData(
60
195
  const runtimeStatus = plugins.some(
61
196
  (plugin) => plugin.name === "claude-mem" && plugin.status === "enabled"
62
197
  )
63
- ? ensureClaudeMemRuntimesImpl()
198
+ ? inspectClaudeMemRuntimesImpl()
64
199
  : null;
65
200
 
66
201
  return {
@@ -71,11 +206,39 @@ export async function collectDoctorData(
71
206
  mcps,
72
207
  userMcpConfig,
73
208
  runtimeStatus,
209
+ runtimeEnvironment: inspectRuntimeEnvironmentImpl(),
74
210
  cwd,
75
211
  projectState: await readProjectStateImpl(cwd),
212
+ projectMcpConfig: await readProjectMcpConfigImpl(cwd),
213
+ projectTeamConfig: await readProjectTeamConfigImpl(cwd),
214
+ projectClaudeSettings: await readProjectClaudeSettingsImpl(cwd),
76
215
  };
77
216
  }
78
217
 
218
+ export async function applyDoctorFixes(
219
+ doctorData,
220
+ {
221
+ ensureClaudeMemRuntimesImpl = ensureClaudeMemRuntimes,
222
+ } = {}
223
+ ) {
224
+ const fixes = [];
225
+ const claudeMemEnabled = doctorData.plugins.some(
226
+ (plugin) => plugin.name === "claude-mem" && plugin.status === "enabled"
227
+ );
228
+
229
+ if (!claudeMemEnabled) {
230
+ return fixes;
231
+ }
232
+
233
+ const runtimeStatus = ensureClaudeMemRuntimesImpl();
234
+ doctorData.runtimeStatus = runtimeStatus;
235
+ fixes.push({
236
+ kind: "claude-mem-runtimes",
237
+ runtimeStatus,
238
+ });
239
+ return fixes;
240
+ }
241
+
79
242
  export function renderReportLines(lines, { logImpl = log } = {}) {
80
243
  for (const line of lines) {
81
244
  if (line.level === "ok") {
package/cli/doctor.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  } from "./utils.js";
9
9
  import { buildDoctorReport } from "./lib/doctor-report.js";
10
10
  import {
11
+ applyDoctorFixes,
11
12
  collectDoctorData,
12
13
  createDoctorContext,
13
14
  printDoctorSummary,
@@ -21,6 +22,13 @@ export async function doctor(args = []) {
21
22
  log.title("🏥 CurdX-Flow Health Check");
22
23
 
23
24
  const doctorData = await collectDoctorData();
25
+ if (context.fix) {
26
+ log.info("Applying safe fixes...");
27
+ const fixes = await applyDoctorFixes(doctorData);
28
+ if (fixes.length === 0) {
29
+ log.info("No automatic fixes available for the current environment");
30
+ }
31
+ }
24
32
  const report = buildDoctorReport(doctorData);
25
33
 
26
34
  renderReportLines(report.lines);