docguard-cli 0.5.2 → 0.7.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 +22 -0
- package/README.md +13 -0
- package/cli/commands/diagnose.mjs +224 -33
- package/cli/commands/generate.mjs +501 -87
- package/cli/commands/guard.mjs +23 -6
- package/cli/commands/publish.mjs +246 -0
- package/cli/commands/score.mjs +31 -0
- package/cli/commands/trace.mjs +311 -0
- package/cli/docguard.mjs +31 -3
- package/cli/scanners/doc-tools.mjs +351 -0
- package/cli/scanners/routes.mjs +461 -0
- package/cli/scanners/schemas.mjs +567 -0
- package/package.json +1 -1
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync, mkdirSync } from 'node:fs';
|
|
9
|
-
import { resolve, join, extname, basename, relative } from 'node:path';
|
|
9
|
+
import { resolve, join, extname, basename, relative, dirname } from 'node:path';
|
|
10
10
|
import { c } from '../docguard.mjs';
|
|
11
|
+
import { detectDocTools } from '../scanners/doc-tools.mjs';
|
|
12
|
+
import { scanRoutesDeep } from '../scanners/routes.mjs';
|
|
13
|
+
import { scanSchemasDeep, generateERDiagram } from '../scanners/schemas.mjs';
|
|
11
14
|
|
|
12
15
|
const IGNORE_DIRS = new Set([
|
|
13
16
|
'node_modules', '.git', '.next', 'dist', 'build', 'coverage',
|
|
@@ -20,6 +23,70 @@ const CODE_EXTENSIONS = new Set([
|
|
|
20
23
|
'.py', '.java', '.go', '.rs', '.rb', '.php', '.cs',
|
|
21
24
|
]);
|
|
22
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Standards citation map — each doc type maps to its governing industry standard.
|
|
28
|
+
* Inspired by RAG-grounded standards alignment (Lopez et al., AITPG, IEEE TSE 2026).
|
|
29
|
+
*/
|
|
30
|
+
const STANDARDS_CITATIONS = {
|
|
31
|
+
'ARCHITECTURE.md': {
|
|
32
|
+
standard: 'arc42 Template + C4 Model',
|
|
33
|
+
reference: 'Starke, G. & Brown, S. "arc42 — Architecture communication template." https://arc42.org | Brown, S. "The C4 Model for visualising software architecture." https://c4model.com',
|
|
34
|
+
sections: '§1 Introduction, §2 Constraints, §3 Context, §4 Solution Strategy, §5 Building Blocks, §6 Runtime, §7 Deployment, §8 Crosscutting, §9 ADRs, §10 Quality, §11 Risks, §12 Glossary',
|
|
35
|
+
},
|
|
36
|
+
'DATA-MODEL.md': {
|
|
37
|
+
standard: 'C4 Component Diagram + Entity-Relationship (Chen notation)',
|
|
38
|
+
reference: 'Brown, S. "C4 Model — Component diagrams." https://c4model.com | Chen, P. "The Entity-Relationship Model." ACM TODS 1(1), 1976',
|
|
39
|
+
sections: 'Entities, Relationships, ER Diagrams (Mermaid), Field-level definitions',
|
|
40
|
+
},
|
|
41
|
+
'TEST-SPEC.md': {
|
|
42
|
+
standard: 'ISO/IEC/IEEE 29119-3:2022 — Test Documentation',
|
|
43
|
+
reference: 'ISO/IEC/IEEE, "Software and systems engineering — Software testing — Part 3: Test documentation." International Standard, 2022',
|
|
44
|
+
sections: 'Test Categories, Coverage Rules, Test Matrix, Tool Configuration',
|
|
45
|
+
},
|
|
46
|
+
'SECURITY.md': {
|
|
47
|
+
standard: 'OWASP ASVS v4.0 + CWE Top 25',
|
|
48
|
+
reference: 'OWASP Foundation, "Application Security Verification Standard v4.0." https://owasp.org/asvs | MITRE, "CWE Top 25." https://cwe.mitre.org/top25',
|
|
49
|
+
sections: 'Authentication, Secrets Management, Access Control, Input Validation',
|
|
50
|
+
},
|
|
51
|
+
'ENVIRONMENT.md': {
|
|
52
|
+
standard: '12-Factor App Methodology',
|
|
53
|
+
reference: 'Wiggins, A. "The Twelve-Factor App." https://12factor.net',
|
|
54
|
+
sections: 'Environment Variables, Config Separation, Setup Steps, Provider Configuration',
|
|
55
|
+
},
|
|
56
|
+
'API-REFERENCE.md': {
|
|
57
|
+
standard: 'OpenAPI Specification 3.1',
|
|
58
|
+
reference: 'OpenAPI Initiative, "OpenAPI Specification v3.1.0." https://spec.openapis.org/oas/v3.1.0',
|
|
59
|
+
sections: 'Endpoints, Request/Response schemas, Authentication, Error codes',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Append a standards citation footer to generated doc content.
|
|
65
|
+
* @param {string} content - The generated markdown content
|
|
66
|
+
* @param {string} docName - The filename (e.g., 'ARCHITECTURE.md')
|
|
67
|
+
* @returns {string} Content with citation footer appended
|
|
68
|
+
*/
|
|
69
|
+
function appendStandardsCitation(content, docName) {
|
|
70
|
+
const citation = STANDARDS_CITATIONS[docName];
|
|
71
|
+
if (!citation) return content;
|
|
72
|
+
|
|
73
|
+
const footer = `
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Standards Reference
|
|
77
|
+
|
|
78
|
+
> **Aligned with**: ${citation.standard}
|
|
79
|
+
>
|
|
80
|
+
> **Sections covered**: ${citation.sections}
|
|
81
|
+
>
|
|
82
|
+
> **Reference**: ${citation.reference}
|
|
83
|
+
>
|
|
84
|
+
> *Standards alignment inspired by RAG-grounded generation (Lopez et al., AITPG, IEEE TSE 2026).*
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
return content.trimEnd() + '\n' + footer;
|
|
88
|
+
}
|
|
89
|
+
|
|
23
90
|
export function runGenerate(projectDir, config, flags) {
|
|
24
91
|
console.log(`${c.bold}🔮 DocGuard Generate — ${config.projectName}${c.reset}`);
|
|
25
92
|
console.log(`${c.dim} Directory: ${projectDir}${c.reset}`);
|
|
@@ -33,10 +100,38 @@ export function runGenerate(projectDir, config, flags) {
|
|
|
33
100
|
}
|
|
34
101
|
console.log('');
|
|
35
102
|
|
|
36
|
-
// ── 2.
|
|
103
|
+
// ── 2. Detect Existing Doc Tools ──
|
|
104
|
+
const docTools = detectDocTools(projectDir);
|
|
105
|
+
if (docTools._detected.length > 0) {
|
|
106
|
+
console.log(` ${c.bold}Detected Documentation Tools:${c.reset}`);
|
|
107
|
+
for (const tool of docTools._detected) {
|
|
108
|
+
const info = docTools[tool];
|
|
109
|
+
const details = info.config || info.path || info.middleware || '';
|
|
110
|
+
let extra = '';
|
|
111
|
+
if (tool === 'openapi' && info.endpoints) extra = ` — ${info.endpoints.length} endpoints, ${info.schemas?.length || 0} schemas`;
|
|
112
|
+
if (tool === 'storybook' && info.storyCount) extra = ` — ${info.storyCount} stories`;
|
|
113
|
+
console.log(` ${c.cyan}${tool}:${c.reset} ${details}${extra}`);
|
|
114
|
+
}
|
|
115
|
+
console.log('');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── 3. Scan Project Structure ──
|
|
37
119
|
const scan = scanProject(projectDir);
|
|
38
120
|
|
|
39
|
-
// ──
|
|
121
|
+
// ── 4. Deep Scan Routes ──
|
|
122
|
+
const deepRoutes = scanRoutesDeep(projectDir, stack, docTools);
|
|
123
|
+
if (deepRoutes.length > 0) {
|
|
124
|
+
console.log(` ${c.bold}Route Scanning:${c.reset} ${deepRoutes.length} endpoints found (source: ${deepRoutes[0]?.source || 'code'})`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── 5. Deep Scan Schemas ──
|
|
128
|
+
const deepSchemas = scanSchemasDeep(projectDir, stack, docTools);
|
|
129
|
+
if (deepSchemas.entities.length > 0) {
|
|
130
|
+
console.log(` ${c.bold}Schema Scanning:${c.reset} ${deepSchemas.entities.length} entities, ${deepSchemas.relationships.length} relationships (source: ${deepSchemas.source})`);
|
|
131
|
+
}
|
|
132
|
+
console.log('');
|
|
133
|
+
|
|
134
|
+
// ── 6. Generate Documents ──
|
|
40
135
|
const docsDir = resolve(projectDir, 'docs-canonical');
|
|
41
136
|
if (!existsSync(docsDir)) {
|
|
42
137
|
mkdirSync(docsDir, { recursive: true });
|
|
@@ -45,12 +140,18 @@ export function runGenerate(projectDir, config, flags) {
|
|
|
45
140
|
let created = 0;
|
|
46
141
|
let skipped = 0;
|
|
47
142
|
|
|
48
|
-
// Generate ARCHITECTURE.md
|
|
49
|
-
const archResult = generateArchitecture(projectDir, config, stack, scan, flags);
|
|
143
|
+
// Generate ARCHITECTURE.md (arc42-aligned)
|
|
144
|
+
const archResult = generateArchitecture(projectDir, config, stack, scan, flags, docTools);
|
|
50
145
|
if (archResult) { created++; } else { skipped++; }
|
|
51
146
|
|
|
52
|
-
// Generate
|
|
53
|
-
|
|
147
|
+
// Generate API-REFERENCE.md (NEW — from deep route scanning)
|
|
148
|
+
if (deepRoutes.length > 0) {
|
|
149
|
+
const apiResult = generateApiReference(projectDir, config, stack, deepRoutes, flags);
|
|
150
|
+
if (apiResult) { created++; } else { skipped++; }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Generate DATA-MODEL.md (enhanced with deep schema scanning)
|
|
154
|
+
const dataResult = generateDataModel(projectDir, config, stack, scan, flags, deepSchemas);
|
|
54
155
|
if (dataResult) { created++; } else { skipped++; }
|
|
55
156
|
|
|
56
157
|
// Generate ENVIRONMENT.md
|
|
@@ -65,13 +166,16 @@ export function runGenerate(projectDir, config, flags) {
|
|
|
65
166
|
const secResult = generateSecurity(projectDir, config, stack, scan, flags);
|
|
66
167
|
if (secResult) { created++; } else { skipped++; }
|
|
67
168
|
|
|
68
|
-
// Generate root files
|
|
69
|
-
const rootResults = generateRootFiles(projectDir, config, stack, scan, flags);
|
|
169
|
+
// Generate root files (AGENTS.md, CHANGELOG, DRIFT-LOG)
|
|
170
|
+
const rootResults = generateRootFiles(projectDir, config, stack, scan, flags, docTools);
|
|
70
171
|
created += rootResults.created;
|
|
71
172
|
skipped += rootResults.skipped;
|
|
72
173
|
|
|
73
174
|
console.log(`\n${c.bold} ─────────────────────────────────────${c.reset}`);
|
|
74
175
|
console.log(` ${c.green}Generated: ${created}${c.reset} Skipped: ${skipped} (already exist)`);
|
|
176
|
+
if (docTools._detected.length > 0) {
|
|
177
|
+
console.log(` ${c.dim}Leveraged: ${docTools._detected.join(', ')} (existing tools detected)${c.reset}`);
|
|
178
|
+
}
|
|
75
179
|
console.log(`\n ${c.yellow}${c.bold}⚠️ Review all generated docs!${c.reset}`);
|
|
76
180
|
console.log(` ${c.dim}Generated docs are a starting point — review and refine them.${c.reset}`);
|
|
77
181
|
console.log(` ${c.dim}Run ${c.cyan}docguard score${c.dim} to check your CDD maturity.${c.reset}\n`);
|
|
@@ -278,7 +382,7 @@ function countFilesAndLines(dir, scan) {
|
|
|
278
382
|
|
|
279
383
|
// ── Document Generators ────────────────────────────────────────────────────
|
|
280
384
|
|
|
281
|
-
function generateArchitecture(dir, config, stack, scan, flags) {
|
|
385
|
+
function generateArchitecture(dir, config, stack, scan, flags, docTools) {
|
|
282
386
|
const path = resolve(dir, 'docs-canonical/ARCHITECTURE.md');
|
|
283
387
|
if (existsSync(path) && !flags.force) {
|
|
284
388
|
console.log(` ${c.dim}⏭️ ARCHITECTURE.md (exists)${c.reset}`);
|
|
@@ -297,14 +401,30 @@ function generateArchitecture(dir, config, stack, scan, flags) {
|
|
|
297
401
|
if (scan.components.length > 0) componentRows.push(`| UI Components | Frontend components | ${scan.components.length} files | |`);
|
|
298
402
|
if (scan.middlewares.length > 0) componentRows.push(`| Middleware | Request processing | ${scan.middlewares.join(', ')} | |`);
|
|
299
403
|
|
|
404
|
+
// Storybook integration
|
|
405
|
+
if (docTools?.storybook?.found) {
|
|
406
|
+
componentRows.push(`| Storybook | UI component docs | .storybook/ (${docTools.storybook.storyCount || '?'} stories) | |`);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Doc tools section
|
|
410
|
+
const docToolRows = [];
|
|
411
|
+
if (docTools?._detected?.length > 0) {
|
|
412
|
+
for (const tool of docTools._detected) {
|
|
413
|
+
const info = docTools[tool];
|
|
414
|
+
docToolRows.push(`| ${tool} | ${info.config || info.path || info.middleware || 'detected'} | Active |`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
300
418
|
const content = `# Architecture
|
|
301
419
|
|
|
302
420
|
<!-- docguard:version 0.1.0 -->
|
|
303
421
|
<!-- docguard:status draft -->
|
|
304
422
|
<!-- docguard:last-reviewed ${new Date().toISOString().split('T')[0]} -->
|
|
305
423
|
<!-- docguard:generated true -->
|
|
424
|
+
<!-- docguard:standards arc42, C4 -->
|
|
306
425
|
|
|
307
426
|
> **Auto-generated by DocGuard.** Review and refine this document.
|
|
427
|
+
> Follows [arc42](https://arc42.org) structure and [C4 Model](https://c4model.com) diagrams.
|
|
308
428
|
|
|
309
429
|
| Metadata | Value |
|
|
310
430
|
|----------|-------|
|
|
@@ -315,26 +435,105 @@ function generateArchitecture(dir, config, stack, scan, flags) {
|
|
|
315
435
|
|
|
316
436
|
---
|
|
317
437
|
|
|
318
|
-
##
|
|
438
|
+
## 1. Introduction & Goals
|
|
439
|
+
<!-- arc42: §1 — Introduction and Goals -->
|
|
319
440
|
|
|
320
|
-
<!-- TODO: Describe what this system does
|
|
441
|
+
<!-- TODO: Describe what this system does, who it's for, and key quality goals -->
|
|
321
442
|
${config.projectName} is a ${stack.framework || stack.language || 'software'} application.
|
|
322
443
|
|
|
323
|
-
|
|
444
|
+
### Quality Goals
|
|
445
|
+
|
|
446
|
+
| Priority | Quality Goal | Scenario |
|
|
447
|
+
|----------|-------------|----------|
|
|
448
|
+
| 1 | <!-- e.g. Performance --> | <!-- e.g. Response time < 200ms --> |
|
|
449
|
+
| 2 | <!-- e.g. Security --> | <!-- e.g. All endpoints authenticated --> |
|
|
450
|
+
| 3 | <!-- e.g. Maintainability --> | <!-- e.g. New feature in < 1 day --> |
|
|
451
|
+
|
|
452
|
+
## 2. Constraints
|
|
453
|
+
<!-- arc42: §2 — Constraints -->
|
|
454
|
+
|
|
455
|
+
| Type | Constraint | Background |
|
|
456
|
+
|------|-----------|------------|
|
|
457
|
+
| Technical | ${stack.language || 'TBD'} | Primary language |
|
|
458
|
+
| Technical | ${stack.framework || 'TBD'} | Framework |
|
|
459
|
+
| Infrastructure | ${stack.hosting || 'TBD'} | Hosting provider |
|
|
460
|
+
|
|
461
|
+
## 3. Context & Scope
|
|
462
|
+
<!-- arc42: §3 — Context and Scope (C4 Level 1: System Context) -->
|
|
463
|
+
|
|
464
|
+
\\\`\\\`\\\`mermaid
|
|
465
|
+
graph TD
|
|
466
|
+
U[Users/Clients] --> S[${config.projectName}]
|
|
467
|
+
S --> DB[(${stack.database || 'Database'})]
|
|
468
|
+
S --> EXT[External Services]
|
|
469
|
+
\\\`\\\`\\\`
|
|
470
|
+
|
|
471
|
+
## 4. Solution Strategy
|
|
472
|
+
<!-- arc42: §4 — Solution Strategy -->
|
|
473
|
+
|
|
474
|
+
See \\\`docs-canonical/ADR.md\\\` for architecture decision records.
|
|
475
|
+
|
|
476
|
+
## 5. Building Block View
|
|
477
|
+
<!-- arc42: §5 — Building Block View (C4 Level 2: Container) -->
|
|
324
478
|
|
|
325
479
|
| Component | Responsibility | Location | Tests |
|
|
326
480
|
|-----------|---------------|----------|-------|
|
|
327
|
-
${componentRows.join('
|
|
481
|
+
${componentRows.join('\\n') || '| <!-- Add components --> | | | |'}
|
|
328
482
|
|
|
329
|
-
|
|
483
|
+
\\\`\\\`\\\`mermaid
|
|
484
|
+
graph TD
|
|
485
|
+
A[Client] --> B[${stack.framework || 'API'}]
|
|
486
|
+
B --> C[Services]
|
|
487
|
+
C --> D[${stack.database || 'Database'}]
|
|
488
|
+
${scan.middlewares.length > 0 ? 'A --> M[Middleware] --> B' : ''}
|
|
489
|
+
${scan.components.length > 0 ? 'A --> UI[UI Components]' : ''}
|
|
490
|
+
\\\`\\\`\\\`
|
|
491
|
+
|
|
492
|
+
## 6. Runtime View
|
|
493
|
+
<!-- arc42: §6 — Runtime View -->
|
|
494
|
+
|
|
495
|
+
\\\`\\\`\\\`mermaid
|
|
496
|
+
sequenceDiagram
|
|
497
|
+
participant C as Client
|
|
498
|
+
participant A as ${stack.framework || 'API'}
|
|
499
|
+
participant S as Service
|
|
500
|
+
participant D as ${stack.database || 'DB'}
|
|
501
|
+
C->>A: Request
|
|
502
|
+
A->>S: Process
|
|
503
|
+
S->>D: Query
|
|
504
|
+
D-->>S: Result
|
|
505
|
+
S-->>A: Response
|
|
506
|
+
A-->>C: JSON
|
|
507
|
+
\\\`\\\`\\\`
|
|
508
|
+
|
|
509
|
+
## 7. Deployment View
|
|
510
|
+
<!-- arc42: §7 — Deployment View -->
|
|
511
|
+
|
|
512
|
+
See \\\`docs-canonical/DEPLOYMENT.md\\\` for details.
|
|
513
|
+
|
|
514
|
+
| Environment | Infrastructure | URL |
|
|
515
|
+
|-------------|---------------|-----|
|
|
516
|
+
| Development | localhost | http://localhost:3000 |
|
|
517
|
+
| Staging | ${stack.hosting || 'TBD'} | <!-- TODO --> |
|
|
518
|
+
| Production | ${stack.hosting || 'TBD'} | <!-- TODO --> |
|
|
519
|
+
|
|
520
|
+
## 8. Crosscutting Concepts
|
|
521
|
+
<!-- arc42: §8 — Crosscutting Concepts -->
|
|
522
|
+
|
|
523
|
+
### Tech Stack
|
|
330
524
|
|
|
331
525
|
| Category | Technology | Version | License |
|
|
332
526
|
|----------|-----------|---------|---------|
|
|
333
527
|
${techRows || '| <!-- Add technologies --> | | | |'}
|
|
528
|
+
${docToolRows.length > 0 ? `
|
|
529
|
+
### Documentation Tools
|
|
334
530
|
|
|
335
|
-
|
|
531
|
+
| Tool | Config | Status |
|
|
532
|
+
|------|--------|--------|
|
|
533
|
+
${docToolRows.join('\\n')}
|
|
534
|
+
` : ''}
|
|
336
535
|
|
|
337
|
-
|
|
536
|
+
### Layer Boundaries
|
|
338
537
|
|
|
339
538
|
| Layer | Can Import From | Cannot Import From |
|
|
340
539
|
|-------|----------------|-------------------|
|
|
@@ -342,14 +541,127 @@ ${scan.routes.length > 0 ? '| Routes/Handlers | Services, Middleware | Models (d
|
|
|
342
541
|
${scan.services.length > 0 ? '| Services | Repositories, Utils | Routes |' : ''}
|
|
343
542
|
${scan.models.length > 0 ? '| Models/Repositories | Utils | Services, Routes |' : ''}
|
|
344
543
|
|
|
345
|
-
##
|
|
544
|
+
## 9. Architecture Decisions
|
|
545
|
+
<!-- arc42: §9 — Architecture Decisions -->
|
|
346
546
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
547
|
+
See \\\`docs-canonical/ADR.md\\\` for the full decision log.
|
|
548
|
+
|
|
549
|
+
## 10. Quality Requirements
|
|
550
|
+
<!-- arc42: §10 — Quality Requirements -->
|
|
551
|
+
|
|
552
|
+
See \\\`docs-canonical/TEST-SPEC.md\\\` for test requirements and coverage targets.
|
|
553
|
+
|
|
554
|
+
## 11. Risks & Technical Debt
|
|
555
|
+
<!-- arc42: §11 — Risk Assessment and Technical Debt -->
|
|
556
|
+
|
|
557
|
+
See \\\`DRIFT-LOG.md\\\` for documented deviations from canonical specs.
|
|
558
|
+
See \\\`docs-canonical/KNOWN-GOTCHAS.md\\\` for known issues.
|
|
559
|
+
|
|
560
|
+
## 12. Glossary
|
|
561
|
+
<!-- arc42: §12 — Glossary -->
|
|
562
|
+
|
|
563
|
+
| Term | Definition |
|
|
564
|
+
|------|-----------|
|
|
565
|
+
| CDD | Canonical-Driven Development — documentation as the source of truth |
|
|
566
|
+
| Canonical Doc | A specification document that defines system behavior |
|
|
567
|
+
| Drift | Conscious deviation from canonical documentation |
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## Revision History
|
|
572
|
+
|
|
573
|
+
| Version | Date | Author | Changes |
|
|
574
|
+
|---------|------|--------|---------|
|
|
575
|
+
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated (arc42 + C4 aligned) |
|
|
576
|
+
`;
|
|
577
|
+
|
|
578
|
+
writeFileSync(path, appendStandardsCitation(content, 'ARCHITECTURE.md'), 'utf-8');
|
|
579
|
+
console.log(` ${c.green}✅ ARCHITECTURE.md${c.reset} (arc42 §1-§12, ${componentRows.length} components, ${Object.values(stack).filter(Boolean).length} tech)`);
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// ── API Reference Generator (NEW — from deep route scanning) ───────────────
|
|
584
|
+
|
|
585
|
+
function generateApiReference(dir, config, stack, deepRoutes, flags) {
|
|
586
|
+
const path = resolve(dir, 'docs-canonical/API-REFERENCE.md');
|
|
587
|
+
if (existsSync(path) && !flags.force) {
|
|
588
|
+
console.log(` ${c.dim}⏭️ API-REFERENCE.md (exists)${c.reset}`);
|
|
589
|
+
return false;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Group routes by resource (first path segment after /api/)
|
|
593
|
+
const groups = {};
|
|
594
|
+
for (const route of deepRoutes) {
|
|
595
|
+
const parts = route.path.split('/').filter(Boolean);
|
|
596
|
+
const resource = parts[1] || parts[0] || 'root';
|
|
597
|
+
if (!groups[resource]) groups[resource] = [];
|
|
598
|
+
groups[resource].push(route);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Build endpoint table
|
|
602
|
+
const endpointRows = deepRoutes
|
|
603
|
+
.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method))
|
|
604
|
+
.map(r => `| \`${r.method}\` | \`${r.path}\` | ${r.handler || '—'} | ${r.auth ? '🔒' : '🔓'} | ${r.description || '—'} |`)
|
|
605
|
+
.join('\n');
|
|
606
|
+
|
|
607
|
+
// Build per-resource sections
|
|
608
|
+
const resourceSections = Object.entries(groups)
|
|
609
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
610
|
+
.map(([resource, routes]) => {
|
|
611
|
+
const routeDetails = routes.map(r => `#### ${r.method} \`${r.path}\`
|
|
612
|
+
|
|
613
|
+
> Source: \`${r.file}\`${r.source ? ` (${r.source})` : ''}
|
|
614
|
+
|
|
615
|
+
- **Auth:** ${r.auth ? 'Required' : 'None'}
|
|
616
|
+
- **Handler:** ${r.handler || '—'}
|
|
617
|
+
${r.description ? `- **Description:** ${r.description}` : ''}
|
|
618
|
+
|
|
619
|
+
| Parameter | In | Type | Required | Description |
|
|
620
|
+
|-----------|-----|------|:--------:|-------------|
|
|
621
|
+
| <!-- TODO --> | | | | |
|
|
622
|
+
|
|
623
|
+
| Status | Response |
|
|
624
|
+
|--------|----------|
|
|
625
|
+
| 200 | Success |
|
|
626
|
+
| 400 | Bad Request |
|
|
627
|
+
| 401 | Unauthorized |
|
|
628
|
+
`).join('\n');
|
|
629
|
+
|
|
630
|
+
return `### ${resource.charAt(0).toUpperCase() + resource.slice(1)}
|
|
631
|
+
|
|
632
|
+
${routeDetails}`;
|
|
633
|
+
}).join('\n---\n\n');
|
|
634
|
+
|
|
635
|
+
const content = `# API Reference
|
|
636
|
+
|
|
637
|
+
<!-- docguard:version 0.1.0 -->
|
|
638
|
+
<!-- docguard:status draft -->
|
|
639
|
+
<!-- docguard:last-reviewed ${new Date().toISOString().split('T')[0]} -->
|
|
640
|
+
<!-- docguard:generated true -->
|
|
641
|
+
|
|
642
|
+
> **Auto-generated by DocGuard.** Review and refine this document.
|
|
643
|
+
|
|
644
|
+
| Metadata | Value |
|
|
645
|
+
|----------|-------|
|
|
646
|
+
| **Status** |  |
|
|
647
|
+
| **Base URL** | \`http://localhost:3000\` |
|
|
648
|
+
| **Auth** | <!-- TODO: Describe auth mechanism --> |
|
|
649
|
+
| **Total Endpoints** | ${deepRoutes.length} |
|
|
650
|
+
| **Source** | ${deepRoutes[0]?.source || 'code scan'} |
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## Endpoints Summary
|
|
655
|
+
|
|
656
|
+
| Method | Path | Handler | Auth | Description |
|
|
657
|
+
|--------|------|---------|:----:|-------------|
|
|
658
|
+
${endpointRows}
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## Endpoint Details
|
|
663
|
+
|
|
664
|
+
${resourceSections}
|
|
353
665
|
|
|
354
666
|
---
|
|
355
667
|
|
|
@@ -357,49 +669,101 @@ graph TD
|
|
|
357
669
|
|
|
358
670
|
| Version | Date | Author | Changes |
|
|
359
671
|
|---------|------|--------|---------|
|
|
360
|
-
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated from
|
|
672
|
+
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated (${deepRoutes.length} endpoints from ${deepRoutes[0]?.source || 'code'}) |
|
|
361
673
|
`;
|
|
362
674
|
|
|
363
|
-
writeFileSync(path, content, 'utf-8');
|
|
364
|
-
console.log(` ${c.green}✅
|
|
675
|
+
writeFileSync(path, appendStandardsCitation(content, 'API-REFERENCE.md'), 'utf-8');
|
|
676
|
+
console.log(` ${c.green}✅ API-REFERENCE.md${c.reset} (${deepRoutes.length} endpoints, ${Object.keys(groups).length} resources)`);
|
|
365
677
|
return true;
|
|
366
678
|
}
|
|
367
679
|
|
|
368
|
-
|
|
680
|
+
// ── Enhanced Data Model Generator ──────────────────────────────────────────
|
|
681
|
+
|
|
682
|
+
function generateDataModel(dir, config, stack, scan, flags, deepSchemas) {
|
|
369
683
|
const path = resolve(dir, 'docs-canonical/DATA-MODEL.md');
|
|
370
684
|
if (existsSync(path) && !flags.force) {
|
|
371
685
|
console.log(` ${c.dim}⏭️ DATA-MODEL.md (exists)${c.reset}`);
|
|
372
686
|
return false;
|
|
373
687
|
}
|
|
374
688
|
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (name !== 'index' && name !== 'schema') {
|
|
380
|
-
entities.push({
|
|
381
|
-
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
382
|
-
file: modelFile,
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
}
|
|
689
|
+
// Use deep schemas if available, fallback to basic scan
|
|
690
|
+
let entities = [];
|
|
691
|
+
let relationships = [];
|
|
692
|
+
let schemaSource = 'file scan';
|
|
386
693
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
694
|
+
if (deepSchemas && deepSchemas.entities.length > 0) {
|
|
695
|
+
entities = deepSchemas.entities;
|
|
696
|
+
relationships = deepSchemas.relationships;
|
|
697
|
+
schemaSource = deepSchemas.source;
|
|
698
|
+
} else {
|
|
699
|
+
// Fallback: basic entity detection from file names
|
|
700
|
+
for (const modelFile of scan.models) {
|
|
701
|
+
const name = basename(modelFile, extname(modelFile));
|
|
702
|
+
if (name !== 'index' && name !== 'schema') {
|
|
703
|
+
entities.push({
|
|
704
|
+
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
705
|
+
fields: [],
|
|
706
|
+
file: modelFile,
|
|
707
|
+
source: 'file',
|
|
708
|
+
});
|
|
396
709
|
}
|
|
397
710
|
}
|
|
398
711
|
}
|
|
399
712
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
713
|
+
// Build entity summary table
|
|
714
|
+
const entityRows = entities
|
|
715
|
+
.filter(e => e.source !== 'prisma-enum')
|
|
716
|
+
.map(e => {
|
|
717
|
+
const pk = e.fields?.find(f => f.primaryKey);
|
|
718
|
+
return `| ${e.name} | ${stack.database || 'TBD'} | ${pk ? pk.name : e.name.toLowerCase() + 'Id'} | ${e.file || '—'} | ${e.fields?.length || 0} fields |`;
|
|
719
|
+
}).join('\n');
|
|
720
|
+
|
|
721
|
+
// Build detailed entity sections
|
|
722
|
+
const entitySections = entities
|
|
723
|
+
.filter(e => e.source !== 'prisma-enum')
|
|
724
|
+
.map(e => {
|
|
725
|
+
if (!e.fields || e.fields.length === 0) {
|
|
726
|
+
return `### ${e.name}
|
|
727
|
+
|
|
728
|
+
> Source: \`${e.file || 'unknown'}\`
|
|
729
|
+
|
|
730
|
+
| Field | Type | Required | Default | Constraints | Description |
|
|
731
|
+
|-------|------|----------|---------|-------------|-------------|
|
|
732
|
+
| <!-- TODO: Fill in fields --> | | | | | |
|
|
733
|
+
`;
|
|
734
|
+
}
|
|
735
|
+
const fieldRows = e.fields.map(f =>
|
|
736
|
+
`| ${f.name} | ${f.type} | ${f.required ? '✓' : '✗'} | ${f.default || '—'} | ${f.primaryKey ? 'PK' : ''}${f.unique ? ' UK' : ''} | ${f.description || ''} |`
|
|
737
|
+
).join('\n');
|
|
738
|
+
|
|
739
|
+
return `### ${e.name}
|
|
740
|
+
|
|
741
|
+
> Source: \`${e.file || 'unknown'}\` (${e.source || 'detected'})
|
|
742
|
+
|
|
743
|
+
| Field | Type | Required | Default | Constraints | Description |
|
|
744
|
+
|-------|------|:--------:|---------|-------------|-------------|
|
|
745
|
+
${fieldRows}
|
|
746
|
+
`;
|
|
747
|
+
}).join('\n');
|
|
748
|
+
|
|
749
|
+
// Build enum sections (if Prisma enums found)
|
|
750
|
+
const enums = entities.filter(e => e.source === 'prisma-enum');
|
|
751
|
+
const enumSection = enums.length > 0 ? `## Enums
|
|
752
|
+
|
|
753
|
+
${enums.map(e => `### ${e.name}
|
|
754
|
+
|
|
755
|
+
| Value |
|
|
756
|
+
|-------|
|
|
757
|
+
${e.fields.map(f => `| ${f.name} |`).join('\n')}
|
|
758
|
+
`).join('\n')}` : '';
|
|
759
|
+
|
|
760
|
+
// Build relationship table
|
|
761
|
+
const relRows = relationships.length > 0
|
|
762
|
+
? relationships.map(r => `| ${r.from} | ${r.to} | ${r.type} | ${r.field} | — |`).join('\n')
|
|
763
|
+
: '| <!-- No relationships detected --> | | | | |';
|
|
764
|
+
|
|
765
|
+
// Generate mermaid ER diagram
|
|
766
|
+
const erDiagram = generateERDiagram(entities, relationships);
|
|
403
767
|
|
|
404
768
|
const content = `# Data Model
|
|
405
769
|
|
|
@@ -416,35 +780,43 @@ function generateDataModel(dir, config, stack, scan, flags) {
|
|
|
416
780
|
| **Version** | \`0.1.0\` |
|
|
417
781
|
| **Database** | ${stack.database || 'TBD'} |
|
|
418
782
|
| **ORM** | ${stack.orm || 'None detected'} |
|
|
783
|
+
| **Schema Source** | ${schemaSource} |
|
|
784
|
+
| **Entities** | ${entities.filter(e => e.source !== 'prisma-enum').length} |
|
|
785
|
+
| **Relationships** | ${relationships.length} |
|
|
419
786
|
|
|
420
787
|
---
|
|
421
788
|
|
|
422
|
-
##
|
|
789
|
+
## Entity Summary
|
|
423
790
|
|
|
424
|
-
| Entity | Storage | Primary Key |
|
|
425
|
-
|
|
426
|
-
${entityRows || '| <!-- No models detected --> | | | |'}
|
|
791
|
+
| Entity | Storage | Primary Key | Source | Fields |
|
|
792
|
+
|--------|---------|-------------|--------|--------|
|
|
793
|
+
${entityRows || '| <!-- No models detected --> | | | | |'}
|
|
427
794
|
|
|
428
|
-
|
|
795
|
+
---
|
|
429
796
|
|
|
430
|
-
|
|
797
|
+
## Entity Details
|
|
431
798
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
| <!-- TODO: Fill in fields --> | | | | | |
|
|
435
|
-
`).join('\n')}
|
|
799
|
+
${entitySections}
|
|
800
|
+
${enumSection}
|
|
436
801
|
|
|
437
802
|
## Relationships
|
|
438
803
|
|
|
439
804
|
| From | To | Type | FK/Reference | Cascade |
|
|
440
805
|
|------|-----|------|-------------|---------|
|
|
441
|
-
|
|
806
|
+
${relRows}
|
|
807
|
+
${erDiagram ? `
|
|
808
|
+
## Entity-Relationship Diagram
|
|
809
|
+
|
|
810
|
+
\`\`\`mermaid
|
|
811
|
+
${erDiagram}
|
|
812
|
+
\`\`\`
|
|
813
|
+
` : ''}
|
|
442
814
|
|
|
443
815
|
## Indexes
|
|
444
816
|
|
|
445
817
|
| Table | Index Name | Fields | Type | Purpose |
|
|
446
818
|
|-------|-----------|--------|------|---------|
|
|
447
|
-
| <!-- TODO --> | | | | |
|
|
819
|
+
| <!-- TODO: Document indexes --> | | | | |
|
|
448
820
|
|
|
449
821
|
---
|
|
450
822
|
|
|
@@ -452,11 +824,11 @@ ${entities.map(e => `### ${e.name}
|
|
|
452
824
|
|
|
453
825
|
| Version | Date | Author | Changes |
|
|
454
826
|
|---------|------|--------|---------|
|
|
455
|
-
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated (${entities.length} entities
|
|
827
|
+
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated (${entities.length} entities, ${relationships.length} relationships from ${schemaSource}) |
|
|
456
828
|
`;
|
|
457
829
|
|
|
458
|
-
writeFileSync(path, content, 'utf-8');
|
|
459
|
-
console.log(` ${c.green}✅ DATA-MODEL.md${c.reset} (${entities.length} entities
|
|
830
|
+
writeFileSync(path, appendStandardsCitation(content, 'DATA-MODEL.md'), 'utf-8');
|
|
831
|
+
console.log(` ${c.green}✅ DATA-MODEL.md${c.reset} (${entities.length} entities, ${relationships.length} relationships from ${schemaSource})`);
|
|
460
832
|
return true;
|
|
461
833
|
}
|
|
462
834
|
|
|
@@ -518,7 +890,7 @@ ${envVarRows || '| <!-- No .env.example found --> | | | | |'}
|
|
|
518
890
|
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated (${scan.envVars.length} env vars found) |
|
|
519
891
|
`;
|
|
520
892
|
|
|
521
|
-
writeFileSync(path, content, 'utf-8');
|
|
893
|
+
writeFileSync(path, appendStandardsCitation(content, 'ENVIRONMENT.md'), 'utf-8');
|
|
522
894
|
console.log(` ${c.green}✅ ENVIRONMENT.md${c.reset} (${scan.envVars.length} env vars detected)`);
|
|
523
895
|
return true;
|
|
524
896
|
}
|
|
@@ -603,7 +975,7 @@ ${serviceRows || '| <!-- No services found --> | | | |'}
|
|
|
603
975
|
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated (${scan.tests.length} test files, ${serviceMap.filter(s => s.status === '✅').length}/${serviceMap.length} mapped) |
|
|
604
976
|
`;
|
|
605
977
|
|
|
606
|
-
writeFileSync(path, content, 'utf-8');
|
|
978
|
+
writeFileSync(path, appendStandardsCitation(content, 'TEST-SPEC.md'), 'utf-8');
|
|
607
979
|
console.log(` ${c.green}✅ TEST-SPEC.md${c.reset} (${scan.tests.length} tests, ${serviceMap.filter(s => s.status === '✅').length}/${serviceMap.length} services mapped)`);
|
|
608
980
|
return true;
|
|
609
981
|
}
|
|
@@ -669,20 +1041,23 @@ ${scan.envVars.filter(v => isSecretVar(v.name)).map(v =>
|
|
|
669
1041
|
| 0.1.0 | ${new Date().toISOString().split('T')[0]} | DocGuard Generate | Auto-generated |
|
|
670
1042
|
`;
|
|
671
1043
|
|
|
672
|
-
writeFileSync(path, content, 'utf-8');
|
|
1044
|
+
writeFileSync(path, appendStandardsCitation(content, 'SECURITY.md'), 'utf-8');
|
|
673
1045
|
console.log(` ${c.green}✅ SECURITY.md${c.reset} (auth: ${stack.auth || 'not detected'})`);
|
|
674
1046
|
return true;
|
|
675
1047
|
}
|
|
676
1048
|
|
|
677
|
-
function generateRootFiles(dir, config, stack, scan, flags) {
|
|
1049
|
+
function generateRootFiles(dir, config, stack, scan, flags, docTools) {
|
|
678
1050
|
let created = 0;
|
|
679
1051
|
let skipped = 0;
|
|
680
1052
|
|
|
681
|
-
// AGENTS.md
|
|
1053
|
+
// AGENTS.md (AGENTS.md Standard compliant)
|
|
682
1054
|
const agentsPath = resolve(dir, 'AGENTS.md');
|
|
683
1055
|
if (!existsSync(agentsPath) || flags.force) {
|
|
684
1056
|
const content = `# AI Agent Instructions — ${config.projectName}
|
|
685
1057
|
|
|
1058
|
+
<!-- Standard: https://agents.md -->
|
|
1059
|
+
<!-- Generated by DocGuard — AGENTS.md standard compliant -->
|
|
1060
|
+
|
|
686
1061
|
> This project follows **Canonical-Driven Development (CDD)**.
|
|
687
1062
|
> Documentation is the source of truth. Read before coding.
|
|
688
1063
|
|
|
@@ -690,10 +1065,11 @@ function generateRootFiles(dir, config, stack, scan, flags) {
|
|
|
690
1065
|
|
|
691
1066
|
1. **Read** \`docs-canonical/\` before suggesting changes
|
|
692
1067
|
2. **Check** existing patterns in the codebase
|
|
693
|
-
3. **
|
|
694
|
-
4. **
|
|
695
|
-
5. **
|
|
696
|
-
6. **
|
|
1068
|
+
3. **Run** \`npx docguard-cli diagnose\` to see what needs fixing
|
|
1069
|
+
4. **Confirm** your approach before writing code
|
|
1070
|
+
5. **Implement** matching existing code style
|
|
1071
|
+
6. **Log** any deviations in \`DRIFT-LOG.md\` with \`// DRIFT: reason\`
|
|
1072
|
+
7. **Verify** with \`npx docguard-cli guard\` — all checks must pass
|
|
697
1073
|
|
|
698
1074
|
## Project Stack
|
|
699
1075
|
|
|
@@ -703,30 +1079,68 @@ ${Object.entries(stack).filter(([, v]) => v).map(([k, v]) => `- **${k}**: ${v}`)
|
|
|
703
1079
|
|
|
704
1080
|
| File | Purpose |
|
|
705
1081
|
|------|---------|
|
|
706
|
-
| \`docs-canonical/ARCHITECTURE.md\` | System design |
|
|
707
|
-
| \`docs-canonical/
|
|
1082
|
+
| \`docs-canonical/ARCHITECTURE.md\` | System design (arc42 aligned) |
|
|
1083
|
+
| \`docs-canonical/API-REFERENCE.md\` | API endpoint documentation |
|
|
1084
|
+
| \`docs-canonical/DATA-MODEL.md\` | Database schemas & entities |
|
|
708
1085
|
| \`docs-canonical/SECURITY.md\` | Auth & secrets |
|
|
709
1086
|
| \`docs-canonical/TEST-SPEC.md\` | Test requirements |
|
|
710
1087
|
| \`docs-canonical/ENVIRONMENT.md\` | Environment setup |
|
|
1088
|
+
| \`AGENTS.md\` | AI agent instructions (this file) |
|
|
711
1089
|
| \`CHANGELOG.md\` | Change tracking |
|
|
712
1090
|
| \`DRIFT-LOG.md\` | Documented deviations |
|
|
713
1091
|
|
|
714
|
-
##
|
|
1092
|
+
## Permissions & Guardrails
|
|
1093
|
+
|
|
1094
|
+
> **IMPORTANT:** These limits apply to all AI agents working on this project.
|
|
1095
|
+
|
|
1096
|
+
### Allowed
|
|
1097
|
+
|
|
1098
|
+
- Read any file in the repository
|
|
1099
|
+
- Modify files within \`src/\`, \`tests/\`, and \`docs-canonical/\`
|
|
1100
|
+
- Run test commands (\`npm test\`, \`npx docguard-cli guard\`)
|
|
1101
|
+
- Create new files in appropriate directories
|
|
1102
|
+
|
|
1103
|
+
### Not Allowed
|
|
1104
|
+
|
|
1105
|
+
- Modify \`.env\` files or secrets
|
|
1106
|
+
- Push commits or create releases without explicit approval
|
|
1107
|
+
- Delete or rename canonical documentation files
|
|
1108
|
+
- Bypass DocGuard checks (\`docguard guard\` must pass)
|
|
1109
|
+
- Install new dependencies without approval
|
|
1110
|
+
|
|
1111
|
+
### Safety Rules
|
|
1112
|
+
|
|
1113
|
+
- Never hardcode secrets, tokens, or API keys
|
|
1114
|
+
- Always validate inputs before processing
|
|
1115
|
+
- Never expose internal paths or stack traces to users
|
|
1116
|
+
- Run \`npx docguard-cli guard\` before every commit
|
|
1117
|
+
|
|
1118
|
+
## Monorepo Support
|
|
1119
|
+
|
|
1120
|
+
<!-- If this is a monorepo, nested AGENTS.md files in subdirectories
|
|
1121
|
+
override these instructions for their scope. -->
|
|
1122
|
+
|
|
1123
|
+
| Scope | AGENTS.md Location |
|
|
1124
|
+
|-------|-------------------|
|
|
1125
|
+
| Root (default) | \`./AGENTS.md\` |
|
|
1126
|
+
| <!-- e.g. packages/api --> | <!-- packages/api/AGENTS.md --> |
|
|
1127
|
+
|
|
1128
|
+
## DocGuard Commands
|
|
715
1129
|
|
|
716
1130
|
\`\`\`bash
|
|
717
|
-
npx docguard guard # Validate compliance
|
|
718
|
-
npx docguard
|
|
719
|
-
npx docguard fix --
|
|
720
|
-
npx docguard
|
|
721
|
-
npx docguard
|
|
1131
|
+
npx docguard-cli guard # Validate compliance
|
|
1132
|
+
npx docguard-cli diagnose # Identify issues + AI fix prompts
|
|
1133
|
+
npx docguard-cli fix --doc ARCH # Fix specific document
|
|
1134
|
+
npx docguard-cli score # CDD maturity score (0-100)
|
|
1135
|
+
npx docguard-cli generate # Generate docs from code
|
|
722
1136
|
\`\`\`
|
|
723
1137
|
|
|
724
1138
|
### AI Agent Workflow (IMPORTANT)
|
|
725
1139
|
|
|
726
|
-
1. **Before work**: Run \`npx docguard guard\` — understand compliance state
|
|
727
|
-
2. **After changes**: Run \`npx docguard
|
|
1140
|
+
1. **Before work**: Run \`npx docguard-cli guard\` — understand compliance state
|
|
1141
|
+
2. **After changes**: Run \`npx docguard-cli diagnose\` — get fix instructions
|
|
728
1142
|
3. **Fix issues**: Each issue has an \`ai_instruction\` — follow it exactly
|
|
729
|
-
4. **Verify**: Run \`npx docguard guard\` again — must pass before commit
|
|
1143
|
+
4. **Verify**: Run \`npx docguard-cli guard\` again — must pass before commit
|
|
730
1144
|
5. **Update CHANGELOG**: All changes need a changelog entry
|
|
731
1145
|
|
|
732
1146
|
## Rules
|
|
@@ -738,7 +1152,7 @@ npx docguard score # CDD maturity score
|
|
|
738
1152
|
- Documentation changes must pass \`docguard guard\`
|
|
739
1153
|
`;
|
|
740
1154
|
writeFileSync(agentsPath, content, 'utf-8');
|
|
741
|
-
console.log(` ${c.green}✅ AGENTS.md${c.reset}`);
|
|
1155
|
+
console.log(` ${c.green}✅ AGENTS.md${c.reset} (AGENTS.md standard compliant)`);
|
|
742
1156
|
created++;
|
|
743
1157
|
} else {
|
|
744
1158
|
console.log(` ${c.dim}⏭️ AGENTS.md (exists)${c.reset}`);
|