docguard-cli 0.9.11 → 0.11.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/PHILOSOPHY.md +59 -106
- package/README.md +26 -3
- package/cli/commands/diagnose.mjs +171 -58
- package/cli/commands/diff.mjs +110 -137
- package/cli/commands/fix.mjs +152 -4
- package/cli/commands/generate.mjs +148 -27
- package/cli/commands/guard.mjs +45 -24
- package/cli/commands/hooks.mjs +40 -2
- package/cli/commands/score.mjs +22 -0
- package/cli/commands/sync.mjs +123 -0
- package/cli/docguard.mjs +22 -0
- package/cli/scanners/api-doc.mjs +122 -0
- package/cli/scanners/doc-tools.mjs +1 -1
- package/cli/scanners/frontend.mjs +438 -0
- package/cli/scanners/integrations.mjs +116 -0
- package/cli/scanners/memory-plan.mjs +242 -0
- package/cli/scanners/project-type.mjs +310 -0
- package/cli/scanners/routes.mjs +194 -32
- package/cli/scanners/schemas.mjs +174 -1
- package/cli/shared-source.mjs +247 -0
- package/cli/validators/api-surface.mjs +254 -0
- package/cli/validators/architecture.mjs +4 -3
- package/cli/validators/changelog.mjs +45 -4
- package/cli/validators/doc-quality.mjs +3 -2
- package/cli/validators/docs-coverage.mjs +9 -14
- package/cli/validators/docs-diff.mjs +117 -66
- package/cli/validators/docs-sync.mjs +30 -24
- package/cli/validators/drift.mjs +6 -2
- package/cli/validators/environment.mjs +43 -3
- package/cli/validators/freshness.mjs +4 -3
- package/cli/validators/metadata-sync.mjs +17 -7
- package/cli/validators/metrics-consistency.mjs +9 -4
- package/cli/validators/schema-sync.mjs +19 -10
- package/cli/validators/security.mjs +20 -7
- package/cli/validators/structure.mjs +8 -1
- package/cli/validators/test-spec.mjs +26 -17
- package/cli/validators/todo-tracking.mjs +21 -8
- package/cli/validators/traceability.mjs +61 -36
- package/cli/writers/api-reference.mjs +101 -0
- package/cli/writers/mechanical.mjs +116 -0
- package/cli/writers/sections.mjs +148 -0
- package/commands/docguard.fix.md +19 -3
- package/commands/docguard.guard.md +5 -4
- package/docs/doc-sections.md +37 -0
- package/docs/quickstart.md +1 -1
- package/extensions/spec-kit-docguard/README.md +8 -5
- package/extensions/spec-kit-docguard/commands/fix.md +74 -0
- package/extensions/spec-kit-docguard/commands/generate.md +25 -2
- package/extensions/spec-kit-docguard/commands/guard.md +6 -5
- package/extensions/spec-kit-docguard/commands/sync.md +62 -0
- package/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +11 -1
- package/extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md +3 -2
- package/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +111 -0
- package/package.json +1 -1
- package/templates/commands/docguard.guard.md +3 -3
package/PHILOSOPHY.md
CHANGED
|
@@ -1,172 +1,125 @@
|
|
|
1
1
|
# The Philosophy of Canonical-Driven Development
|
|
2
2
|
|
|
3
|
-
> Why
|
|
3
|
+
> Why every codebase needs a living, machine-readable memory — and how DocGuard builds and maintains one.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## The Problem We're Solving
|
|
8
8
|
|
|
9
|
-
In 2026, AI coding agents can write thousands of lines of code in minutes.
|
|
9
|
+
In 2026, AI coding agents can write thousands of lines of code in minutes. But they have a fatal flaw: **they don't remember.**
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Every new session, every new agent, every new conversation starts from zero. The agent re-reads your code, re-derives how the system works, makes assumptions, and builds on them. Humans hit the same wall: a new contributor faces 500 files and a 50-line README.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
This is the **comprehension crisis of the AI era:**
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
> The faster AI writes code, the faster projects lose their design intent.
|
|
15
|
+
> The faster AI writes code, the faster everyone loses the map of what was built.
|
|
18
16
|
|
|
19
17
|
---
|
|
20
18
|
|
|
21
19
|
## The Insight
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
A project needs a **canonical memory** — a complete, structured, always-current description of what the system *is*: every endpoint, screen, entity, the architecture, the tech stack, the setup. Written so an AI agent (or a human) can load it in seconds and understand the whole project without re-reading the code.
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
DocGuard's job is to **build that memory from the code, keep it true as the code changes, and protect the human reasoning inside it.**
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
> **Canonical** (adj.): accepted as accurate and authoritative; the standard form.
|
|
28
26
|
|
|
29
27
|
---
|
|
30
28
|
|
|
31
29
|
## The Three Pillars of CDD
|
|
32
30
|
|
|
33
|
-
### Pillar 1: Documentation
|
|
34
|
-
|
|
35
|
-
In traditional development, code is the source of truth. Documentation is an afterthought — written after code (if at all), rarely updated, and quickly stale.
|
|
36
|
-
|
|
37
|
-
In CDD, this is inverted:
|
|
38
|
-
|
|
39
|
-
| Traditional | CDD |
|
|
40
|
-
|-------------|-----|
|
|
41
|
-
| Code first, docs maybe | Docs first, code conforms |
|
|
42
|
-
| Docs describe code | Code implements docs |
|
|
43
|
-
| Docs rot silently | Drift is tracked explicitly |
|
|
44
|
-
| Docs are optional | Docs are required and validated |
|
|
31
|
+
### Pillar 1: Documentation is a first-class, validated artifact
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
- When starting a project, write `ARCHITECTURE.md` before `index.ts`
|
|
48
|
-
- When adding a feature, update `FEATURES.md` before opening your editor
|
|
49
|
-
- When the code deviates, log it in `DRIFT-LOG.md` instead of pretending the docs are wrong
|
|
33
|
+
In traditional development, docs are an afterthought — written late (if at all), never updated, quickly stale. CDD makes documentation a **required, validated, and maintained** artifact, on the same footing as tests. If it isn't validated on every change, it rots; so DocGuard validates it.
|
|
50
34
|
|
|
51
|
-
### Pillar 2: Two
|
|
35
|
+
### Pillar 2: Two tiers — derived truth and human reasoning
|
|
52
36
|
|
|
53
|
-
CDD separates documentation into two
|
|
37
|
+
CDD separates documentation into two kinds of content, and treats them differently:
|
|
54
38
|
|
|
55
|
-
|
|
39
|
+
- **Code-derived** (endpoints, entities, screens, tech stack, env vars): DocGuard generates and re-generates these *from the code*. They are mechanical, and DocGuard owns them.
|
|
40
|
+
- **Human reasoning** (the "why", design intent, trade-offs, gotchas): authored by people (or an AI agent), and **never overwritten** by the tool.
|
|
56
41
|
|
|
57
|
-
|
|
42
|
+
DocGuard keeps these in the same readable markdown using section markers
|
|
43
|
+
(`<!-- docguard:section id=… source=code -->`), so it can refresh the derived
|
|
44
|
+
parts surgically while leaving your writing untouched.
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
- Pretending the docs are still accurate (lying)
|
|
61
|
-
- Silently updating docs to match the broken code (losing intent)
|
|
46
|
+
### Pillar 3: Generate AND Guard — bidirectional, continuous
|
|
62
47
|
|
|
63
|
-
|
|
48
|
+
Earlier versions of this document framed CDD as "validate code against docs, never generate docs from code." Experience proved that too narrow. The tool people actually want does **both directions, continuously:**
|
|
64
49
|
|
|
65
|
-
|
|
50
|
+
| Direction | Mode | What it does |
|
|
51
|
+
|-----------|------|--------------|
|
|
52
|
+
| code → docs | **Generate** | Reverse-engineer a complete canonical memory from any codebase. DocGuard scans and builds the code-truth skeleton; an AI agent writes the prose. |
|
|
53
|
+
| code ↔ docs | **Sync** | When code changes, refresh the affected doc sections automatically — mechanical where deterministic, agent-assisted for prose. |
|
|
54
|
+
| docs ↔ code | **Guard** | Validate that the memory still matches reality. Catch documented-but-deleted endpoints, undocumented routes, missing tests, unlogged drift. |
|
|
66
55
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
| Generated Docs (traditional) | Enforced Docs (CDD) |
|
|
70
|
-
|------------------------------|---------------------|
|
|
71
|
-
| Machine reads code → produces docs | Machine reads docs → validates code |
|
|
72
|
-
| Docs always match code (including bugs) | Docs represent intent (bugs are caught as drift) |
|
|
73
|
-
| Docs are disposable artifacts | Docs are authoritative sources |
|
|
74
|
-
| No governance, no warnings | Validators catch misalignment |
|
|
75
|
-
|
|
76
|
-
DocGuard CAN generate docs from existing codebases (for adoption). But the intent is that once generated, those docs become the canonical source — and future code must conform to them.
|
|
56
|
+
The CLI orchestrates (scan, structure, verify); the AI agent does the language-specific writing. Together they keep the memory both **complete** and **accurate**.
|
|
77
57
|
|
|
78
58
|
---
|
|
79
59
|
|
|
80
|
-
##
|
|
81
|
-
|
|
82
|
-
Three forces are converging in 2025-2026 that make CDD necessary:
|
|
60
|
+
## Complete + Accurate = Trustworthy
|
|
83
61
|
|
|
84
|
-
|
|
62
|
+
A memory is only useful if you can trust it. DocGuard measures two things:
|
|
85
63
|
|
|
86
|
-
|
|
64
|
+
- **Completeness** — is the map whole? (No missing chapters: architecture, data model, API surface, screens, environment.)
|
|
65
|
+
- **Accuracy** — does the map match the territory? (The documented endpoints exist; the documented env vars are used; the schemas match the models.)
|
|
87
66
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
It's common for a single project to be worked on by Claude Code, Copilot, Cursor, and a human — sometimes in the same week. Each agent needs a common source of truth. `AGENTS.md` provides behavioral rules; canonical docs provide design knowledge.
|
|
91
|
-
|
|
92
|
-
### 3. The Documentation Crisis Is Accelerating
|
|
93
|
-
|
|
94
|
-
AI makes it trivially easy to add code. Nobody is making it easy to maintain documentation. The result: projects with 100,000 lines of code and a 50-line README. CDD addresses this by making documentation a first-class, validated artifact.
|
|
67
|
+
A document can be beautifully formatted and completely wrong. DocGuard's validators that compare docs against **code truth** are what make a green check mean something — and when a check has nothing to validate, it says so honestly instead of showing a misleading pass.
|
|
95
68
|
|
|
96
69
|
---
|
|
97
70
|
|
|
98
|
-
##
|
|
99
|
-
|
|
100
|
-
CDD doesn't replace existing methodologies. It enhances them:
|
|
101
|
-
|
|
102
|
-
### CDD + TDD (Test-Driven Development)
|
|
103
|
-
Write canonical docs first. The TEST-SPEC.md in your canonical docs declares what tests must exist. TDD then drives the implementation of those tests. CDD governs the test policy; TDD governs the test implementation.
|
|
104
|
-
|
|
105
|
-
### CDD + BDD (Behavior-Driven Development)
|
|
106
|
-
Behavior specifications can live in `docs-canonical/FEATURES.md`. BDD's Given/When/Then scenarios become part of the canonical record. DocGuard can validate that corresponding E2E tests exist.
|
|
71
|
+
## Any language, any project
|
|
107
72
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
73
|
+
DocGuard documents **any** project, not just web/JS. It detects the ecosystem
|
|
74
|
+
(JavaScript/TypeScript, Python, Rust, Go, Java/Kotlin, Ruby, PHP, C#) and any
|
|
75
|
+
polyglot/monorepo mix, then builds a memory shaped for that project: a Rust CLI
|
|
76
|
+
gets a Rust-shaped doc set; a Django app a Django-shaped one; a React app gets
|
|
77
|
+
its screens and components.
|
|
113
78
|
|
|
114
79
|
---
|
|
115
80
|
|
|
116
|
-
##
|
|
117
|
-
|
|
118
|
-
If your project follows CDD:
|
|
119
|
-
|
|
120
|
-
1. **Any AI agent can onboard** to your project in seconds — not minutes of code analysis, but seconds of reading structured documentation.
|
|
121
|
-
|
|
122
|
-
2. **Design intent is never lost** — even when the original developer leaves, the canonical docs preserve WHY the system was designed the way it was.
|
|
123
|
-
|
|
124
|
-
3. **Drift is conscious** — every deviation from the plan is documented, justified, and trackable. No silent rot.
|
|
125
|
-
|
|
126
|
-
4. **Quality is enforceable** — DocGuard validators run in CI/CD, catching missing tests, undocumented routes, and unlogged drift before code ships.
|
|
81
|
+
## Why Now?
|
|
127
82
|
|
|
128
|
-
|
|
83
|
+
1. **AI agents are primary developers.** They need structured context to work well. A canonical memory is the highest-leverage context you can give them.
|
|
84
|
+
2. **Multi-agent development is real.** Claude Code, Copilot, Cursor, and humans touch the same repo in the same week. They need one shared, current source of truth.
|
|
85
|
+
3. **Code volume is exploding; comprehension isn't keeping up.** AI makes adding code trivial. DocGuard makes *understanding* it trivial — and keeps that understanding current.
|
|
129
86
|
|
|
130
87
|
---
|
|
131
88
|
|
|
132
|
-
##
|
|
89
|
+
## The Lifecycle
|
|
133
90
|
|
|
134
|
-
|
|
91
|
+
```
|
|
92
|
+
generate ──▶ guard ──▶ sync ──▶ guard ──▶ …
|
|
93
|
+
(build) (verify) (keep (verify)
|
|
94
|
+
current)
|
|
95
|
+
```
|
|
135
96
|
|
|
136
|
-
**Day 1
|
|
97
|
+
- **Day 1:** `docguard generate --plan` → a complete first-draft memory of your repo (agent fills the prose).
|
|
98
|
+
- **Every change:** `docguard sync` refreshes the derived sections; `docguard guard` verifies; the agent updates prose where flagged.
|
|
99
|
+
- **Forever:** the memory stays complete and true. Any agent or human can understand your project in seconds.
|
|
137
100
|
|
|
138
|
-
|
|
101
|
+
---
|
|
139
102
|
|
|
140
|
-
|
|
103
|
+
## CDD and Other Methodologies
|
|
141
104
|
|
|
142
|
-
|
|
105
|
+
- **+ Spec Kit (SDD):** Spec Kit generates code from specs (the build phase); DocGuard maintains the living memory and governance afterward. DocGuard ships as a Spec Kit extension.
|
|
106
|
+
- **+ TDD/BDD:** `TEST-SPEC.md` declares what must be tested; DocGuard verifies the tests exist; TDD/BDD drive their implementation.
|
|
107
|
+
- **+ Agile:** the memory grows sprint by sprint alongside the code. A 30-line `ARCHITECTURE.md` that is complete, current, and validated beats a 300-page document that's stale.
|
|
143
108
|
|
|
144
109
|
---
|
|
145
110
|
|
|
146
111
|
## Academic Foundations
|
|
147
112
|
|
|
148
|
-
CDD is a practitioner methodology
|
|
149
|
-
|
|
150
|
-
### The Three-Stage Pipeline
|
|
151
|
-
|
|
152
|
-
DocGuard's architecture follows a **generate → validate → evaluate** pipeline inspired by the AITPG framework (Lopez et al., IEEE TSE 2026), which demonstrated that multi-agent debate over RAG-grounded standards produces 32% more comprehensive documentation while maintaining semantic alignment with expert references.
|
|
153
|
-
|
|
154
|
-
### Calibrated Quality Evaluation
|
|
113
|
+
CDD is a practitioner methodology whose patterns align with peer-reviewed research:
|
|
155
114
|
|
|
156
|
-
|
|
115
|
+
- **Generate → validate → evaluate pipeline** — inspired by the AITPG framework (Lopez et al., IEEE TSE 2026): multi-agent generation grounded in standards produces more comprehensive documentation while staying semantically aligned with expert references.
|
|
116
|
+
- **Calibrated quality evaluation** — DocGuard's HIGH/MEDIUM/LOW labels and multi-signal scoring adapt the CJE framework from TRACE (Lopez et al., IEEE TMLCN 2026).
|
|
117
|
+
- **Standards-grounded generation** — each canonical document maps to a relevant standard (arc42, C4, OWASP ASVS, ISO 29119, OpenAPI, 12-Factor App).
|
|
157
118
|
|
|
158
|
-
### Standards-Grounded Generation
|
|
159
|
-
|
|
160
|
-
Both AITPG and TRACE demonstrate that grounding AI-generated content in vectorized standards (ISO 29119, 3GPP) dramatically improves output quality. DocGuard applies this principle by mapping each canonical document to its relevant industry standard (arc42, C4, OWASP ASVS, ISO 29119, OpenAPI 3.1, 12-Factor App).
|
|
161
|
-
|
|
162
|
-
> **Full citations**: See [CONTRIBUTING.md — Research & Academic Credits](CONTRIBUTING.md#research--academic-credits)
|
|
163
|
-
>
|
|
164
119
|
> **Lead researcher**: [Martin Manuel Lopez](https://github.com/martinmanuel9) · [ORCID 0009-0002-7652-2385](https://orcid.org/0009-0002-7652-2385), University of Arizona
|
|
165
120
|
|
|
166
121
|
---
|
|
167
122
|
|
|
168
123
|
## License
|
|
169
124
|
|
|
170
|
-
This philosophy document and the CDD methodology are released under the [MIT License](https://opensource.org/licenses/MIT).
|
|
171
|
-
|
|
172
|
-
CDD is an open methodology. Anyone can adopt, adapt, and contribute to it.
|
|
125
|
+
This philosophy document and the CDD methodology are released under the [MIT License](https://opensource.org/licenses/MIT). CDD is an open methodology — anyone can adopt, adapt, and contribute.
|
package/README.md
CHANGED
|
@@ -130,7 +130,28 @@ diagnose → AI reads prompts → AI fixes docs → guard verifies
|
|
|
130
130
|
└───────────────── issues found? ←──────────────────────┘
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
`diagnose` is the primary command. It runs all validators, maps every failure to an AI-actionable fix prompt, and outputs a remediation plan. Your AI agent runs it, fixes the docs, and runs `guard` to verify.
|
|
133
|
+
`diagnose` is the primary command. It runs all validators, maps every failure to an AI-actionable fix prompt, and outputs a remediation plan. Your AI agent runs it, fixes the docs, and runs `guard` to verify.
|
|
134
|
+
|
|
135
|
+
### Mechanical vs. agent fixes
|
|
136
|
+
|
|
137
|
+
DocGuard splits drift into two kinds and is explicit about which is which:
|
|
138
|
+
|
|
139
|
+
| Kind | Example | How it's fixed |
|
|
140
|
+
|------|---------|----------------|
|
|
141
|
+
| **Mechanical** (deterministic) | An endpoint documented in `API-REFERENCE.md` that the OpenAPI spec confirms is gone | `docguard fix --write` deletes the row + detail block itself — **no AI** |
|
|
142
|
+
| **Agent** (needs judgment) | Rewriting an X-Ray prose section as CloudWatch; writing a new endpoint's request/response | Routed to an AI agent via `diagnose` / `fix --doc` prompts |
|
|
143
|
+
|
|
144
|
+
`docguard fix --write` only touches docs marked `<!-- docguard:generated true -->` (override with `--force`), is idempotent, and prints exactly what changed. It never rewrites prose — that stays with the agent.
|
|
145
|
+
|
|
146
|
+
### Hands-off loop (set and forget)
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
guard ──▶ fix --write (mechanical, auto) ──▶ guard ──▶ diagnose (agent prompts for the rest)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- **CI / pre-commit:** `docguard hooks --type pre-commit --auto-fix` installs a hook that applies mechanical fixes, re-stages the docs, then runs `guard`; anything left is surfaced as agent prompts.
|
|
153
|
+
- **Agent-driven:** `docguard diagnose --auto` scaffolds missing docs **and** applies mechanical fixes, then emits prompts for the content rewrites that remain.
|
|
154
|
+
- **JSON for automation:** `guard`/`diagnose --format json` include a `mechanicalFixes` array and tag each issue `mechanical` vs `agent`, so an agent can apply or delegate precisely.
|
|
134
155
|
|
|
135
156
|
---
|
|
136
157
|
|
|
@@ -192,6 +213,7 @@ DocGuard ships **13 commands**:
|
|
|
192
213
|
| `init` | Initialize CDD docs from templates (interactive) |
|
|
193
214
|
| `score` | CDD maturity score (0–100) with weighted breakdown |
|
|
194
215
|
| `fix --doc <name>` | Generate AI prompt for a specific document |
|
|
216
|
+
| `fix --write` | Apply deterministic fixes (remove stale documented endpoints) — no AI |
|
|
195
217
|
| `diff` | Compare canonical docs vs actual code artifacts |
|
|
196
218
|
| `agents` | Generate agent-specific config files |
|
|
197
219
|
| `trace` | Requirements traceability matrix |
|
|
@@ -251,7 +273,7 @@ DocGuard runs **19 automated validators** on every `guard` check:
|
|
|
251
273
|
| 1 | **Structure** | Required CDD files exist | ✅ On |
|
|
252
274
|
| 2 | **Doc Sections** | Canonical docs have required sections | ✅ On |
|
|
253
275
|
| 3 | **Docs-Sync** | Routes/services referenced in docs + OpenAPI cross-check | ✅ On |
|
|
254
|
-
| 4 | **Drift** | `// DRIFT:` comments logged in DRIFT-LOG.md | ✅ On |
|
|
276
|
+
| 4 | **Drift-Comments** | `// DRIFT:` comments logged in DRIFT-LOG.md | ✅ On |
|
|
255
277
|
| 5 | **Changelog** | CHANGELOG.md has [Unreleased] section | ✅ On |
|
|
256
278
|
| 6 | **Test-Spec** | Tests exist per TEST-SPEC.md rules | ✅ On |
|
|
257
279
|
| 7 | **Environment** | Env vars documented, .env.example exists | ✅ On |
|
|
@@ -267,6 +289,7 @@ DocGuard runs **19 automated validators** on every `guard` check:
|
|
|
267
289
|
| 17 | **TODO-Tracking** | Untracked TODOs/FIXMEs and skipped tests | ✅ On |
|
|
268
290
|
| 18 | **Schema-Sync** | Database models documented in DATA-MODEL.md | ✅ On |
|
|
269
291
|
| 19 | **Spec-Kit** | Spec quality validation (FR-IDs, mandatory sections, phased tasks) | ✅ On |
|
|
292
|
+
| 20 | **API-Surface** | API-REFERENCE.md endpoints match the real API surface (OpenAPI spec / routes); flags documented-but-deleted endpoints | ✅ On |
|
|
270
293
|
|
|
271
294
|
---
|
|
272
295
|
|
|
@@ -320,7 +343,7 @@ DocGuard provides AI agent slash commands for integrated workflows. Installed au
|
|
|
320
343
|
|
|
321
344
|
| Command | What It Does |
|
|
322
345
|
|:--------|:-------------|
|
|
323
|
-
| `/docguard.guard` | Run quality validation — check all
|
|
346
|
+
| `/docguard.guard` | Run quality validation — check all 20 validators |
|
|
324
347
|
| `/docguard.review` | Analyze doc quality and suggest improvements |
|
|
325
348
|
| `/docguard.fix` | Generate targeted fix prompts for specific issues |
|
|
326
349
|
| `/docguard.score` | Show CDD maturity score with category breakdown |
|
|
@@ -20,20 +20,22 @@ import { detectAgentMode, isSpecKitInitialized } from '../ensure-skills.mjs';
|
|
|
20
20
|
import { existsSync, readFileSync } from 'node:fs';
|
|
21
21
|
import { resolve, dirname } from 'node:path';
|
|
22
22
|
import { fileURLToPath } from 'node:url';
|
|
23
|
-
import { execSync } from 'node:child_process';
|
|
23
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
24
|
+
import { applyAllMechanicalFixes } from './fix.mjs';
|
|
24
25
|
|
|
25
26
|
// Map validator failures to the right fix --doc target
|
|
26
27
|
const VALIDATOR_TO_DOC = {
|
|
27
|
-
'Structure':
|
|
28
|
-
'Doc Sections':
|
|
29
|
-
'Docs-Sync':
|
|
30
|
-
'Drift':
|
|
31
|
-
'Changelog':
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
28
|
+
'Structure': null, // structural — needs init, not doc fix
|
|
29
|
+
'Doc Sections': null, // section-level — maps to specific doc
|
|
30
|
+
'Docs-Sync': null, // cross-reference — needs manual review
|
|
31
|
+
'Drift-Comments': null, // drift log maintenance
|
|
32
|
+
'Changelog': null, // changelog maintenance
|
|
33
|
+
'API-Surface': 'api-reference',
|
|
34
|
+
'Test-Spec': 'test-spec',
|
|
35
|
+
'Environment': 'environment',
|
|
36
|
+
'Security': 'security',
|
|
37
|
+
'Architecture': 'architecture',
|
|
38
|
+
'Freshness': null, // freshness — maps to stale doc
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
// Actionable fix instructions per validator (LLM-first: includes both skill and CLI commands)
|
|
@@ -59,9 +61,9 @@ const FIX_INSTRUCTIONS = {
|
|
|
59
61
|
description: 'Documentation references are out of sync with code. Review and update component maps.',
|
|
60
62
|
autoFixable: false,
|
|
61
63
|
},
|
|
62
|
-
'Drift': {
|
|
64
|
+
'Drift-Comments': {
|
|
63
65
|
action: 'Update DRIFT-LOG.md',
|
|
64
|
-
description: '
|
|
66
|
+
description: 'A // DRIFT: code comment has no matching DRIFT-LOG.md entry. Add the entry or remove the comment.',
|
|
65
67
|
autoFixable: false,
|
|
66
68
|
},
|
|
67
69
|
'Changelog': {
|
|
@@ -104,6 +106,78 @@ const FIX_INSTRUCTIONS = {
|
|
|
104
106
|
description: 'Documents haven\'t been reviewed since recent code changes. Re-run fix --doc for each stale doc.',
|
|
105
107
|
autoFixable: false,
|
|
106
108
|
},
|
|
109
|
+
// ── Routed (Phase F): these used to fall through to a generic "Manual review needed" ──
|
|
110
|
+
'Metrics-Consistency': {
|
|
111
|
+
action: 'Update stale number(s) in docs',
|
|
112
|
+
command: 'docguard fix --write',
|
|
113
|
+
llmCommand: 'docguard fix --write',
|
|
114
|
+
description: 'A doc claims a different count than the actual. Mechanical replace — no AI needed.',
|
|
115
|
+
autoFixable: true,
|
|
116
|
+
},
|
|
117
|
+
'Metadata-Sync': {
|
|
118
|
+
action: 'Update stale version reference(s)',
|
|
119
|
+
command: 'docguard fix --write',
|
|
120
|
+
llmCommand: 'docguard fix --write',
|
|
121
|
+
description: 'Docs reference an older version than the manifest. Mechanical replace — no AI needed.',
|
|
122
|
+
autoFixable: true,
|
|
123
|
+
},
|
|
124
|
+
'Docs-Sync': {
|
|
125
|
+
action: 'Reference the route/service in a canonical doc',
|
|
126
|
+
command: 'docguard fix --doc architecture',
|
|
127
|
+
llmCommand: '/docguard.fix --doc architecture',
|
|
128
|
+
description: 'A code file under routes/services is not referenced by any canonical doc. Add it (or its module) to ARCHITECTURE.md.',
|
|
129
|
+
autoFixable: false,
|
|
130
|
+
},
|
|
131
|
+
'Docs-Diff': {
|
|
132
|
+
action: 'Reconcile the documented vs. real surface',
|
|
133
|
+
command: 'docguard diff',
|
|
134
|
+
llmCommand: '/docguard.fix',
|
|
135
|
+
description: 'Tech stack or test files documented but not found in code (or vice versa). Inspect with `docguard diff`.',
|
|
136
|
+
autoFixable: false,
|
|
137
|
+
},
|
|
138
|
+
'Docs-Coverage': {
|
|
139
|
+
action: 'Reference the missing config/dotfile/source dir in docs',
|
|
140
|
+
command: 'docguard fix --doc architecture',
|
|
141
|
+
llmCommand: '/docguard.fix --doc architecture',
|
|
142
|
+
description: 'A project config/source dir is undocumented. Add a reference to the appropriate canonical doc.',
|
|
143
|
+
autoFixable: false,
|
|
144
|
+
},
|
|
145
|
+
'Doc-Quality': {
|
|
146
|
+
action: 'Improve readability / structure of the flagged doc',
|
|
147
|
+
command: 'docguard fix --doc',
|
|
148
|
+
llmCommand: '/docguard.fix --doc',
|
|
149
|
+
description: 'Passive voice, low atomicity, or weak structure detected. Re-run fix --doc for the affected file.',
|
|
150
|
+
autoFixable: false,
|
|
151
|
+
},
|
|
152
|
+
'TODO-Tracking': {
|
|
153
|
+
action: 'Track or remove the TODO/FIXME',
|
|
154
|
+
description: 'An untracked TODO/FIXME in source. Add it to ROADMAP.md / CURRENT-STATE.md, open an issue, or remove it.',
|
|
155
|
+
autoFixable: false,
|
|
156
|
+
},
|
|
157
|
+
'Traceability': {
|
|
158
|
+
action: 'Link the requirement ID to its test(s)',
|
|
159
|
+
description: 'A documented requirement ID has no matching reference in any test file. Add `@req FR-XXX` to the test that verifies it.',
|
|
160
|
+
autoFixable: false,
|
|
161
|
+
},
|
|
162
|
+
'Schema-Sync': {
|
|
163
|
+
action: 'Document the model in DATA-MODEL.md',
|
|
164
|
+
command: 'docguard fix --doc data-model',
|
|
165
|
+
llmCommand: '/docguard.fix --doc data-model',
|
|
166
|
+
description: 'A database model in code is not documented in DATA-MODEL.md. Add an Entity entry for it.',
|
|
167
|
+
autoFixable: false,
|
|
168
|
+
},
|
|
169
|
+
'Spec-Kit': {
|
|
170
|
+
action: 'Add the missing Spec Kit artifact / section',
|
|
171
|
+
description: 'A Spec Kit artifact (spec.md / plan.md / tasks.md) is missing a required section, FR-ID, or phased task structure. Edit the spec to match the standard.',
|
|
172
|
+
autoFixable: false,
|
|
173
|
+
},
|
|
174
|
+
'API-Surface': {
|
|
175
|
+
action: 'Reconcile API-REFERENCE.md with the real API surface',
|
|
176
|
+
command: 'docguard fix --write',
|
|
177
|
+
llmCommand: 'docguard fix --write',
|
|
178
|
+
description: 'Documented-but-absent endpoints can be deleted mechanically with `docguard fix --write`. Undocumented-in-code endpoints need an agent to write the request/response block (`/docguard.fix --doc api-reference`).',
|
|
179
|
+
autoFixable: true,
|
|
180
|
+
},
|
|
107
181
|
};
|
|
108
182
|
|
|
109
183
|
export function runDiagnose(projectDir, config, flags) {
|
|
@@ -119,29 +193,34 @@ export function runDiagnose(projectDir, config, flags) {
|
|
|
119
193
|
|
|
120
194
|
// ── Step 3: Auto-fix (only with --auto flag) or suggest fixes ──
|
|
121
195
|
const shouldAutoFix = flags.auto && flags.format !== 'json';
|
|
196
|
+
// Mechanical fixes = deterministic, no-LLM edits (e.g. remove a documented
|
|
197
|
+
// endpoint the spec confirms is gone). Surfaced by the API-Surface validator.
|
|
198
|
+
const mechanicalCount = countMechanicalFixes(guardData);
|
|
122
199
|
if (issues.length > 0) {
|
|
123
200
|
const autoFixable = issues.filter(i => i.autoFixable);
|
|
124
201
|
const hasStructural = issues.some(i => i.validator === 'Structure');
|
|
125
202
|
|
|
126
|
-
if (shouldAutoFix && (hasStructural || autoFixable.length > 0)) {
|
|
127
|
-
//
|
|
203
|
+
if (shouldAutoFix && (hasStructural || autoFixable.length > 0 || mechanicalCount > 0)) {
|
|
204
|
+
// 1. init — create missing files
|
|
128
205
|
try {
|
|
129
206
|
const cliPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'docguard.mjs');
|
|
130
|
-
|
|
131
|
-
encoding: 'utf-8',
|
|
132
|
-
stdio: 'pipe',
|
|
133
|
-
});
|
|
207
|
+
execFileSync(process.execPath, [cliPath, 'init', '--dir', projectDir], { encoding: 'utf-8', stdio: 'pipe' });
|
|
134
208
|
} catch { /* init may partially succeed */ }
|
|
135
209
|
|
|
136
|
-
//
|
|
210
|
+
// 2. generate — fill MISSING content only (never --force; won't overwrite existing docs)
|
|
137
211
|
try {
|
|
138
212
|
const cliPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'docguard.mjs');
|
|
139
|
-
|
|
140
|
-
encoding: 'utf-8',
|
|
141
|
-
stdio: 'pipe',
|
|
142
|
-
});
|
|
213
|
+
execFileSync(process.execPath, [cliPath, 'generate', '--dir', projectDir], { encoding: 'utf-8', stdio: 'pipe' });
|
|
143
214
|
} catch { /* generate may partially succeed */ }
|
|
144
215
|
|
|
216
|
+
// 3. mechanical fixes — apply ALL deterministic edits (no LLM):
|
|
217
|
+
// endpoint removal, stale counts, stale versions, changelog header.
|
|
218
|
+
let mechApplied = 0;
|
|
219
|
+
try {
|
|
220
|
+
const r = applyAllMechanicalFixes(projectDir, config, { force: flags.force });
|
|
221
|
+
mechApplied = r.applied.length;
|
|
222
|
+
} catch { /* best-effort */ }
|
|
223
|
+
|
|
145
224
|
// Re-run guard to see what's still broken
|
|
146
225
|
guardData = runGuardInternal(projectDir, config);
|
|
147
226
|
issues = collectIssues(guardData);
|
|
@@ -149,20 +228,30 @@ export function runDiagnose(projectDir, config, flags) {
|
|
|
149
228
|
if (!flags.format || flags.format === 'text') {
|
|
150
229
|
const fixedCount = autoFixable.length - issues.filter(i => i.autoFixable).length;
|
|
151
230
|
if (fixedCount > 0) {
|
|
152
|
-
console.log(` ${c.green}⚡ Auto-fixed ${fixedCount} issue(s)${c.reset} (created/regenerated docs)
|
|
231
|
+
console.log(` ${c.green}⚡ Auto-fixed ${fixedCount} issue(s)${c.reset} (created/regenerated docs)`);
|
|
232
|
+
}
|
|
233
|
+
if (mechApplied > 0) {
|
|
234
|
+
console.log(` ${c.green}⚡ Applied ${mechApplied} mechanical fix(es)${c.reset} (removed stale API endpoints)`);
|
|
153
235
|
}
|
|
236
|
+
if (fixedCount > 0 || mechApplied > 0) console.log('');
|
|
154
237
|
}
|
|
155
|
-
} else if (!shouldAutoFix && (
|
|
156
|
-
// Suggest-only mode
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (autoFixable.length > 0) console.log(` ${c.dim}/docguard.fix${c.reset}`);
|
|
161
|
-
} else {
|
|
162
|
-
if (hasStructural) console.log(` ${c.dim}docguard init --dir .${c.reset}`);
|
|
163
|
-
if (autoFixable.length > 0) console.log(` ${c.dim}docguard generate --dir . --force${c.reset}`);
|
|
238
|
+
} else if (!shouldAutoFix && (!flags.format || flags.format === 'text')) {
|
|
239
|
+
// Suggest-only mode — be accurate about what each path does.
|
|
240
|
+
if (mechanicalCount > 0) {
|
|
241
|
+
console.log(` ${c.green}🔧 ${mechanicalCount} issue(s) are mechanically fixable — no AI needed.${c.reset} Apply with:`);
|
|
242
|
+
console.log(` ${c.cyan}docguard fix --write${c.reset}${c.dim} (removes stale documented endpoints)${c.reset}`);
|
|
164
243
|
}
|
|
165
|
-
|
|
244
|
+
if (hasStructural || autoFixable.length > 0) {
|
|
245
|
+
console.log(` ${c.yellow}💡 ${autoFixable.length + (hasStructural ? 1 : 0)} issue(s) can be scaffolded/regenerated.${c.reset} Run ${c.cyan}docguard diagnose --auto${c.reset} (creates missing docs + applies mechanical fixes), or:`);
|
|
246
|
+
if (agentMode === 'llm') {
|
|
247
|
+
if (hasStructural) console.log(` ${c.dim}/docguard.init${c.reset}`);
|
|
248
|
+
if (autoFixable.length > 0) console.log(` ${c.dim}/docguard.fix${c.reset}`);
|
|
249
|
+
} else {
|
|
250
|
+
if (hasStructural) console.log(` ${c.dim}docguard init --dir .${c.reset}`);
|
|
251
|
+
if (autoFixable.length > 0) console.log(` ${c.dim}docguard generate --dir . --force${c.reset}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (mechanicalCount > 0 || hasStructural || autoFixable.length > 0) console.log('');
|
|
166
255
|
}
|
|
167
256
|
}
|
|
168
257
|
|
|
@@ -193,46 +282,65 @@ export function runDiagnose(projectDir, config, flags) {
|
|
|
193
282
|
}
|
|
194
283
|
}
|
|
195
284
|
|
|
285
|
+
/** Count deterministic (no-LLM) fixes available across guard results. */
|
|
286
|
+
function countMechanicalFixes(guardData) {
|
|
287
|
+
let n = 0;
|
|
288
|
+
for (const v of guardData.validators) {
|
|
289
|
+
if (Array.isArray(v.fixes)) n += v.fixes.length;
|
|
290
|
+
}
|
|
291
|
+
return n;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* A documented-but-absent endpoint is MECHANICALLY fixable (deterministic
|
|
296
|
+
* removal via `docguard fix --write`) — distinct from drift that needs an agent.
|
|
297
|
+
*/
|
|
298
|
+
function isMechanicalMessage(validator, message) {
|
|
299
|
+
return validator === 'API-Surface' && /not found in code/i.test(message);
|
|
300
|
+
}
|
|
301
|
+
|
|
196
302
|
/**
|
|
197
303
|
* Collect issues from guard results with fix metadata.
|
|
198
304
|
*/
|
|
199
305
|
function collectIssues(guardData) {
|
|
200
306
|
const issues = [];
|
|
201
307
|
for (const v of guardData.validators) {
|
|
202
|
-
if (v.status === 'skipped' || v.status === 'pass') continue;
|
|
308
|
+
if (v.status === 'skipped' || v.status === 'pass' || v.status === 'na') continue;
|
|
203
309
|
|
|
204
310
|
const fixInfo = FIX_INSTRUCTIONS[v.name] || { action: `Review ${v.name}`, description: 'Manual review needed.', autoFixable: false };
|
|
205
311
|
const docTarget = VALIDATOR_TO_DOC[v.name];
|
|
206
312
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
message: err,
|
|
212
|
-
action: fixInfo.action,
|
|
213
|
-
command: fixInfo.command || null,
|
|
214
|
-
llmCommand: fixInfo.llmCommand || null,
|
|
215
|
-
docTarget,
|
|
216
|
-
autoFixable: fixInfo.autoFixable || false,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
for (const warn of v.warnings) {
|
|
220
|
-
issues.push({
|
|
221
|
-
severity: 'warning',
|
|
313
|
+
const mkIssue = (severity, message) => {
|
|
314
|
+
const mechanical = isMechanicalMessage(v.name, message);
|
|
315
|
+
return {
|
|
316
|
+
severity,
|
|
222
317
|
validator: v.name,
|
|
223
|
-
message
|
|
224
|
-
action: fixInfo.action,
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
318
|
+
message,
|
|
319
|
+
action: mechanical ? 'Remove stale endpoint from API-REFERENCE.md' : fixInfo.action,
|
|
320
|
+
// Mechanical fixes point at the deterministic CLI applier, not an LLM.
|
|
321
|
+
command: mechanical ? 'docguard fix --write' : (fixInfo.command || null),
|
|
322
|
+
llmCommand: mechanical ? null : (fixInfo.llmCommand || null),
|
|
323
|
+
mechanical,
|
|
324
|
+
docTarget: mechanical ? null : docTarget,
|
|
228
325
|
autoFixable: fixInfo.autoFixable || false,
|
|
229
|
-
}
|
|
230
|
-
}
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
for (const err of v.errors) issues.push(mkIssue('error', err));
|
|
330
|
+
for (const warn of v.warnings) issues.push(mkIssue('warning', warn));
|
|
231
331
|
}
|
|
232
332
|
return issues;
|
|
233
333
|
}
|
|
234
334
|
|
|
235
335
|
function outputJSON(guardData, scoreData, issues) {
|
|
336
|
+
// Structured, deterministic fix actions an agent or `--write` can apply directly.
|
|
337
|
+
const mechanicalFixes = [];
|
|
338
|
+
for (const v of guardData.validators) {
|
|
339
|
+
if (Array.isArray(v.fixes)) {
|
|
340
|
+
for (const f of v.fixes) mechanicalFixes.push({ validator: v.name, ...f });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
236
344
|
const result = {
|
|
237
345
|
project: guardData.project,
|
|
238
346
|
profile: guardData.profile,
|
|
@@ -246,8 +354,13 @@ function outputJSON(guardData, scoreData, issues) {
|
|
|
246
354
|
message: i.message,
|
|
247
355
|
action: i.action,
|
|
248
356
|
command: i.command,
|
|
357
|
+
// 'mechanical' = deterministic CLI fix (docguard fix --write);
|
|
358
|
+
// 'agent' = needs an AI agent to write content.
|
|
359
|
+
fixKind: i.mechanical ? 'mechanical' : 'agent',
|
|
249
360
|
docTarget: i.docTarget,
|
|
250
361
|
})),
|
|
362
|
+
// Deterministic actions consumable by `docguard fix --write` or an agent.
|
|
363
|
+
mechanicalFixes,
|
|
251
364
|
// Unique fix commands for automation
|
|
252
365
|
fixCommands: [...new Set(issues.filter(i => i.command).map(i => i.command))],
|
|
253
366
|
timestamp: new Date().toISOString(),
|