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.
@@ -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. Scan Project Structure ──
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
- // ── 3. Generate Documents ──
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 DATA-MODEL.md
53
- const dataResult = generateDataModel(projectDir, config, stack, scan, flags);
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
- ## System Overview
438
+ ## 1. Introduction & Goals
439
+ <!-- arc42: §1 — Introduction and Goals -->
319
440
 
320
- <!-- TODO: Describe what this system does and who it's for -->
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
- ## Component Map
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('\n') || '| <!-- Add components --> | | | |'}
481
+ ${componentRows.join('\\n') || '| <!-- Add components --> | | | |'}
328
482
 
329
- ## Tech Stack
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
- ## Layer Boundaries
531
+ | Tool | Config | Status |
532
+ |------|--------|--------|
533
+ ${docToolRows.join('\\n')}
534
+ ` : ''}
336
535
 
337
- <!-- TODO: Define which layers can import from which -->
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
- ## Diagrams
544
+ ## 9. Architecture Decisions
545
+ <!-- arc42: §9 — Architecture Decisions -->
346
546
 
347
- \`\`\`mermaid
348
- graph TD
349
- A[Client] --> B[${stack.framework || 'API'}]
350
- B --> C[Services]
351
- C --> D[${stack.database || 'Database'}]
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** | ![Status](https://img.shields.io/badge/status-draft-yellow) |
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 codebase scan |
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}✅ ARCHITECTURE.md${c.reset} (${componentRows.length} components, ${Object.values(stack).filter(Boolean).length} tech)`);
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
- function generateDataModel(dir, config, stack, scan, flags) {
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
- // Parse model files for entity names
376
- const entities = [];
377
- for (const modelFile of scan.models) {
378
- const name = basename(modelFile, extname(modelFile));
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
- // Check for Prisma schema
388
- const prismaPath = resolve(dir, 'prisma/schema.prisma');
389
- if (existsSync(prismaPath)) {
390
- const prismaContent = readFileSync(prismaPath, 'utf-8');
391
- const modelRegex = /model\s+(\w+)\s*\{/g;
392
- let match;
393
- while ((match = modelRegex.exec(prismaContent)) !== null) {
394
- if (!entities.find(e => e.name.toLowerCase() === match[1].toLowerCase())) {
395
- entities.push({ name: match[1], file: 'prisma/schema.prisma' });
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
- const entityRows = entities.map(e =>
401
- `| ${e.name} | ${stack.database || 'TBD'} | ${e.name.toLowerCase()}Id | See \`${e.file}\` |`
402
- ).join('\n');
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
- ## Entities
789
+ ## Entity Summary
423
790
 
424
- | Entity | Storage | Primary Key | Description |
425
- |--------|---------|-------------|-------------|
426
- ${entityRows || '| <!-- No models detected --> | | | |'}
791
+ | Entity | Storage | Primary Key | Source | Fields |
792
+ |--------|---------|-------------|--------|--------|
793
+ ${entityRows || '| <!-- No models detected --> | | | | |'}
427
794
 
428
- ${entities.map(e => `### ${e.name}
795
+ ---
429
796
 
430
- > Source: \`${e.file}\`
797
+ ## Entity Details
431
798
 
432
- | Field | Type | Required | Default | Constraints | Description |
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
- | <!-- TODO --> | | | | |
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 found) |
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 detected)`);
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. **Confirm** your approach before writing code
694
- 4. **Implement** matching existing code style
695
- 5. **Log** any deviations in \`DRIFT-LOG.md\` with \`// DRIFT: reason\`
696
- 6. **Run DocGuard** after changes \`npx docguard guard\`
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/DATA-MODEL.md\` | Database schemas |
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
- ## DocGuard Documentation Enforcement
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 fix # Find issues with fix instructions
719
- npx docguard fix --format prompt # AI-ready fix prompt
720
- npx docguard fix --auto # Auto-fix missing files
721
- npx docguard score # CDD maturity score
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 fix --format prompt\` — get fix instructions
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}`);