docguard-cli 0.22.1 → 0.24.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 (61) hide show
  1. package/README.md +4 -4
  2. package/cli/commands/demo.mjs +1 -1
  3. package/cli/commands/diff.mjs +19 -8
  4. package/cli/commands/explain.mjs +178 -17
  5. package/cli/commands/fix.mjs +17 -2
  6. package/cli/commands/generate.mjs +2 -2
  7. package/cli/commands/guard.mjs +86 -11
  8. package/cli/commands/hooks.mjs +12 -7
  9. package/cli/commands/init.mjs +18 -6
  10. package/cli/commands/score.mjs +147 -61
  11. package/cli/commands/setup.mjs +2 -2
  12. package/cli/commands/trace.mjs +3 -101
  13. package/cli/commands/upgrade.mjs +61 -13
  14. package/cli/config.mjs +245 -0
  15. package/cli/docguard.mjs +21 -217
  16. package/cli/ensure-skills.mjs +24 -26
  17. package/cli/scanners/api-doc.mjs +17 -3
  18. package/cli/scanners/doc-tools.mjs +32 -15
  19. package/cli/scanners/frontend.mjs +24 -8
  20. package/cli/scanners/js-ast.mjs +432 -0
  21. package/cli/scanners/memory-plan.mjs +1 -1
  22. package/cli/scanners/py-ast.mjs +213 -0
  23. package/cli/scanners/routes.mjs +194 -69
  24. package/cli/scanners/schemas.mjs +97 -51
  25. package/cli/scanners/speckit.mjs +14 -0
  26. package/cli/shared-git.mjs +0 -0
  27. package/cli/shared-ignore.mjs +16 -1
  28. package/cli/shared-source.mjs +59 -2
  29. package/cli/shared-trace-patterns.mjs +118 -0
  30. package/cli/shared.mjs +60 -1
  31. package/cli/validator-markers.mjs +91 -0
  32. package/cli/validators/api-surface.mjs +37 -3
  33. package/cli/validators/canonical-sync.mjs +22 -19
  34. package/cli/validators/doc-quality.mjs +27 -44
  35. package/cli/validators/docs-coverage.mjs +13 -0
  36. package/cli/validators/docs-diff.mjs +16 -6
  37. package/cli/validators/docs-sync.mjs +4 -3
  38. package/cli/validators/drift.mjs +3 -2
  39. package/cli/validators/freshness.mjs +47 -15
  40. package/cli/validators/metadata-sync.mjs +21 -11
  41. package/cli/validators/metrics-consistency.mjs +45 -17
  42. package/cli/validators/security.mjs +13 -5
  43. package/cli/validators/structure.mjs +6 -5
  44. package/cli/validators/surface-sync.mjs +7 -5
  45. package/cli/validators/test-spec.mjs +76 -51
  46. package/cli/validators/todo-tracking.mjs +4 -2
  47. package/cli/validators/traceability.mjs +12 -54
  48. package/cli/writers/sections.mjs +32 -19
  49. package/docs/commands.md +1 -1
  50. package/docs/configuration.md +11 -0
  51. package/docs/faq.md +1 -1
  52. package/extensions/spec-kit-docguard/README.md +1 -1
  53. package/extensions/spec-kit-docguard/extension.yml +2 -2
  54. package/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +2 -2
  55. package/extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md +2 -2
  56. package/extensions/spec-kit-docguard/skills/docguard-review/SKILL.md +2 -2
  57. package/extensions/spec-kit-docguard/skills/docguard-score/SKILL.md +2 -2
  58. package/extensions/spec-kit-docguard/skills/docguard-sync/SKILL.md +2 -1
  59. package/extensions/spec-kit-docguard/templates/github-workflows/docguard-autofix.yml +3 -2
  60. package/extensions/spec-kit-docguard/templates/github-workflows/docguard-guard.yml +2 -2
  61. package/package.json +5 -3
@@ -15,6 +15,7 @@
15
15
 
16
16
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
17
17
  import { resolve, join, relative, basename, extname } from 'node:path';
18
+ import { TRACE_MAP, TEST_PATTERNS, isTraceableSource } from '../shared-trace-patterns.mjs';
18
19
 
19
20
  const IGNORE_DIRS = new Set([
20
21
  'node_modules', '.git', '.next', 'dist', 'build', 'coverage',
@@ -22,57 +23,6 @@ const IGNORE_DIRS = new Set([
22
23
  '.amplify-hosting', '.serverless',
23
24
  ]);
24
25
 
25
- /**
26
- * Mapping of canonical docs to source code patterns they should trace to.
27
- */
28
- const TRACE_MAP = {
29
- 'ARCHITECTURE.md': {
30
- sourcePatterns: [
31
- { label: 'Entry points', glob: /^(index|main|app|server)\.[jt]sx?$/ },
32
- { label: 'Config files', glob: /^(package\.json|tsconfig.*|next\.config|vite\.config)/ },
33
- { label: 'Route handlers', glob: /(routes?|api|pages|app)\// },
34
- ],
35
- },
36
- 'DATA-MODEL.md': {
37
- sourcePatterns: [
38
- { label: 'Schema definitions', glob: /(schema|model|entity|migration|prisma)/i },
39
- { label: 'Type definitions', glob: /types?\.[jt]sx?$/ },
40
- { label: 'Database configs', glob: /(drizzle|knex|sequelize|typeorm)/i },
41
- ],
42
- },
43
- 'TEST-SPEC.md': {
44
- sourcePatterns: [
45
- { label: 'Test files', glob: /\.(test|spec)\.(mjs|cjs|[jt]sx?)$/ },
46
- { label: 'Test config', glob: /(jest|vitest|playwright|cypress)\.config/ },
47
- { label: 'E2E tests', glob: /(e2e|integration)\// },
48
- ],
49
- },
50
- 'SECURITY.md': {
51
- sourcePatterns: [
52
- { label: 'Auth modules', glob: /(auth|login|session|jwt|oauth|middleware)/i },
53
- { label: 'Secret configs', glob: /\.(env|env\.example|env\.local)$/ },
54
- { label: 'Gitignore', glob: /^\.gitignore$/ },
55
- ],
56
- },
57
- 'ENVIRONMENT.md': {
58
- sourcePatterns: [
59
- { label: 'Env files', glob: /\.env/ },
60
- { label: 'Docker configs', glob: /(Dockerfile|docker-compose|\.dockerignore)/ },
61
- { label: 'CI/CD configs', glob: /\.(github|gitlab-ci|circleci)/ },
62
- ],
63
- },
64
- 'API-REFERENCE.md': {
65
- sourcePatterns: [
66
- { label: 'Route handlers', glob: /(routes?|controllers?|handlers?)\// },
67
- // Next.js App Router (and Pages Router) — `app/api/`, `src/app/api/`,
68
- // `pages/api/`, `src/pages/api/`. Without this, a perfectly-populated
69
- // Next.js API tree gets reported as "API-REFERENCE.md — unlinked doc".
70
- { label: 'Next.js API routes', glob: /(^|\/)(app|pages)\/api\// },
71
- { label: 'OpenAPI spec', glob: /(openapi|swagger)\.(json|ya?ml)/ },
72
- { label: 'API middleware', glob: /middleware\// },
73
- ],
74
- },
75
- };
76
26
 
77
27
  // ──── Default requirement ID patterns ────
78
28
  // Users can override via config.traceability.requirementPattern
@@ -89,7 +39,12 @@ const DEFAULT_REQ_PATTERNS = [
89
39
  /\b(ARCH)-(\d{2,4})\b/g,
90
40
  /\b(MOD)-(\d{2,4})\b/g,
91
41
  /\b(SC)-(\d{2,4})\b/g, // Spec Kit: Success Criteria
92
- /\b(T)(\d{3,4})\b/g, // Spec Kit: Task IDs (T001, T002)
42
+ // Spec Kit task IDs (T001, T002). Unlike the hyphenated IDs above, a bare
43
+ // `T350` over-matches prose (timeouts, model names, status codes), forcing
44
+ // spurious "untraced requirement" warnings. Anchor to the two contexts where
45
+ // a real task ID actually appears: a markdown checklist marker (`- [ ] T001`,
46
+ // the spec-kit tasks.md format) or a test annotation (`@req T001`/`@task`).
47
+ /(?<=\[[ xX]\]\s|@(?:req|task|covers)\s)(T)(\d{3,4})\b/g,
93
48
  ];
94
49
 
95
50
  /**
@@ -152,9 +107,12 @@ export function validateTraceability(projectDir, config) {
152
107
 
153
108
  // Count matching source files
154
109
  // ⚡ Bolt: Fast early return using .some() instead of .filter()
110
+ // v0.24: skip .md files — a doc isn't "linked" just because another doc's
111
+ // name matches the glob (e.g. SECURITY's `guard` matching docguard.guard.md);
112
+ // that masked genuinely unlinked docs (field report).
155
113
  let hasSource = false;
156
114
  for (const pattern of traceInfo.sourcePatterns) {
157
- if (projectFiles.some(f => pattern.glob.test(f))) {
115
+ if (projectFiles.some(f => isTraceableSource(f) && pattern.glob.test(f))) {
158
116
  hasSource = true;
159
117
  break;
160
118
  }
@@ -285,7 +243,7 @@ function collectRequirementIds(projectDir, config, patterns) {
285
243
 
286
244
  function scanTestFilesForReferences(projectDir, projectFiles, patterns) {
287
245
  const testFiles = projectFiles.filter(f =>
288
- /\.(test|spec)\.(mjs|cjs|[jt]sx?)$/.test(f) ||
246
+ TEST_PATTERNS.some(p => p.test(f)) || // multilingual: JS/TS, Python, Go, Rust, Java/Kotlin, Ruby, PHP
289
247
  /__tests__\//.test(f) ||
290
248
  /tests?\//.test(f)
291
249
  );
@@ -36,8 +36,20 @@ function parseAttrs(attrStr) {
36
36
 
37
37
  /**
38
38
  * Parse all well-formed sections in a document.
39
- * A section is a line matching the open marker, then content lines, then a
40
- * close-marker line. An open with no matching close is ignored (not corrupted).
39
+ * A section is an open-marker line, then content lines, then a close-marker
40
+ * line. Sections are FLAT there is no nesting.
41
+ *
42
+ * Two malformed cases are handled so that a hand-edit mistake can never cause
43
+ * a later regenerate to overwrite human prose:
44
+ * - An open with no matching close (reached EOF) is dropped, not returned.
45
+ * - A NEW open encountered while a previous one is still unclosed means the
46
+ * previous open was malformed (its close was deleted or typo'd). We ABANDON
47
+ * the previous open and restart at the new one. The earlier, broken
48
+ * approach kept the first open and paired it with the *next* section's
49
+ * close — swallowing the human prose and the next section into one body,
50
+ * which a subsequent replaceSection() would then silently overwrite.
51
+ * A dropped section simply isn't returned, so replaceSection() no-ops on it
52
+ * (returns content unchanged) instead of corrupting the surrounding document.
41
53
  * @returns {Array<{ id, source, attrs, openLine, closeLine, body }>}
42
54
  */
43
55
  export function parseSections(content) {
@@ -47,25 +59,26 @@ export function parseSections(content) {
47
59
 
48
60
  for (let i = 0; i < lines.length; i++) {
49
61
  const line = lines[i];
50
- if (open === null) {
51
- const om = line.match(OPEN_RE);
52
- if (om) {
53
- const attrs = parseAttrs(om[1] || '');
54
- open = { attrs, openLine: i };
62
+ if (CLOSE_RE.test(line)) {
63
+ if (open !== null) {
64
+ sections.push({
65
+ id: open.attrs.id || '',
66
+ source: open.attrs.source || 'code',
67
+ attrs: open.attrs,
68
+ openLine: open.openLine,
69
+ closeLine: i,
70
+ body: lines.slice(open.openLine + 1, i).join('\n'),
71
+ });
72
+ open = null;
55
73
  }
56
- } else if (CLOSE_RE.test(line)) {
57
- sections.push({
58
- id: open.attrs.id || '',
59
- source: open.attrs.source || 'code',
60
- attrs: open.attrs,
61
- openLine: open.openLine,
62
- closeLine: i,
63
- body: lines.slice(open.openLine + 1, i).join('\n'),
64
- });
65
- open = null;
74
+ // A close with no matching open is ignored.
75
+ continue;
76
+ }
77
+ const om = line.match(OPEN_RE);
78
+ if (om) {
79
+ // Abandon any still-open (malformed) section; start fresh here.
80
+ open = { attrs: parseAttrs(om[1] || ''), openLine: i };
66
81
  }
67
- // Note: a second open before a close just extends the search for a close;
68
- // we keep the FIRST open's start, so malformed nesting can't corrupt content.
69
82
  }
70
83
  return sections;
71
84
  }
package/docs/commands.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Commands Reference
2
2
 
3
- DocGuard v0.5.013 commands, zero dependencies.
3
+ DocGuard CLIone pinned runtime dependency (`@babel/parser`, optional-load); Node.js 18+. See `package.json` for the current version.
4
4
 
5
5
  ## The AI Loop
6
6
 
@@ -73,6 +73,17 @@ See [Profiles](./profiles.md) for details.
73
73
  | `environment` | `true` | Setup steps, env vars, prerequisites, .env.example |
74
74
  | `freshness` | varies | Docs updated recently relative to code changes (git-based) |
75
75
 
76
+ ## Muting a validator
77
+
78
+ Two ways to turn a validator off, for two different intents:
79
+
80
+ | Intent | How | Renders as |
81
+ |--------|-----|-----------|
82
+ | Operational toggle (CI speed, not relevant *right now*) | `.docguard.json` → `"validators": { "testSpec": false }` | silent — disabled |
83
+ | **Intentional non-applicability** (POC with no tests, library with no auth) | inline marker in a canonical doc or `AGENTS.md`:<br>`<!-- docguard:validator testSpec n/a — POC, no automated tests yet -->` | `➖ Test-Spec [N/A] (declared N/A: …)` — visible, git-tracked |
84
+
85
+ The marker is preferred when the validator genuinely does not apply: the rationale lives next to the declaration, travels with the repo, and shows up honestly as N/A rather than a hidden skip or a fake green check. The key is the validator key from the table above (case/separator tolerant — `test-spec` works too); a mistyped key is reported as a warning rather than silently ignored. A no-tests POC typically marks both `testSpec` and `traceability` N/A.
86
+
76
87
  ## Project Type Detection
77
88
 
78
89
  DocGuard auto-detects your project type from `package.json`:
package/docs/faq.md CHANGED
@@ -129,7 +129,7 @@ Only if you install hooks (`docguard hooks`). Without hooks, it's advisory only.
129
129
 
130
130
  ### Does DocGuard have dependencies?
131
131
 
132
- **Zero.** Pure Node.js, no npm dependencies. Works with Node.js 18+.
132
+ **One.** `@babel/parser` (exact-pinned), for AST-accurate JS/TS parsing — and it's loaded *optionally*, so DocGuard still runs (on the regex fallback tier) if it's ever missing. Everything else is pure Node.js built-ins. Works with Node.js 18+. Python parsing optionally shells out to the project's own `python3`.
133
133
 
134
134
  ### Does it work with non-JavaScript projects?
135
135
 
@@ -12,7 +12,7 @@ Enterprise-grade Canonical-Driven Development (CDD) enforcement and **AI-readabl
12
12
  - **5 AI Skills** — docguard-fix, docguard-guard, docguard-sync, docguard-review, docguard-score (enterprise-grade behavior protocols, not just step-lists)
13
13
  - **Workflow Chaining** — YAML handoffs enable guard → sync → fix → review → score flows
14
14
  - **Spec Kit Hooks** — Quality gate integrations at implement, tasks, and review phases
15
- - **Zero Dependencies** — Pure Node.js built-ins only
15
+ - **Minimal Dependencies** — one pinned, optional-load parser (`@babel/parser`); Node.js built-ins otherwise
16
16
 
17
17
  ## Installation
18
18
 
@@ -3,8 +3,8 @@ schema_version: "1.0"
3
3
  extension:
4
4
  id: "docguard"
5
5
  name: "DocGuard — CDD Enforcement"
6
- version: "0.22.1"
7
- description: "Canonical-Driven Development enforcement as a true spec-kit extension. LLM-first design with 19 automated validators, 4 AI behavior skills, spec-kit skill chaining, and workflow hooks. Zero NPM runtime dependencies."
6
+ version: "0.24.0"
7
+ description: "Canonical-Driven Development enforcement as a true spec-kit extension. LLM-first design with automated validators, 4 AI behavior skills, spec-kit skill chaining, and workflow hooks. One pinned runtime dependency (@babel/parser); pure Node.js otherwise."
8
8
  author: "Ricardo Accioly"
9
9
  repository: "https://github.com/raccioly/docguard"
10
10
  license: "MIT"
@@ -6,10 +6,10 @@ description: AI-driven documentation repair with structured research workflow, t
6
6
  compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
7
7
  metadata:
8
8
  author: docguard
9
- version: 0.22.1
9
+ version: 0.24.0
10
10
  source: extensions/spec-kit-docguard/skills/docguard-fix
11
11
  ---
12
- <!-- docguard:version: 0.22.1 -->
12
+ <!-- docguard:version: 0.24.0 -->
13
13
 
14
14
  # DocGuard Fix Skill
15
15
 
@@ -7,10 +7,10 @@ description: Run DocGuard guard validation against Canonical-Driven Development
7
7
  compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
8
8
  metadata:
9
9
  author: docguard
10
- version: 0.22.1
10
+ version: 0.24.0
11
11
  source: extensions/spec-kit-docguard/skills/docguard-guard
12
12
  ---
13
- <!-- docguard:version: 0.22.1 -->
13
+ <!-- docguard:version: 0.24.0 -->
14
14
 
15
15
  # DocGuard Guard Skill
16
16
 
@@ -6,10 +6,10 @@ description: Cross-document consistency analysis and quality assessment. Perform
6
6
  compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
7
7
  metadata:
8
8
  author: docguard
9
- version: 0.22.1
9
+ version: 0.24.0
10
10
  source: extensions/spec-kit-docguard/skills/docguard-review
11
11
  ---
12
- <!-- docguard:version: 0.22.1 -->
12
+ <!-- docguard:version: 0.24.0 -->
13
13
 
14
14
  # DocGuard Review Skill
15
15
 
@@ -6,10 +6,10 @@ description: CDD maturity assessment with category-aware improvement roadmap. Ru
6
6
  compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
7
7
  metadata:
8
8
  author: docguard
9
- version: 0.22.1
9
+ version: 0.24.0
10
10
  source: extensions/spec-kit-docguard/skills/docguard-score
11
11
  ---
12
- <!-- docguard:version: 0.22.1 -->
12
+ <!-- docguard:version: 0.24.0 -->
13
13
 
14
14
  # DocGuard Score Skill
15
15
 
@@ -4,9 +4,10 @@ description: Keep canonical documentation ALWAYS UP TO DATE. Refreshes code-trut
4
4
  compatibility: Requires DocGuard CLI installed (npm i -g docguard-cli or npx docguard-cli)
5
5
  metadata:
6
6
  author: docguard
7
- version: 0.22.1
7
+ version: 0.24.0
8
8
  source: extensions/spec-kit-docguard/skills/docguard-sync
9
9
  ---
10
+ <!-- docguard:version: 0.24.0 -->
10
11
 
11
12
  # DocGuard Sync Skill
12
13
 
@@ -13,7 +13,8 @@
13
13
  # Setup:
14
14
  # 1. Copy this file to .github/workflows/docguard-autofix.yml
15
15
  # 2. Ensure the workflow has the permissions block below (write access).
16
- # 3. (Optional) Pin to a specific DocGuard version by changing `@main` to a tag.
16
+ # 3. Pinned to the `@v0.24.0` release tag for reproducible CI. Change it to a
17
+ # newer tag to upgrade, or to `@main` to always track the latest (unpinned).
17
18
  #
18
19
  # Security note: this workflow makes commits back to the PR branch. It refuses
19
20
  # to run on PRs from forks (where pushing back is impossible by design).
@@ -43,7 +44,7 @@ jobs:
43
44
  fetch-depth: 0
44
45
 
45
46
  - name: Run DocGuard fix --write + auto-commit + PR comment
46
- uses: raccioly/docguard@main
47
+ uses: raccioly/docguard@v0.24.0
47
48
  with:
48
49
  command: fix
49
50
  auto-commit: 'true'
@@ -28,7 +28,7 @@ jobs:
28
28
  fetch-depth: 0
29
29
 
30
30
  - name: Run all validators
31
- uses: raccioly/docguard@main
31
+ uses: raccioly/docguard@v0.24.0
32
32
  with:
33
33
  command: guard
34
34
  # Flip to 'true' once your repo is clean — turns warnings into hard failures.
@@ -42,7 +42,7 @@ jobs:
42
42
  - uses: actions/checkout@v4
43
43
 
44
44
  - name: Score & comment
45
- uses: raccioly/docguard@main
45
+ uses: raccioly/docguard@v0.24.0
46
46
  with:
47
47
  command: score
48
48
  format: json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docguard-cli",
3
- "version": "0.22.1",
3
+ "version": "0.24.0",
4
4
  "description": "The enforcement tool for Canonical-Driven Development (CDD). Audit, generate, and guard your project documentation.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,6 +45,9 @@
45
45
  "engines": {
46
46
  "node": ">=18.0.0"
47
47
  },
48
+ "dependencies": {
49
+ "@babel/parser": "7.29.7"
50
+ },
48
51
  "files": [
49
52
  "cli/",
50
53
  "templates/",
@@ -56,6 +59,5 @@
56
59
  "PHILOSOPHY.md",
57
60
  "README.md",
58
61
  "LICENSE"
59
- ],
60
- "dependencies": {}
62
+ ]
61
63
  }