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.
- package/README.es.md +102 -0
- package/README.md +80 -32
- package/README.pt-BR.md +101 -0
- package/STANDARD.md +20 -10
- package/cli/commands/agents.mjs +149 -0
- package/cli/commands/diff.mjs +6 -15
- package/cli/commands/generate.mjs +14 -1001
- package/cli/commands/guard.mjs +136 -8
- package/cli/commands/llms.mjs +67 -5
- package/cli/commands/mcp.mjs +263 -0
- package/cli/commands/memory.mjs +115 -0
- package/cli/commands/score.mjs +76 -12
- package/cli/commands/trace.mjs +364 -1
- package/cli/commands/verify.mjs +93 -6
- package/cli/docguard.mjs +42 -5
- package/cli/findings.mjs +511 -0
- package/cli/scanners/agent-readability.mjs +202 -0
- package/cli/scanners/instruction-audit.mjs +320 -0
- package/cli/scanners/semantic-claims.mjs +7 -1
- package/cli/scanners/speckit.mjs +443 -28
- package/cli/shared-ignore.mjs +148 -16
- package/cli/shared.mjs +45 -1
- package/cli/validators/api-surface.mjs +113 -26
- package/cli/validators/architecture.mjs +66 -43
- package/cli/validators/canonical-sync.mjs +59 -28
- package/cli/validators/changelog.mjs +41 -17
- package/cli/validators/cross-reference.mjs +28 -11
- package/cli/validators/doc-quality.mjs +78 -44
- package/cli/validators/docs-coverage.mjs +90 -63
- package/cli/validators/docs-diff.mjs +63 -64
- package/cli/validators/docs-sync.mjs +48 -33
- package/cli/validators/drift.mjs +40 -34
- package/cli/validators/environment.mjs +67 -27
- package/cli/validators/freshness.mjs +12 -5
- package/cli/validators/generated-staleness.mjs +26 -10
- package/cli/validators/metadata-sync.mjs +28 -25
- package/cli/validators/metrics-consistency.mjs +89 -47
- package/cli/validators/schema-sync.mjs +37 -32
- package/cli/validators/security.mjs +7 -20
- package/cli/validators/spec-kit.mjs +3 -0
- package/cli/validators/structure.mjs +58 -23
- package/cli/validators/surface-sync.mjs +34 -15
- package/cli/validators/test-spec.mjs +87 -29
- package/cli/validators/todo-tracking.mjs +83 -74
- package/cli/validators/traceability.mjs +67 -39
- package/cli/writers/doc-generators.mjs +853 -0
- package/cli/writers/generate-io.mjs +142 -0
- package/cli/writers/sarif.mjs +129 -0
- package/commands/docguard.fix.md +56 -53
- package/commands/docguard.guard.md +53 -47
- package/commands/docguard.review.md +49 -31
- package/docs/ai-integration.md +133 -134
- package/docs/commands.md +49 -3
- package/docs/configuration.md +38 -0
- package/docs/faq.md +15 -0
- package/extensions/spec-kit-docguard/extension.yml +1 -1
- package/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +2 -2
- package/extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md +2 -2
- package/extensions/spec-kit-docguard/skills/docguard-review/SKILL.md +2 -2
- package/extensions/spec-kit-docguard/skills/docguard-score/SKILL.md +2 -2
- package/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +2 -2
- package/package.json +2 -1
- package/schemas/docguard-config.schema.json +28 -0
- package/templates/ci/gitlab-component.yml +90 -0
- package/templates/commands/docguard.fix.md +33 -10
- package/templates/commands/docguard.guard.md +40 -26
- package/templates/commands/docguard.init.md +23 -11
- package/templates/commands/docguard.review.md +25 -8
- 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
|
+
[](https://github.com/raccioly/docguard/actions/workflows/ci.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/docguard-cli)
|
|
14
|
+
[](https://pypi.org/project/docguard-cli/)
|
|
15
|
+
[](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
|
-
- [
|
|
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 (
|
|
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
|
-
##
|
|
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
|
-
|
|
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 **
|
|
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
|
```
|
package/README.pt-BR.md
ADDED
|
@@ -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
|
+
[](https://github.com/raccioly/docguard/actions/workflows/ci.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/docguard-cli)
|
|
14
|
+
[](https://pypi.org/project/docguard-cli/)
|
|
15
|
+
[](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
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|
|
package/cli/commands/agents.mjs
CHANGED
|
@@ -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) {
|
package/cli/commands/diff.mjs
CHANGED
|
@@ -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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
}
|