docguard-cli 0.28.0 → 0.30.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.
Files changed (69) hide show
  1. package/README.es.md +102 -0
  2. package/README.md +80 -32
  3. package/README.pt-BR.md +101 -0
  4. package/STANDARD.md +20 -10
  5. package/cli/commands/agents.mjs +149 -0
  6. package/cli/commands/diff.mjs +6 -15
  7. package/cli/commands/generate.mjs +14 -1001
  8. package/cli/commands/guard.mjs +136 -8
  9. package/cli/commands/llms.mjs +67 -5
  10. package/cli/commands/mcp.mjs +263 -0
  11. package/cli/commands/memory.mjs +115 -0
  12. package/cli/commands/score.mjs +76 -12
  13. package/cli/commands/trace.mjs +364 -1
  14. package/cli/commands/verify.mjs +93 -6
  15. package/cli/docguard.mjs +42 -5
  16. package/cli/findings.mjs +511 -0
  17. package/cli/scanners/agent-readability.mjs +202 -0
  18. package/cli/scanners/instruction-audit.mjs +320 -0
  19. package/cli/scanners/semantic-claims.mjs +7 -1
  20. package/cli/scanners/speckit.mjs +443 -28
  21. package/cli/shared-ignore.mjs +148 -16
  22. package/cli/shared.mjs +45 -1
  23. package/cli/validators/api-surface.mjs +113 -26
  24. package/cli/validators/architecture.mjs +66 -43
  25. package/cli/validators/canonical-sync.mjs +59 -28
  26. package/cli/validators/changelog.mjs +41 -17
  27. package/cli/validators/cross-reference.mjs +28 -11
  28. package/cli/validators/doc-quality.mjs +78 -44
  29. package/cli/validators/docs-coverage.mjs +90 -63
  30. package/cli/validators/docs-diff.mjs +63 -64
  31. package/cli/validators/docs-sync.mjs +48 -33
  32. package/cli/validators/drift.mjs +40 -34
  33. package/cli/validators/environment.mjs +67 -27
  34. package/cli/validators/freshness.mjs +12 -5
  35. package/cli/validators/generated-staleness.mjs +26 -10
  36. package/cli/validators/metadata-sync.mjs +28 -25
  37. package/cli/validators/metrics-consistency.mjs +89 -47
  38. package/cli/validators/schema-sync.mjs +37 -32
  39. package/cli/validators/security.mjs +7 -20
  40. package/cli/validators/spec-kit.mjs +3 -0
  41. package/cli/validators/structure.mjs +58 -23
  42. package/cli/validators/surface-sync.mjs +34 -15
  43. package/cli/validators/test-spec.mjs +87 -29
  44. package/cli/validators/todo-tracking.mjs +83 -74
  45. package/cli/validators/traceability.mjs +67 -39
  46. package/cli/writers/doc-generators.mjs +853 -0
  47. package/cli/writers/generate-io.mjs +142 -0
  48. package/cli/writers/sarif.mjs +129 -0
  49. package/commands/docguard.fix.md +56 -53
  50. package/commands/docguard.guard.md +53 -47
  51. package/commands/docguard.review.md +49 -31
  52. package/docs/ai-integration.md +133 -134
  53. package/docs/commands.md +49 -3
  54. package/docs/configuration.md +38 -0
  55. package/docs/faq.md +15 -0
  56. package/extensions/spec-kit-docguard/extension.yml +1 -1
  57. package/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +2 -2
  58. package/extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md +2 -2
  59. package/extensions/spec-kit-docguard/skills/docguard-review/SKILL.md +2 -2
  60. package/extensions/spec-kit-docguard/skills/docguard-score/SKILL.md +2 -2
  61. package/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +2 -2
  62. package/package.json +2 -1
  63. package/schemas/docguard-config.schema.json +28 -0
  64. package/templates/ci/gitlab-component.yml +90 -0
  65. package/templates/commands/docguard.fix.md +33 -10
  66. package/templates/commands/docguard.guard.md +40 -26
  67. package/templates/commands/docguard.init.md +23 -11
  68. package/templates/commands/docguard.review.md +25 -8
  69. package/templates/commands/docguard.update.md +14 -4
package/README.es.md ADDED
@@ -0,0 +1,102 @@
1
+ <!-- docguard:translation source=README.md lang=es reviewed=2026-07-03 -->
2
+ <!-- El README en inglés es la fuente canónica. Esta es una versión curada — los
3
+ números y listas volátiles viven solo en el original para que nunca diverjan del código. -->
4
+
5
+ # 🛡️ DocGuard
6
+
7
+ [English](README.md) · [Português (BR)](README.pt-BR.md) · **Español**
8
+
9
+ > **La capa de enforcement para Spec-Driven Development.**
10
+ > Valida. Puntúa. Garantiza. Entrega documentación que los agentes de IA realmente pueden usar.
11
+
12
+ [![CI](https://github.com/raccioly/docguard/actions/workflows/ci.yml/badge.svg)](https://github.com/raccioly/docguard/actions/workflows/ci.yml)
13
+ [![npm](https://img.shields.io/npm/v/docguard-cli)](https://www.npmjs.com/package/docguard-cli)
14
+ [![PyPI](https://img.shields.io/pypi/v/docguard-cli)](https://pypi.org/project/docguard-cli/)
15
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
16
+
17
+ ---
18
+
19
+ > **✨ Mira lo que DocGuard detecta en 30 segundos — sin instalar nada:**
20
+ > ```bash
21
+ > npx docguard-cli demo
22
+ > ```
23
+
24
+ ## ¿Qué es DocGuard?
25
+
26
+ DocGuard es la herramienta de enforcement del **Canonical-Driven Development (CDD)**:
27
+ una metodología donde la documentación es la fuente de la verdad y la herramienta
28
+ **verifica, de forma determinista, que siga siendo verdad respecto al código**.
29
+
30
+ La diferencia frente a otras herramientas de documentación: un resultado verde de
31
+ DocGuard significa *"los documentos coinciden con el código, de forma verificable"* —
32
+ no solo "los archivos existen". Extrae rutas, esquemas, variables de entorno, conteos
33
+ y afirmaciones documentadas, y los compara contra el código real. Núcleo sin llamadas
34
+ a LLM: determinista, offline, auditable.
35
+
36
+ ## Inicio rápido
37
+
38
+ ```bash
39
+ # en el directorio de tu proyecto
40
+ npx docguard-cli init # crea los documentos canónicos (detecta tu stack)
41
+ npx docguard-cli guard # valida — verde significa "docs correctos"
42
+ npx docguard-cli score # nota de madurez de la documentación (0-100)
43
+ ```
44
+
45
+ Para un proyecto existente, el camino inverso funciona mejor:
46
+
47
+ ```bash
48
+ npx docguard-cli generate --plan --write # ingeniería inversa: docs desde el código
49
+ ```
50
+
51
+ ## Los 5 comandos del día a día
52
+
53
+ | Comando | Qué hace |
54
+ |:--------|:---------|
55
+ | `init` | Inicializa el proyecto (detecta el stack automáticamente) |
56
+ | `guard` | Valida los documentos contra el código — la puerta de CI |
57
+ | `diff` | Muestra las brechas entre docs y código (`--since <ref>` para impacto de PR) |
58
+ | `sync` | Regenera las secciones de "verdad del código" en los documentos |
59
+ | `score` | Nota de madurez CDD, con desglose por categoría |
60
+
61
+ La lista completa de comandos, validadores y flags está en el
62
+ [README en inglés](README.md#usage) — el propio DocGuard la mantiene
63
+ sincronizada con el código.
64
+
65
+ ## Integración con IA (nativa, no improvisada)
66
+
67
+ DocGuard está diseñado para ser usado **por** agentes de IA, no solo por humanos:
68
+
69
+ - **Servidor MCP** — `claude mcp add docguard -- npx docguard-cli mcp` expone
70
+ guard/score/explain/verify/diagnose como herramientas nativas para Claude,
71
+ Cursor y cualquier cliente MCP.
72
+ - **Contrato JSON estable** — `guard --format json` con códigos de hallazgo
73
+ estables, explicables (`docguard explain <CÓDIGO>`) y suprimibles en línea.
74
+ - **SARIF** — `guard --format sarif` se integra con GitHub Code Scanning.
75
+ - **llms.txt / llms-full.txt / context pack** — superficies de contexto para
76
+ LLMs que leen el repositorio.
77
+ - **GitHub Action** — anotaciones inline en el diff del PR + comentario fijo
78
+ con el impacto en los documentos canónicos.
79
+ - **`agents --sync`** — AGENTS.md se convierte en la fuente canónica de
80
+ CLAUDE.md, las reglas de Cursor, las instrucciones de Copilot y demás — sin
81
+ duplicación manual, sin drift.
82
+
83
+ Guía completa: [docs/ai-integration.md](docs/ai-integration.md) (en inglés).
84
+
85
+ ## Instalación permanente
86
+
87
+ ```bash
88
+ npm install -g docguard-cli # Node.js 18+
89
+ # o vía Python:
90
+ pip install docguard-cli # wrapper de PyPI (requiere Node.js 18+)
91
+ ```
92
+
93
+ ## Comunidad
94
+
95
+ - [Discusiones](https://github.com/raccioly/docguard/discussions) — preguntas e ideas
96
+ - [Issues](https://github.com/raccioly/docguard/issues) — bugs y peticiones de features
97
+ - [CHANGELOG](CHANGELOG.md) — historial completo de versiones
98
+ - [Cómo contribuir](CONTRIBUTING.md)
99
+
100
+ ---
101
+
102
+ **Licencia MIT** · Hecho para equipos que tratan la documentación como un contrato, no como un adorno.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # 🛡️ DocGuard
2
2
 
3
+ **English** · [Português (BR)](README.pt-BR.md) · [Español](README.es.md)
4
+
3
5
  > **The enforcement layer for Spec-Driven Development.**
4
6
  > Validate. Score. Enforce. Ship documentation that AI agents can actually use.
5
7
 
@@ -27,7 +29,7 @@
27
29
  ## Table of Contents
28
30
 
29
31
  - [What is DocGuard?](#what-is-docguard)
30
- - [What's New](#-whats-new)
32
+ - [Why DocGuard?](#why-docguard)
31
33
  - [Quick Start](#-quick-start)
32
34
  - [Spec Kit Integration](#-spec-kit-integration)
33
35
  - [Usage](#usage)
@@ -38,6 +40,7 @@
38
40
  - [Examples](#-examples)
39
41
  - [Testing](#-testing)
40
42
  - [CI/CD Integration](#%EF%B8%8F-cicd-integration)
43
+ - [What's New](#-whats-new)
41
44
  - [File Structure](#-file-structure)
42
45
  - [Configuration](#%EF%B8%8F-configuration)
43
46
  - [Research Credits](#-research-credits)
@@ -63,7 +66,7 @@ DocGuard is an official [GitHub Spec Kit](https://github.com/github/spec-kit) co
63
66
 
64
67
  ```mermaid
65
68
  graph TD
66
- CLI["CLI Entry<br/>docguard.mjs"] --> Commands["Commands (17)"]
69
+ CLI["CLI Entry<br/>docguard.mjs"] --> Commands["Commands (18)"]
67
70
  Commands --> guard["guard"]
68
71
  Commands --> generate["generate"]
69
72
  Commands --> score["score"]
@@ -94,35 +97,14 @@ graph TD
94
97
 
95
98
  ---
96
99
 
97
- ## What's New
98
-
99
- Recent highlights across the v0.16 → v0.19 line:
100
-
101
- - **`docguard explain <validator>`** — `docguard explain freshness` prints purpose, rules, common
102
- failures, and fix recipes for any of the 24 validators. No need to dig into source.
103
- - **`docguard memory --diff`** — surface what changed in your canonical docs between two refs
104
- (`HEAD~10..HEAD` by default). Great for code review and changelog drafting.
105
- - **`docguard score --diff`** — see exactly which validators moved the score up or down between
106
- two commits. Pinpoints regressions without re-running the full suite by hand.
107
- - **`docguard upgrade --apply --pr`** — when the config schema bumps, DocGuard migrates
108
- `.docguard.json` for you and (optionally) opens a PR with the change.
109
- - **Language-aware traceability** — both `docguard trace` *and* the guard-time Traceability validator
110
- understand Python, Rust, Go, Java, Ruby, and PHP layouts in addition to JS/TS, via a shared pattern
111
- set (`cli/shared-trace-patterns.mjs`) so the two never drift apart.
112
- - **Per-validator severity overrides** — escalate `freshness` to `high` for production repos,
113
- demote `doc-quality` to `low` for prototypes. Configurable per-project.
114
- - **JSON Schema for `.docguard.json`** — IDE autocomplete, in-line docs, and validation via
115
- `$schema`. Shipped in the package at `schemas/docguard-config.schema.json`.
116
- - **Version pin (`docguardVersion` + `--pin`)** — pin the CLI version your project supports so
117
- CI fails loudly if someone bumps DocGuard without re-running the suite.
118
- - **Cross-process plan cache** — repeated runs reuse the validator plan across processes when
119
- the working tree hasn't changed. ~30% faster guard runs on typical repos.
120
- - **Headless-aware banner** — `--quiet`, `--format json`, `--write`, and `--changed-only`
121
- automatically suppress the banner so JSON output stays parse-clean.
122
- - **npm-pack smoke gate** — every release now extracts the actual tarball and runs the CLI
123
- end-to-end before publish, catching missing-file regressions.
100
+ ## Why DocGuard?
124
101
 
125
- See [CHANGELOG.md](CHANGELOG.md) for the full history.
102
+ Documentation that drifts from code is worse than no documentation — it
103
+ confidently misleads humans and AI agents alike. DocGuard treats your canonical
104
+ docs as an enforced contract: deterministic validators diff what the docs claim
105
+ against what the code does, on every commit, with no LLM required. The full
106
+ thesis (and the research behind it) lives in [PHILOSOPHY.md](PHILOSOPHY.md);
107
+ recent feature highlights moved [below](#-whats-new).
126
108
 
127
109
  ---
128
110
 
@@ -150,6 +132,19 @@ docguard diagnose
150
132
 
151
133
  > **Note:** The Python package is a thin wrapper that delegates to `npx`. Node.js 18+ is required on the system.
152
134
 
135
+ ### More ways to integrate
136
+
137
+ - **pre-commit** — changed-only guard on every commit:
138
+ ```yaml
139
+ repos:
140
+ - repo: https://github.com/raccioly/docguard
141
+ rev: v0.29.0
142
+ hooks: [{ id: docguard-guard }] # docguard-guard-full for pre-push
143
+ ```
144
+ - **MCP** (Claude, Cursor, any MCP client) — `claude mcp add docguard -- npx -y docguard-cli mcp`; 5 read-only tools (guard, score, explain, verify-claims, diagnose). Registry manifest ships in-repo (`server.json`, Smithery-ready).
145
+ - **GitLab CI** — component staged at [`templates/ci/gitlab-component.yml`](templates/ci/gitlab-component.yml) (guard/score/ci job with a SARIF artifact).
146
+ - **Homebrew** — `brew install raccioly/tap/docguard` (formula in [`packaging/homebrew/`](packaging/homebrew/)).
147
+
153
148
  ### Core Workflow
154
149
 
155
150
  ```bash
@@ -250,7 +245,7 @@ This installs DocGuard's slash commands (`/docguard.init`, `/docguard.guard`, `/
250
245
 
251
246
  ## Usage
252
247
 
253
- DocGuard ships **17 commands** (the "Daily 5" + 12 situational tools, including the zero-install `demo`). Six additional one-shot scaffolders are accessed via `docguard init --with <name>`. Eight v0.19 commands continue to work as deprecation aliases through v0.20.x — see [MIGRATION-v0.20.md](docs-implementation/MIGRATION-v0.20.md).
248
+ DocGuard ships **18 commands** (the "Daily 5" + 13 situational tools, including the zero-install `demo` and the `mcp` server). Six additional one-shot scaffolders are accessed via `docguard init --with <name>`. Eight v0.19 commands continue to work as deprecation aliases through v0.20.x — see [MIGRATION-v0.20.md](docs-implementation/MIGRATION-v0.20.md).
254
249
 
255
250
  **The Daily 5** — what you'll reach for 95% of the time:
256
251
 
@@ -271,15 +266,19 @@ DocGuard ships **17 commands** (the "Daily 5" + 12 situational tools, including
271
266
  | `fix` | Generate AI fix instructions for specific docs (`--doc <name> --format prompt`) |
272
267
  | `fix --write` | Apply deterministic fixes (no AI — version bumps, counts, anchors, sections) |
273
268
  | `fix --history` | Audit log of every mechanical fix applied (from `.docguard/fixed.json`) |
274
- | `generate` | Reverse-engineer docs from existing codebase (`--plan` for AI scan) |
269
+ | `generate` | Reverse-engineer docs from existing codebase (`--plan` for AI scan) — includes auto-generated Mermaid ER diagrams from your detected schemas (Prisma/Drizzle/TypeORM/Sequelize/Django/Rails) in DATA-MODEL.md |
275
270
  | `agent` | One-shot agent task graph — ordered, pre-filled code-truth, per-task verify (`--format json`) |
276
271
  | `explain <warning\|CODE>` | Paste any warning — or a finding code like `SEC001` — to get the validator's docstring, fix path, and how to suppress |
277
272
  | `verify --semantic` | Extract documented numbers/limits/enums (retention days, rate limits, GSI/role counts, status enums) as a task list for an agent to check against code — the semantic-drift class regex/AST can't see |
273
+ | `verify --instructions` | Audit AGENTS.md/CLAUDE.md themselves for drift: duplicate rules, never-vs-always contradictions, stale file pointers, unknown commands — plus clustered rule pairs as agent judgment tasks |
278
274
  | `feedback` | Report likely false positives back to DocGuard — local-first record + a 1-click prefilled, redacted GitHub issue (zero typing) |
275
+ | `mcp` | MCP server over stdio — exposes guard/score/explain/verify/diagnose as native tools for Claude, Cursor, and any MCP client. Setup: `claude mcp add docguard -- npx docguard-cli mcp` |
279
276
  | `memory` | Per-domain accuracy headline (endpoints / entities / env / tech) |
280
277
  | `memory --diff` | Drill into which specific claims don't match code |
278
+ | `memory --pack` | Write `.docguard/context-pack.md` — compact, code-truth-stamped session-start context for AI agents |
281
279
  | `score --diff` | Drill into which checks pulled each category down |
282
280
  | `trace` / `trace --reverse <file>` | Requirements traceability — forward AND reverse |
281
+ | `trace --features` | Per-feature spec-adherence scores (requirement coverage, task completion, task evidence, artifacts) — worst-first with fix hints |
283
282
  | `upgrade [--apply] [--pr]` | Check + migrate `.docguard.json` schema; `--pr` opens a PR |
284
283
  | `watch` | Live mode: re-run guard on file changes |
285
284
 
@@ -306,6 +305,11 @@ Run them solo (`docguard init --with hooks`) or stacked (`docguard init --with a
306
305
  | `--verbose` | Show detailed output | All |
307
306
  | `--quiet` / `-q` | Suppress banner — for hooks, CI loops, scripts | All |
308
307
  | `--format json` | Machine-readable output (clean JSON, no ANSI bleed) | guard, score, diff, trace, diagnose, memory, impact, explain |
308
+ | `--format sarif` | SARIF 2.1.0 output — findings as rules/results for GitHub Code Scanning and SARIF dashboards | guard |
309
+ | `--full` | Generate `llms-full.txt` (full doc bodies inlined) instead of the `llms.txt` link index | llms |
310
+ | `--pack` | Write `.docguard/context-pack.md` — agent session-start context | memory |
311
+ | `--sync` | Regenerate the agent-file family (CLAUDE.md, Copilot, Cursor, …) from AGENTS.md; hash-marked, never touches hand-written files without `--force` | agents |
312
+ | `--check` | CI gate for the synced agent-file family — exit 2 when a variant is stale | agents |
309
313
  | `--force` | Overwrite existing files (creates `.bak` backups) | generate, agents, init |
310
314
  | `--force-redo` | Bypass ping-pong suppression in `.docguard/fixed.json` | fix --write |
311
315
  | `--profile <name>` | Starter / standard / enterprise | init |
@@ -547,6 +551,7 @@ DocGuard runs its own `guard`, `score`, `diff`, `diagnose`, and `badge` commands
547
551
  ```yaml
548
552
  name: DocGuard Guard
549
553
  on: [pull_request, push]
554
+ permissions: { pull-requests: write } # for the sticky PR comment (optional)
550
555
  jobs:
551
556
  docguard:
552
557
  runs-on: ubuntu-latest
@@ -558,6 +563,17 @@ jobs:
558
563
  command: guard
559
564
  ```
560
565
 
566
+ On pull requests, guard mode also gives inline PR feedback (both default on):
567
+
568
+ | Input | Default | Description |
569
+ |-------|---------|-------------|
570
+ | `annotations` | `true` | Inline `::error`/`::warning` annotations on the PR diff, one per guard finding (capped at 50; a final notice reports how many were elided) |
571
+ | `pr-comment` | `true` | Sticky PR comment with the guard verdict, top findings (by code), and which canonical docs the PR's changed files impact (`diff --since origin/<base>`). Needs `permissions: pull-requests: write`; degrades to a log warning without it |
572
+
573
+ Both run even when guard fails — that's when the feedback matters. Prefer native
574
+ code-scanning integration? `docguard guard --format sarif` uploads straight to
575
+ GitHub Code Scanning via `github/codeql-action/upload-sarif`.
576
+
561
577
  ### GitHub Actions — Auto-Fix (commits mechanical fixes back)
562
578
 
563
579
  ```yaml
@@ -592,6 +608,38 @@ Two ready-to-use templates ship with the Spec Kit extension and as standalone fi
592
608
 
593
609
  ---
594
610
 
611
+ ## ✨ What's New
612
+
613
+ Recent highlights across the v0.16 → v0.19 line:
614
+
615
+ - **`docguard explain <validator>`** — `docguard explain freshness` prints purpose, rules, common
616
+ failures, and fix recipes for any of the 24 validators. No need to dig into source.
617
+ - **`docguard memory --diff`** — surface what changed in your canonical docs between two refs
618
+ (`HEAD~10..HEAD` by default). Great for code review and changelog drafting.
619
+ - **`docguard score --diff`** — see exactly which validators moved the score up or down between
620
+ two commits. Pinpoints regressions without re-running the full suite by hand.
621
+ - **`docguard upgrade --apply --pr`** — when the config schema bumps, DocGuard migrates
622
+ `.docguard.json` for you and (optionally) opens a PR with the change.
623
+ - **Language-aware traceability** — both `docguard trace` *and* the guard-time Traceability validator
624
+ understand Python, Rust, Go, Java, Ruby, and PHP layouts in addition to JS/TS, via a shared pattern
625
+ set (`cli/shared-trace-patterns.mjs`) so the two never drift apart.
626
+ - **Per-validator severity overrides** — escalate `freshness` to `high` for production repos,
627
+ demote `doc-quality` to `low` for prototypes. Configurable per-project.
628
+ - **JSON Schema for `.docguard.json`** — IDE autocomplete, in-line docs, and validation via
629
+ `$schema`. Shipped in the package at `schemas/docguard-config.schema.json`.
630
+ - **Version pin (`docguardVersion` + `--pin`)** — pin the CLI version your project supports so
631
+ CI fails loudly if someone bumps DocGuard without re-running the suite.
632
+ - **Cross-process plan cache** — repeated runs reuse the validator plan across processes when
633
+ the working tree hasn't changed. ~30% faster guard runs on typical repos.
634
+ - **Headless-aware banner** — `--quiet`, `--format json`, `--write`, and `--changed-only`
635
+ automatically suppress the banner so JSON output stays parse-clean.
636
+ - **npm-pack smoke gate** — every release now extracts the actual tarball and runs the CLI
637
+ end-to-end before publish, catching missing-file regressions.
638
+
639
+ See [CHANGELOG.md](CHANGELOG.md) for the full history.
640
+
641
+ ---
642
+
595
643
  ## 📁 File Structure
596
644
 
597
645
  ```
@@ -0,0 +1,101 @@
1
+ <!-- docguard:translation source=README.md lang=pt-BR reviewed=2026-07-03 -->
2
+ <!-- O README em inglês é a fonte canônica. Esta é uma versão curada — números
3
+ e listas voláteis ficam apenas no original para nunca divergirem do código. -->
4
+
5
+ # 🛡️ DocGuard
6
+
7
+ [English](README.md) · **Português (BR)** · [Español](README.es.md)
8
+
9
+ > **A camada de enforcement para Spec-Driven Development.**
10
+ > Valide. Pontue. Garanta. Entregue documentação que agentes de IA conseguem realmente usar.
11
+
12
+ [![CI](https://github.com/raccioly/docguard/actions/workflows/ci.yml/badge.svg)](https://github.com/raccioly/docguard/actions/workflows/ci.yml)
13
+ [![npm](https://img.shields.io/npm/v/docguard-cli)](https://www.npmjs.com/package/docguard-cli)
14
+ [![PyPI](https://img.shields.io/pypi/v/docguard-cli)](https://pypi.org/project/docguard-cli/)
15
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
16
+
17
+ ---
18
+
19
+ > **✨ Veja o que o DocGuard detecta em 30 segundos — sem instalar nada:**
20
+ > ```bash
21
+ > npx docguard-cli demo
22
+ > ```
23
+
24
+ ## O que é o DocGuard?
25
+
26
+ O DocGuard é a ferramenta de enforcement do **Canonical-Driven Development (CDD)** —
27
+ uma metodologia em que a documentação é a fonte da verdade e a ferramenta **verifica,
28
+ deterministicamente, que ela continua verdadeira em relação ao código**.
29
+
30
+ A diferença para outras ferramentas de documentação: um resultado verde do DocGuard
31
+ significa *"os documentos correspondem ao código, de forma verificável"* — não apenas
32
+ "os arquivos existem". Ele extrai rotas, schemas, variáveis de ambiente, contagens e
33
+ afirmações documentadas, e compara tudo com o código real. Núcleo com zero chamadas a
34
+ LLM: determinístico, offline, auditável.
35
+
36
+ ## Início rápido
37
+
38
+ ```bash
39
+ # no diretório do seu projeto
40
+ npx docguard-cli init # cria os documentos canônicos (detecta seu stack)
41
+ npx docguard-cli guard # valida — verde significa "docs corretos"
42
+ npx docguard-cli score # nota de maturidade da documentação (0-100)
43
+ ```
44
+
45
+ Para um projeto existente, o caminho inverso funciona melhor:
46
+
47
+ ```bash
48
+ npx docguard-cli generate --plan --write # engenharia reversa: docs a partir do código
49
+ ```
50
+
51
+ ## Os 5 comandos do dia a dia
52
+
53
+ | Comando | O que faz |
54
+ |:--------|:----------|
55
+ | `init` | Inicializa o projeto (detecta o stack automaticamente) |
56
+ | `guard` | Valida os documentos contra o código — o portão de CI |
57
+ | `diff` | Mostra a diferença entre docs e código (`--since <ref>` para impacto de PR) |
58
+ | `sync` | Regenera as seções de "verdade do código" nos documentos |
59
+ | `score` | Nota de maturidade CDD, com detalhamento por categoria |
60
+
61
+ A lista completa de comandos, validadores e flags está no
62
+ [README em inglês](README.md#usage) — mantida sincronizada com o código pelo
63
+ próprio DocGuard.
64
+
65
+ ## Integração com IA (nativo, não improvisado)
66
+
67
+ O DocGuard foi desenhado para ser usado **por** agentes de IA, não só por humanos:
68
+
69
+ - **Servidor MCP** — `claude mcp add docguard -- npx docguard-cli mcp` expõe
70
+ guard/score/explain/verify/diagnose como ferramentas nativas para Claude,
71
+ Cursor e qualquer cliente MCP.
72
+ - **Contrato JSON estável** — `guard --format json` com códigos de finding
73
+ estáveis, explicáveis (`docguard explain <CÓDIGO>`) e supressíveis na linha.
74
+ - **SARIF** — `guard --format sarif` integra com o GitHub Code Scanning.
75
+ - **llms.txt / llms-full.txt / context pack** — superfícies de contexto para
76
+ LLMs que leem o repositório.
77
+ - **GitHub Action** — anotações inline no diff do PR + comentário fixo com o
78
+ impacto nos documentos canônicos.
79
+ - **`agents --sync`** — o AGENTS.md vira fonte canônica para CLAUDE.md, regras
80
+ do Cursor, instruções do Copilot e afins — sem duplicação manual, sem drift.
81
+
82
+ Guia completo: [docs/ai-integration.md](docs/ai-integration.md) (em inglês).
83
+
84
+ ## Instalação permanente
85
+
86
+ ```bash
87
+ npm install -g docguard-cli # Node.js 18+
88
+ # ou via Python:
89
+ pip install docguard-cli # wrapper PyPI (requer Node.js 18+)
90
+ ```
91
+
92
+ ## Comunidade
93
+
94
+ - [Discussões](https://github.com/raccioly/docguard/discussions) — perguntas e ideias
95
+ - [Issues](https://github.com/raccioly/docguard/issues) — bugs e pedidos de feature
96
+ - [CHANGELOG](CHANGELOG.md) — histórico completo de versões
97
+ - [Como contribuir](CONTRIBUTING.md)
98
+
99
+ ---
100
+
101
+ **Licença MIT** · Feito para times que tratam documentação como contrato, não como enfeite.
package/STANDARD.md CHANGED
@@ -610,16 +610,26 @@ Project-level configuration file that customizes validation for the specific pro
610
610
 
611
611
  ## 8. Validator Reference
612
612
 
613
- | # | Validator | Checks | Default | Severity |
614
- |---|-----------|--------|---------|----------|
615
- | 1 | **structure** | All required files exist | On | Error |
616
- | 2 | **docs-sync** | Source files have matching canonical doc entries | ✅ On | Warning |
617
- | 3 | **drift** | `// DRIFT:` comments have DRIFT-LOG entries | ✅ On | Error |
618
- | 4 | **changelog** | Staged changes have CHANGELOG entries | ✅ On | Warning |
619
- | 5 | **architecture** | Imports follow declared layer boundaries | ❌ Off | Error |
620
- | 6 | **test-spec** | Required tests exist per TEST-SPEC.md | On | Warning |
621
- | 7 | **security** | No secrets in code, security patterns followed | ❌ Off | Error |
622
- | 8 | **environment** | Env vars documented, .env.example exists | ✅ On | Warning |
613
+ This specification defines the **CDD structure** the files, sections, and
614
+ markers of §4–§7. Validators are an **implementation detail of the DocGuard
615
+ CLI** and are additive across releases, so this document deliberately does not
616
+ enumerate them (an embedded table drifted two major versions behind the CLI
617
+ the exact failure mode CDD exists to prevent).
618
+
619
+ The founding eight (structure, docs-sync, drift, changelog, architecture,
620
+ test-spec, security, environment) map directly to the file formats in §5; the
621
+ CLI has since grown well past twenty. For the authoritative, machine-governed
622
+ list:
623
+
624
+ - run `docguard guard` — every validator prints its name and result;
625
+ - run `docguard explain <validator>` for any validator's contract;
626
+ - see the [README Validators section](README.md#-validators), whose counts are
627
+ enforced against code by the `canonical-sync` validator on every guard run.
628
+
629
+ A conforming third-party CDD implementation MUST validate the structural rules
630
+ of §4–§6 (required files, section presence, DRIFT markers ↔ DRIFT-LOG) and MAY
631
+ implement any further checks; the exit-code contract below is the stable
632
+ interface.
623
633
 
624
634
  ### Exit Codes
625
635
 
@@ -1,10 +1,19 @@
1
1
  /**
2
2
  * Agents Command — Generate agent-specific config files from AGENTS.md
3
3
  * Creates .cursor/rules/, .clinerules, .github/copilot-instructions.md, etc.
4
+ *
5
+ * v0.29 sync mode: AGENTS.md is the CANONICAL source; the generated family
6
+ * (CLAUDE.md, .clinerules, copilot-instructions, …) carries a source-hash
7
+ * marker. `--sync` regenerates every marked (or missing) variant; `--check`
8
+ * is the CI staleness gate (exit 2 when a marked variant's hash no longer
9
+ * matches AGENTS.md). Files that exist WITHOUT our marker are user content —
10
+ * never overwritten without --force. This kills the hand-duplication drift
11
+ * between agent files, which is exactly the failure class DocGuard exists for.
4
12
  */
5
13
 
6
14
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
7
15
  import { resolve, dirname } from 'node:path';
16
+ import { createHash } from 'node:crypto';
8
17
  import { c } from '../shared.mjs';
9
18
 
10
19
  const AGENT_TARGETS = {
@@ -40,6 +49,44 @@ const AGENT_TARGETS = {
40
49
  },
41
50
  };
42
51
 
52
+ // ── Sync markers (v0.29) ─────────────────────────────────────────────────────
53
+
54
+ const sourceHash = (content) => createHash('sha256').update(content).digest('hex').slice(0, 16);
55
+
56
+ /**
57
+ * Stamp generated content with the sync marker. Text formats get HTML-comment
58
+ * lines; JSON gets a `_docguardSync` field (comments would break parsing).
59
+ * For frontmatter files (.mdc) the marker goes AFTER the closing `---` so the
60
+ * frontmatter stays the first bytes, as Cursor requires.
61
+ */
62
+ function stampMarker(content, hash, targetPath) {
63
+ const marker = `<!-- docguard:agents-sync source=AGENTS.md hash=${hash} -->\n<!-- Do not edit — regenerate with: docguard agents --sync -->\n`;
64
+ if (targetPath.endsWith('.json')) {
65
+ try {
66
+ const obj = JSON.parse(content);
67
+ obj._docguardSync = { source: 'AGENTS.md', hash, note: 'Do not edit — regenerate with: docguard agents --sync' };
68
+ return JSON.stringify(obj, null, 2);
69
+ } catch { return content; }
70
+ }
71
+ if (content.startsWith('---\n')) {
72
+ const end = content.indexOf('\n---', 4);
73
+ if (end !== -1) {
74
+ const cut = end + 4;
75
+ return content.slice(0, cut) + '\n' + marker + content.slice(cut);
76
+ }
77
+ }
78
+ return marker + '\n' + content;
79
+ }
80
+
81
+ /** Extract the recorded source hash from a generated file, or null if unmarked. */
82
+ function extractMarkerHash(content, targetPath) {
83
+ if (targetPath.endsWith('.json')) {
84
+ try { return JSON.parse(content)._docguardSync?.hash ?? null; } catch { return null; }
85
+ }
86
+ const m = content.match(/docguard:agents-sync source=AGENTS\.md hash=([0-9a-f]{16})/);
87
+ return m ? m[1] : null;
88
+ }
89
+
43
90
  export function runAgents(projectDir, config, flags) {
44
91
  console.log(`${c.bold}🤖 DocGuard Agents — ${config.projectName}${c.reset}`);
45
92
  console.log(`${c.dim} Directory: ${projectDir}${c.reset}\n`);
@@ -53,6 +100,15 @@ export function runAgents(projectDir, config, flags) {
53
100
 
54
101
  const agentsContent = readFileSync(agentsPath, 'utf-8');
55
102
 
103
+ // ── v0.29: --check — CI staleness gate for the synced family ──
104
+ if (flags.check) {
105
+ return runAgentsCheck(projectDir, agentsContent, flags);
106
+ }
107
+ // ── v0.29: --sync — regenerate marked/missing variants from AGENTS.md ──
108
+ if (flags.sync) {
109
+ return runAgentsSync(projectDir, config, agentsContent, flags);
110
+ }
111
+
56
112
  // Parse which agents to generate for
57
113
  let targets = Object.keys(AGENT_TARGETS);
58
114
  const specificAgent = flags.agent;
@@ -95,6 +151,99 @@ export function runAgents(projectDir, config, flags) {
95
151
  console.log(` Created: ${created} Skipped: ${skipped}\n`);
96
152
  }
97
153
 
154
+ // ── Sync + Check modes (v0.29) ───────────────────────────────────────────────
155
+
156
+ /**
157
+ * `docguard agents --sync` — regenerate the agent-file family from AGENTS.md.
158
+ *
159
+ * Semantics per target:
160
+ * - missing → generate (stamped with the current source hash)
161
+ * - exists, our marker → regenerate (marked files are OURS to update)
162
+ * - exists, unmarked → SKIP with a warning (hand-written user content;
163
+ * --force overrides, which is the only destructive
164
+ * path and is explicit)
165
+ */
166
+ function runAgentsSync(projectDir, config, agentsContent, flags) {
167
+ const hash = sourceHash(agentsContent);
168
+ let synced = 0, fresh = 0, skipped = 0;
169
+
170
+ let targets = Object.keys(AGENT_TARGETS);
171
+ if (flags.agent) {
172
+ if (!AGENT_TARGETS[flags.agent]) {
173
+ console.log(` ${c.red}Unknown agent: ${flags.agent}${c.reset}`);
174
+ console.log(` Available: ${targets.join(', ')}\n`);
175
+ process.exit(1);
176
+ }
177
+ targets = [flags.agent];
178
+ }
179
+
180
+ for (const key of targets) {
181
+ const target = AGENT_TARGETS[key];
182
+ const targetPath = resolve(projectDir, target.path);
183
+ const exists = existsSync(targetPath);
184
+
185
+ if (exists) {
186
+ const current = readFileSync(targetPath, 'utf-8');
187
+ const recorded = extractMarkerHash(current, target.path);
188
+ if (recorded === null && !flags.force) {
189
+ console.log(` ${c.yellow}⚠️ ${target.name}: ${target.path} exists without a sync marker (hand-written?) — skipped. Use --force to adopt it.${c.reset}`);
190
+ skipped++;
191
+ continue;
192
+ }
193
+ if (recorded === hash) {
194
+ console.log(` ${c.dim}✓ ${target.name}: ${target.path} already in sync${c.reset}`);
195
+ fresh++;
196
+ continue;
197
+ }
198
+ }
199
+
200
+ const content = stampMarker(target.generate(agentsContent, config), hash, target.path);
201
+ const dir = dirname(targetPath);
202
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
203
+ writeFileSync(targetPath, content, 'utf-8');
204
+ console.log(` ${c.green}✅ ${target.name}${c.reset}: ${target.path} ${c.dim}(${exists ? 'resynced' : 'created'}, hash ${hash})${c.reset}`);
205
+ synced++;
206
+ }
207
+
208
+ console.log(`\n${c.bold} ─────────────────────────────────────${c.reset}`);
209
+ console.log(` Synced: ${synced} In sync: ${fresh} Skipped (unmarked): ${skipped}`);
210
+ console.log(` ${c.dim}CI gate: ${c.cyan}docguard agents --check${c.dim} exits 2 when a variant goes stale.${c.reset}\n`);
211
+ }
212
+
213
+ /**
214
+ * `docguard agents --check` — CI staleness gate. Only files that CARRY our
215
+ * marker are judged (an unmarked or absent variant is the user's choice, not
216
+ * drift). Stale marked file → warning + exit code 2 (matches guard's
217
+ * warnings-exit contract). Uses process.exitCode, never process.exit, so
218
+ * stdout always drains (bug-105 discipline).
219
+ */
220
+ function runAgentsCheck(projectDir, agentsContent, flags) {
221
+ const hash = sourceHash(agentsContent);
222
+ const stale = [];
223
+ let inSync = 0, unmanaged = 0;
224
+
225
+ for (const [, target] of Object.entries(AGENT_TARGETS)) {
226
+ const targetPath = resolve(projectDir, target.path);
227
+ if (!existsSync(targetPath)) { unmanaged++; continue; }
228
+ let recorded = null;
229
+ try { recorded = extractMarkerHash(readFileSync(targetPath, 'utf-8'), target.path); } catch { /* unreadable → unmanaged */ }
230
+ if (recorded === null) { unmanaged++; continue; }
231
+ if (recorded === hash) inSync++;
232
+ else stale.push(target.path);
233
+ }
234
+
235
+ if (stale.length > 0) {
236
+ for (const p of stale) {
237
+ console.log(` ${c.yellow}⚠ ${p} is stale — AGENTS.md changed since it was generated.${c.reset}`);
238
+ }
239
+ console.log(`\n ${c.yellow}${stale.length} agent file(s) out of sync.${c.reset} Fix: ${c.cyan}docguard agents --sync${c.reset}\n`);
240
+ process.exitCode = 2;
241
+ return;
242
+ }
243
+
244
+ console.log(` ${c.green}✅ Agent-file family in sync${c.reset} ${c.dim}(${inSync} synced, ${unmanaged} unmanaged/absent — unmarked files are yours, not checked)${c.reset}\n`);
245
+ }
246
+
98
247
  // ── Generator Functions ────────────────────────────────────────────────────
99
248
 
100
249
  function getCddBlock(config) {
@@ -6,6 +6,7 @@
6
6
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
7
7
  import { resolve, join, extname, basename } from 'node:path';
8
8
  import { c } from '../shared.mjs';
9
+ import { walkFiles as sharedWalkFiles } from '../shared-ignore.mjs';
9
10
  import { collectPackageJsons, detectDocker, grepEnvUsage, resolveSourceRoots } from '../shared-source.mjs';
10
11
  import { parseApiReferenceDoc, compareEndpoints } from '../scanners/api-doc.mjs';
11
12
  import { resolveApiSurface } from '../validators/api-surface.mjs';
@@ -379,22 +380,12 @@ function diffTests(dir, config = {}) {
379
380
 
380
381
  // ── Utilities ──────────────────────────────────────────────────────────────
381
382
 
383
+ // v0.29 consolidation: traversal delegates to the shared canonical walker
384
+ // (this copy was hiding in commands/, missed by the first validator sweep).
382
385
  function getFilesRecursive(dir) {
383
386
  const results = [];
384
- if (!existsSync(dir)) return results;
385
-
386
- const entries = readdirSync(dir);
387
- for (const entry of entries) {
388
- if (IGNORE_DIRS.has(entry) || entry.startsWith('.')) continue;
389
- const fullPath = join(dir, entry);
390
- try {
391
- const stat = statSync(fullPath);
392
- if (stat.isDirectory()) {
393
- results.push(...getFilesRecursive(fullPath));
394
- } else if (stat.isFile() && CODE_EXTENSIONS.has(extname(fullPath))) {
395
- results.push(fullPath);
396
- }
397
- } catch { /* skip */ }
398
- }
387
+ sharedWalkFiles(dir, (fullPath) => {
388
+ if (CODE_EXTENSIONS.has(extname(fullPath))) results.push(fullPath);
389
+ }, { ignoreDirs: IGNORE_DIRS });
399
390
  return results;
400
391
  }