docsgov 0.1.0 → 0.1.1

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 (41) hide show
  1. package/README.md +46 -24
  2. package/dist/apispec/apispec.js +1 -1
  3. package/dist/apispec/apispec.test.js +2 -2
  4. package/dist/check/run.js +1 -1
  5. package/dist/check/run.test.js +6 -6
  6. package/dist/check/suggest.js +1 -1
  7. package/dist/check/tokens.js +1 -1
  8. package/dist/cmd/main.js +17 -17
  9. package/dist/cmd/main.test.js +13 -13
  10. package/dist/codeq/errors.js +2 -2
  11. package/dist/codeq/index.js +1 -1
  12. package/dist/codeq/resolver.test.js +1 -1
  13. package/dist/config/config.js +2 -2
  14. package/dist/config/config.test.js +5 -5
  15. package/dist/config/fs.js +1 -1
  16. package/dist/config/glob.js +1 -1
  17. package/dist/config/glob.test.js +1 -1
  18. package/dist/dedup/configload.js +3 -3
  19. package/dist/dedup/configload.test.js +5 -5
  20. package/dist/dedup/dedup.index.test.js +9 -9
  21. package/dist/dedup/dedup.js +5 -5
  22. package/dist/dedup/dedup.test.js +4 -4
  23. package/dist/dedup/dedupcfg/config.js +2 -2
  24. package/dist/dedup/embedder/cache.js +4 -4
  25. package/dist/dedup/embedder/cache.test.js +13 -13
  26. package/dist/dedup/embedder/embedder.js +2 -2
  27. package/dist/dedup/embedder/embedder.mock.test.js +1 -1
  28. package/dist/dedup/embedder/embedder.test.js +4 -4
  29. package/dist/dedup/embedder/session.test.js +1 -1
  30. package/dist/dedup/gitignore.js +5 -5
  31. package/dist/dedup/gitignore.test.js +2 -2
  32. package/dist/dedup/indexdb/indexdb.js +2 -2
  33. package/dist/repo/exists.test.js +7 -7
  34. package/dist/repo/index.js +1 -1
  35. package/dist/repo/overlay.test.js +6 -6
  36. package/dist/repo/repo.js +10 -10
  37. package/dist/repo/repo.test.js +35 -35
  38. package/dist/repo/testutil.js +1 -1
  39. package/dist/repo/write.test.js +12 -12
  40. package/dist/violation/types.js +1 -1
  41. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # docgov
1
+ # docsgov
2
2
 
3
- Config-driven **documentation governance**. `docgov` checks that the
3
+ Config-driven **documentation governance**. `docsgov` checks that the
4
4
  references inside your Markdown docs still point at things that actually exist —
5
5
  so docs rot loudly (a failing check) instead of silently.
6
6
 
@@ -22,19 +22,19 @@ The package source lives at the repository root (a TypeScript/Node project).
22
22
  ## Install
23
23
 
24
24
  ```bash
25
- npm install -g docgov
26
- docgov --version
25
+ npm install -g docsgov # the npm package is "docsgov"
26
+ docsgov --version # the command it installs is "docsgov"
27
27
  ```
28
28
 
29
29
  Or run it without installing:
30
30
 
31
31
  ```bash
32
- npx docgov check
32
+ npx docsgov check
33
33
  ```
34
34
 
35
35
  **Requirements**
36
36
 
37
- - **Node.js >= 22.** docgov uses the built-in `node:sqlite` module (for the
37
+ - **Node.js >= 22.** docsgov uses the built-in `node:sqlite` module (for the
38
38
  `dedup` index), which requires Node 22 or newer.
39
39
  - **No system libraries needed.** The tree-sitter grammars ship as bundled
40
40
  WebAssembly, and the `dedup` embedder runs through `@huggingface/transformers`
@@ -44,10 +44,32 @@ npx docgov check
44
44
 
45
45
  ---
46
46
 
47
+ ### Skills
48
+
49
+ Add the marketplace:
50
+ ```bash
51
+ claude plugin marketplace add
52
+ ```
53
+
54
+ Marketplace name is `docsgov-skills` (from marketplace.json). Use `@docsgov-skills` when installing plugins.
55
+ In Claude Code, use `/plugin ...` slash commands. In your terminal, use `claude plugin ...`.
56
+
57
+ **Init Skill** (recommended to setup for new repo):
58
+ ```bash
59
+ claude plugin install docsgov-init@docsgov-skills
60
+ ```
61
+
62
+ **Operations Suite** (the guide for agent to handle docsgov error codes):
63
+ ```bash
64
+ claude plugin install docsgov@docsgov-skills
65
+ ```
66
+
67
+ ---
68
+
47
69
  ## Quick start
48
70
 
49
71
  1. Mark the repo root and declare what to govern by creating
50
- **`.docgov/docgov.yaml`**:
72
+ **`.docsgov/docsgov.yaml`**:
51
73
 
52
74
  ```yaml
53
75
  code:
@@ -60,7 +82,7 @@ npx docgov check
60
82
  2. Run the check from anywhere inside the repo:
61
83
 
62
84
  ```bash
63
- docgov check
85
+ docsgov check
64
86
  ```
65
87
 
66
88
  Exit `0` = clean, `1` = violations found, `2` = config/usage error.
@@ -69,25 +91,25 @@ npx docgov check
69
91
 
70
92
  ## Commands
71
93
 
72
- ### `docgov check [--format text|json]`
94
+ ### `docsgov check [--format text|json]`
73
95
 
74
96
  Runs the code, doc, and api guards over their configured scopes and reports
75
97
  every violation. `--format json` emits machine-readable output for CI;
76
98
  `--format text` (the default) is styled for the terminal.
77
99
 
78
- ### `docgov dedup`
100
+ ### `docsgov dedup`
79
101
 
80
102
  Refreshes the embedding index for `docs/` and reports near-duplicate concepts.
81
103
  Exits `1` if a high-confidence duplicate group is found.
82
104
 
83
- ### `docgov update [--version vX.Y.Z] [--check]`
105
+ ### `docsgov update [--version vX.Y.Z] [--check]`
84
106
 
85
- docgov is distributed via npm, so `update` does not self-replace the binary.
107
+ docsgov is distributed via npm, so `update` does not self-replace the binary.
86
108
 
87
- - `docgov update --check` reports the current version and the latest version
109
+ - `docsgov update --check` reports the current version and the latest version
88
110
  from the npm registry (best-effort; degrades gracefully when offline).
89
- - `docgov update` (or with `--version vX.Y.Z`) prints the install command to run,
90
- e.g. `npm install -g docgov@latest`.
111
+ - `docsgov update` (or with `--version vX.Y.Z`) prints the install command to run,
112
+ e.g. `npm install -g docsgov@latest`.
91
113
 
92
114
  ### Exit codes
93
115
 
@@ -95,7 +117,7 @@ docgov is distributed via npm, so `update` does not self-replace the binary.
95
117
  | --- | --- |
96
118
  | `0` | success — no violations |
97
119
  | `1` | `check` found violations (or `dedup` found duplicates) |
98
- | `2` | usage or configuration error (e.g. no `.docgov/` found, bad `--format`) |
120
+ | `2` | usage or configuration error (e.g. no `.docsgov/` found, bad `--format`) |
99
121
 
100
122
  These are stable, so CI can gate on them directly.
101
123
 
@@ -103,8 +125,8 @@ These are stable, so CI can gate on them directly.
103
125
 
104
126
  ## Configuration
105
127
 
106
- docgov reads a **single** file: `.docgov/docgov.yaml`. The `.docgov/` directory
107
- is also the **repo-root marker** — docgov walks up from the working directory
128
+ docsgov reads a **single** file: `.docsgov/docsgov.yaml`. The `.docsgov/` directory
129
+ is also the **repo-root marker** — docsgov walks up from the working directory
108
130
  until it finds one. A missing file makes `check` exit `2`.
109
131
 
110
132
  The file has three optional top-level sections. Each has a `boundary` (which
@@ -181,12 +203,12 @@ the repo root are rejected.
181
203
  ## Folder structure
182
204
 
183
205
  A governed repository looks like this — the only required piece is
184
- `.docgov/docgov.yaml`; the `docs/` layout is yours to choose:
206
+ `.docsgov/docsgov.yaml`; the `docs/` layout is yours to choose:
185
207
 
186
208
  ```
187
209
  your-repo/
188
- ├── .docgov/
189
- │ └── docgov.yaml # the single config file + repo-root marker
210
+ ├── .docsgov/
211
+ │ └── docsgov.yaml # the single config file + repo-root marker
190
212
  ├── docs/ # whatever structure you like
191
213
  │ ├── README.md
192
214
  │ ├── config.md
@@ -195,7 +217,7 @@ your-repo/
195
217
  └── cmd/
196
218
  ```
197
219
 
198
- This repository governs **its own** `docs/` with docgov; see
220
+ This repository governs **its own** `docs/` with docsgov; see
199
221
  [`docs/README.md`](docs/README.md) for that layout as a worked example.
200
222
 
201
223
  ---
@@ -208,8 +230,8 @@ This repository governs **its own** `docs/` with docgov; see
208
230
  docs-governance:
209
231
  image: node:22
210
232
  script:
211
- - npm install -g docgov
212
- - docgov check # exits 1 on violations → job fails
233
+ - npm install -g docsgov
234
+ - docsgov check # exits 1 on violations → job fails
213
235
  ```
214
236
 
215
237
  ---
@@ -19,7 +19,7 @@ function asString(v) {
19
19
  return typeof v === "string" ? v : "";
20
20
  }
21
21
  /**
22
- * Spec is a loaded, self-contained OpenAPI v3.1 document. Only the parts docgov
22
+ * Spec is a loaded, self-contained OpenAPI v3.1 document. Only the parts docsgov
23
23
  * needs are typed; schema bodies stay as generic nodes for recursive walking.
24
24
  */
25
25
  export class Spec {
@@ -400,7 +400,7 @@ describe("load/parse error semantics", () => {
400
400
  // I/O and parse failures are exceptional (thrown sentinels), unlike domain
401
401
  // results which are returned data.
402
402
  test("missing file throws SpecNotFoundError", async () => {
403
- await expect(load(join(tmpdir(), "docgov-apispec-does-not-exist.json"))).rejects.toBeInstanceOf(SpecNotFoundError);
403
+ await expect(load(join(tmpdir(), "docsgov-apispec-does-not-exist.json"))).rejects.toBeInstanceOf(SpecNotFoundError);
404
404
  });
405
405
  test("malformed syntax throws SpecParseError", () => {
406
406
  expect(() => parse("{not json", "x.json")).toThrow(SpecParseError);
@@ -413,7 +413,7 @@ describe("load/parse error semantics", () => {
413
413
  describe("load: reads YAML and JSON from disk", () => {
414
414
  let dir;
415
415
  beforeAll(async () => {
416
- dir = await mkdtemp(join(tmpdir(), "docgov-apispec-"));
416
+ dir = await mkdtemp(join(tmpdir(), "docsgov-apispec-"));
417
417
  });
418
418
  afterAll(async () => {
419
419
  await rm(dir, { recursive: true, force: true });
package/dist/check/run.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Port of internal/check/run.go — the three-pass Run pipeline (Stage 5 of
2
- // minimize-docgov) and the {{api:…}} qualifier dispatch from apitokens' caller.
2
+ // minimize-docsgov) and the {{api:…}} qualifier dispatch from apitokens' caller.
3
3
  //
4
4
  // run() runs three independent passes (code, doc, api) over the scopes declared
5
5
  // in cfg. Only present (non-undefined) sections are executed. Violations are
@@ -59,13 +59,13 @@ afterEach(async () => {
59
59
  });
60
60
  /**
61
61
  * tempRepo creates a temp dir, writes the given files (map path→content), and
62
- * creates a .docgov/ sentinel dir so find() anchors there. Mirrors the Go
62
+ * creates a .docsgov/ sentinel dir so find() anchors there. Mirrors the Go
63
63
  * tempRepo helper.
64
64
  */
65
65
  async function tempRepo(files) {
66
- const root = await nodefs.realpath(await nodefs.mkdtemp(path.join(os.tmpdir(), "docgov-check-")));
66
+ const root = await nodefs.realpath(await nodefs.mkdtemp(path.join(os.tmpdir(), "docsgov-check-")));
67
67
  createdRoots.push(root);
68
- await nodefs.mkdir(path.join(root, ".docgov"), { recursive: true });
68
+ await nodefs.mkdir(path.join(root, ".docsgov"), { recursive: true });
69
69
  for (const [rel, content] of Object.entries(files)) {
70
70
  const abs = path.join(root, ...rel.split("/"));
71
71
  await nodefs.mkdir(path.dirname(abs), { recursive: true });
@@ -429,10 +429,10 @@ describe("run / api pass", () => {
429
429
  // --- E2E + ORDERING ---
430
430
  describe("run / e2e", () => {
431
431
  // A clean tree configured with all three guards must produce zero violations
432
- // when loaded from a real docgov.yaml — the end-to-end happy path.
432
+ // when loaded from a real docsgov.yaml — the end-to-end happy path.
433
433
  it("returns no violations for a clean tree across all three guards", async () => {
434
434
  const r = await tempRepo({
435
- ".docgov/docgov.yaml": `
435
+ ".docsgov/docsgov.yaml": `
436
436
  code:
437
437
  boundary: [docs/**]
438
438
  source: [src/**]
@@ -455,7 +455,7 @@ api:
455
455
  // passes run independently and collect together.
456
456
  it("returns one violation per guard for a drifted tree", async () => {
457
457
  const r = await tempRepo({
458
- ".docgov/docgov.yaml": `
458
+ ".docsgov/docsgov.yaml": `
459
459
  code:
460
460
  boundary: [docs/**]
461
461
  source: [src/**]
@@ -105,7 +105,7 @@ function rankCandidates(target, candidates) {
105
105
  }
106
106
  /**
107
107
  * levenshtein is the standard two-row edit-distance DP (insert/delete/substitute,
108
- * cost 1 each). Case-sensitive, since the languages docgov resolves treat
108
+ * cost 1 each). Case-sensitive, since the languages docsgov resolves treat
109
109
  * identifiers as case-sensitive.
110
110
  */
111
111
  function levenshtein(a, b) {
@@ -13,7 +13,7 @@
13
13
  // The Go original walks the goldmark AST and uses byte offsets; this port walks
14
14
  // the mdast tree (remark-parse + remark-gfm) and uses string character offsets.
15
15
  // Everything operates on the same decoded string, so offsets are internally
16
- // consistent (and identical to bytes for the ASCII token bodies docgov scans).
16
+ // consistent (and identical to bytes for the ASCII token bodies docsgov scans).
17
17
  import { parseMarkdown } from "../dedup/mdsection/index.js";
18
18
  /**
19
19
  * codeTokenRE matches a {{code:…}} token anywhere in a text span. It does not
package/dist/cmd/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env -S node --disable-warning=ExperimentalWarning
2
- // Command docgov is the CLI entrypoint for the docgov documentation-governance
3
- // engine. Port of cmd/docgov/{main,dedup_on,dedup_off,update}.go.
2
+ // Command docsgov is the CLI entrypoint for the docsgov documentation-governance
3
+ // engine. Port of cmd/docsgov/{main,dedup_on,dedup_off,update}.go.
4
4
  //
5
5
  // PORTING NOTES (deviations recorded prominently):
6
6
  //
@@ -24,7 +24,7 @@
24
24
  // is an npm-appropriate command:
25
25
  // - `update --check` reports the current version and the latest version
26
26
  // from the npm registry (best-effort; handles offline gracefully);
27
- // - plain `update` prints guidance to run `npm install -g docgov@latest`.
27
+ // - plain `update` prints guidance to run `npm install -g docsgov@latest`.
28
28
  // The `--version <tag>` flag is kept for compatibility (it is reported back
29
29
  // in the install guidance). The asset-name mapping and replaceExecutable
30
30
  // logic from update.go have no npm analogue and are omitted.
@@ -35,7 +35,7 @@
35
35
  // userland process.emitWarning wrapper cannot suppress it — the builtin is
36
36
  // initialized at module-link time, before any of our code runs. The shebang
37
37
  // therefore launches node with `--disable-warning=ExperimentalWarning`
38
- // (env -S splits the args) so the installed `docgov` runs clean. Requires
38
+ // (env -S splits the args) so the installed `docsgov` runs clean. Requires
39
39
  // Node >=22 (engines) where the flag exists.
40
40
  import { fileURLToPath } from "node:url";
41
41
  import { readFileSync, realpathSync } from "node:fs";
@@ -137,7 +137,7 @@ async function runCheckAction(format) {
137
137
  throw new ViolationsError();
138
138
  }
139
139
  }
140
- // runDedupAction implements "docgov dedup": find repo root → refresh the
140
+ // runDedupAction implements "docsgov dedup": find repo root → refresh the
141
141
  // embedding index → analyze → render the report. The index is rebuilt
142
142
  // automatically on every run, so there is no separate index step. Index
143
143
  // progress goes to stderr; the report goes to stdout. Throws DuplicatesError
@@ -178,17 +178,17 @@ async function runUpdateAction(opts) {
178
178
  return;
179
179
  }
180
180
  const target = opts.version !== undefined && opts.version !== ""
181
- ? `docgov@${opts.version}`
182
- : "docgov@latest";
181
+ ? `docsgov@${opts.version}`
182
+ : "docsgov@latest";
183
183
  process.stdout.write(`current: ${current}\n`);
184
- process.stdout.write(`docgov is installed via npm; update it with:\n npm install -g ${target}\n`);
184
+ process.stdout.write(`docsgov is installed via npm; update it with:\n npm install -g ${target}\n`);
185
185
  }
186
186
  // fetchLatestVersion queries the npm registry for the latest published version.
187
187
  // Best-effort: returns null on any network/parse failure (offline-safe) so the
188
188
  // update command degrades gracefully rather than erroring out.
189
189
  async function fetchLatestVersion() {
190
190
  try {
191
- const resp = await fetch("https://registry.npmjs.org/docgov/latest");
191
+ const resp = await fetch("https://registry.npmjs.org/docsgov/latest");
192
192
  if (!resp.ok) {
193
193
  return null;
194
194
  }
@@ -204,7 +204,7 @@ async function fetchLatestVersion() {
204
204
  export function newApp(version) {
205
205
  const app = new Command();
206
206
  app
207
- .name("docgov")
207
+ .name("docsgov")
208
208
  .usage("[command]")
209
209
  .description("config-driven documentation governance")
210
210
  .version(version)
@@ -212,7 +212,7 @@ export function newApp(version) {
212
212
  // process.exit, so run() is the single owner of the exit-code convention.
213
213
  .exitOverride()
214
214
  // Suppress commander's own "(see --help)" suggestion noise on errors; run()
215
- // reports usage errors via stderr "docgov: ...".
215
+ // reports usage errors via stderr "docsgov: ...".
216
216
  .showSuggestionAfterError(false);
217
217
  app
218
218
  .command("check")
@@ -223,7 +223,7 @@ export function newApp(version) {
223
223
  });
224
224
  app
225
225
  .command("update")
226
- .description("report the latest docgov release (install via npm)")
226
+ .description("report the latest docsgov release (install via npm)")
227
227
  .option("--version <tag>", "report guidance for a specific tag (e.g. v1.2.3)")
228
228
  .option("--check", "report current and latest versions without installing", false)
229
229
  .action(async (opts) => {
@@ -271,7 +271,7 @@ export async function run(argv) {
271
271
  return exitUsage;
272
272
  }
273
273
  // Engine/config/operational error → exit 2 with the Go-style prefix.
274
- process.stderr.write(`docgov: ${errMsg(err)}\n`);
274
+ process.stderr.write(`docsgov: ${errMsg(err)}\n`);
275
275
  return exitUsage;
276
276
  }
277
277
  }
@@ -287,7 +287,7 @@ async function main() {
287
287
  // Flush stdout/stderr before exiting. When stdout is a pipe or file (not a
288
288
  // TTY), Node buffers writes asynchronously; calling process.exit() directly
289
289
  // would terminate before the buffer drains and silently truncate the report
290
- // (a piped/redirected `docgov check` would print nothing). Draining both
290
+ // (a piped/redirected `docsgov check` would print nothing). Draining both
291
291
  // streams first guarantees the output is delivered; process.exit then forces
292
292
  // termination so lingering tree-sitter/onnx handles cannot keep the process
293
293
  // alive (Go used os.Exit for the same immediacy).
@@ -306,10 +306,10 @@ function drainStream(stream) {
306
306
  // import.meta.url !== the entry file URL, so main() is not called.
307
307
  //
308
308
  // The entry (process.argv[1]) must be resolved through realpathSync before
309
- // comparing: an npm-installed bin is reached via symlinks (bin/docgov
310
- // lib/node_modules/docgov → this file), so path.resolve alone leaves it as the
309
+ // comparing: an npm-installed bin is reached via symlinks (bin/docsgov
310
+ // lib/node_modules/docsgov → this file), so path.resolve alone leaves it as the
311
311
  // symlink path and the comparison fails — which would make main() silently never
312
- // run when invoked as `docgov`. import.meta.url is already a realpath (Node
312
+ // run when invoked as `docsgov`. import.meta.url is already a realpath (Node
313
313
  // resolves module specifiers through realpath), so we realpath the entry to match.
314
314
  const invokedDirectly = (() => {
315
315
  const entry = process.argv[1];
@@ -1,19 +1,19 @@
1
1
  // Tests the CLI wire-up: exit-code mapping, command routing, --format flag, the
2
2
  // check e2e loop, dedup command registration, and the npm-appropriate update
3
- // command. Port of cmd/docgov/{main,dedup_cli,update}_test.go, adapted to the
3
+ // command. Port of cmd/docsgov/{main,dedup_cli,update}_test.go, adapted to the
4
4
  // commander framework and npm distribution.
5
5
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
6
6
  import { tmpdir } from "node:os";
7
7
  import * as path from "node:path";
8
8
  import { afterEach, describe, expect, it, vi } from "vitest";
9
9
  import { run, newApp, readVersion, ViolationsError, DuplicatesError, exitOK, exitViolation, exitUsage, } from "./main.js";
10
- // makeNewSchemaRepo builds a minimal temp repo with a .docgov/docgov.yaml and
10
+ // makeNewSchemaRepo builds a minimal temp repo with a .docsgov/docsgov.yaml and
11
11
  // the provided docs files (relPath→content). Returns the temp dir path. Mirrors
12
12
  // the Go makeNewSchemaRepo helper.
13
- function makeNewSchemaRepo(docgovYAML, docs) {
14
- const tmp = mkdtempSync(path.join(tmpdir(), "docgov-cmd-"));
15
- mkdirSync(path.join(tmp, ".docgov"), { recursive: true });
16
- writeFileSync(path.join(tmp, ".docgov", "docgov.yaml"), docgovYAML);
13
+ function makeNewSchemaRepo(docsgovYAML, docs) {
14
+ const tmp = mkdtempSync(path.join(tmpdir(), "docsgov-cmd-"));
15
+ mkdirSync(path.join(tmp, ".docsgov"), { recursive: true });
16
+ writeFileSync(path.join(tmp, ".docsgov", "docsgov.yaml"), docsgovYAML);
17
17
  for (const [relPath, content] of Object.entries(docs)) {
18
18
  const abs = path.join(tmp, ...relPath.split("/"));
19
19
  mkdirSync(path.dirname(abs), { recursive: true });
@@ -142,11 +142,11 @@ describe("check command", () => {
142
142
  }));
143
143
  expect(code).toBe(exitViolation);
144
144
  });
145
- // Missing .docgov/docgov.yaml is a usage/config error → exit 2. Mirrors Go's
145
+ // Missing .docsgov/docsgov.yaml is a usage/config error → exit 2. Mirrors Go's
146
146
  // TestCheckNewSchema_MissingConfigExitsTwo.
147
- it("missing docgov.yaml exits 2", async () => {
148
- const tmp = mkdtempSync(path.join(tmpdir(), "docgov-cmd-"));
149
- mkdirSync(path.join(tmp, ".docgov"), { recursive: true });
147
+ it("missing docsgov.yaml exits 2", async () => {
148
+ const tmp = mkdtempSync(path.join(tmpdir(), "docsgov-cmd-"));
149
+ mkdirSync(path.join(tmp, ".docsgov"), { recursive: true });
150
150
  const restore = silenceStderr();
151
151
  const code = await withCwd(tmp, () => run(["check"]));
152
152
  restore();
@@ -305,7 +305,7 @@ describe("update command (npm)", () => {
305
305
  code = await run(["update"]);
306
306
  });
307
307
  expect(code).toBe(exitOK);
308
- expect(out).toContain("npm install -g docgov@latest");
308
+ expect(out).toContain("npm install -g docsgov@latest");
309
309
  });
310
310
  // `update --version <tag>` is shadowed by commander's program-level --version
311
311
  // flag (added by .version()), which prints the program version and exits 0
@@ -392,14 +392,14 @@ describe("update command (npm)", () => {
392
392
  });
393
393
  describe("dedup command", () => {
394
394
  // The dedup action runs Index (which loads the dedup config) before anything
395
- // else. A malformed .docgov/dedup/config.yml makes Load throw, which must map
395
+ // else. A malformed .docsgov/dedup/config.yml makes Load throw, which must map
396
396
  // to a usage/config error (exit 2) — NOT exit 1 (which means duplicates were
397
397
  // found) and NOT a crash. This exercises runDedupAction's Index call and the
398
398
  // engine-error → exit-2 mapping without triggering a model download (Load
399
399
  // throws first). Falsifiable: swallowing the error would change the code to 0.
400
400
  it("malformed dedup config exits 2 (usage)", async () => {
401
401
  const tmp = makeNewSchemaRepo("doc:\n boundary:\n - docs/**\n", {
402
- ".docgov/dedup/config.yml": ": : : not valid yaml ][\n",
402
+ ".docsgov/dedup/config.yml": ": : : not valid yaml ][\n",
403
403
  "docs/guide.md": "# Guide\n\nHello.\n",
404
404
  });
405
405
  const restore = silenceStderr();
@@ -1,5 +1,5 @@
1
1
  // Package codeq resolves code references against the project source tree.
2
- // It is the only place tree-sitter touches docgov; every consumer above this
2
+ // It is the only place tree-sitter touches docsgov; every consumer above this
3
3
  // layer sees the Resolver interface as a boolean oracle.
4
4
  //
5
5
  // Go's codeq uses sentinel `var Err… = errors.New(…)` values wrapped with
@@ -34,7 +34,7 @@ export class ParseFailedError extends Error {
34
34
  }
35
35
  /**
36
36
  * UnsupportedLanguageError is thrown when the file extension has no registered
37
- * resolver. It is distinct from an operational failure — it means docgov has no
37
+ * resolver. It is distinct from an operational failure — it means docsgov has no
38
38
  * grammar for that language, not that the symbol is absent.
39
39
  *
40
40
  * Go original: `ErrUnsupportedLanguage`, wrapped as `fmt.Errorf("%w: %q", …, ext)`.
@@ -1,5 +1,5 @@
1
1
  // Public surface of the codeq package — the only place tree-sitter touches
2
- // docgov. Consumers above this layer see the Resolver/DefaultResolver boolean
2
+ // docsgov. Consumers above this layer see the Resolver/DefaultResolver boolean
3
3
  // oracle and the typed errors, never the binding.
4
4
  export { FileNotFoundError, ParseFailedError, UnsupportedLanguageError, } from "./errors.js";
5
5
  export { DefaultResolver, createDefaultResolver } from "./resolver.js";
@@ -64,7 +64,7 @@ describe("DefaultResolver dispatch", () => {
64
64
  expect(await r.resolve(fs, ref("pkg/foo.go", "Nope"))).toBe(false);
65
65
  });
66
66
  it("throws UnsupportedLanguageError for an unregistered extension", async () => {
67
- // WHY: an unknown extension is NOT "symbol absent" — it means docgov has no
67
+ // WHY: an unknown extension is NOT "symbol absent" — it means docsgov has no
68
68
  // grammar for it; the caller reports it differently. Mirrors Go returning
69
69
  // ErrUnsupportedLanguage (wrapped with the ext).
70
70
  const r = new DefaultResolver(new Map([[".go", spyResolver(true)]]));
@@ -32,7 +32,7 @@ function toStringArray(value) {
32
32
  return value.map((item) => String(item));
33
33
  }
34
34
  /**
35
- * loadConfig reads .docgov/docgov.yaml from fsys and returns the parsed Config.
35
+ * loadConfig reads .docsgov/docsgov.yaml from fsys and returns the parsed Config.
36
36
  *
37
37
  * A missing file propagates a NotExistError (the CLI maps this to its exit code
38
38
  * in a later stage). A malformed YAML file throws a descriptive error. No
@@ -45,7 +45,7 @@ function toStringArray(value) {
45
45
  */
46
46
  export async function loadConfig(fsys) {
47
47
  // readFile throws NotExistError for a missing file; let it propagate.
48
- const data = await fsys.readFile(".docgov/docgov.yaml");
48
+ const data = await fsys.readFile(".docsgov/docsgov.yaml");
49
49
  const text = new TextDecoder().decode(data);
50
50
  // parseYaml throws on malformed YAML (descriptive error); let it propagate.
51
51
  const parsed = parseYaml(text);
@@ -6,7 +6,7 @@ describe("loadConfig", () => {
6
6
  // whole check pipeline depends on.
7
7
  it("loads code, doc, and api scopes with their exact glob lists", async () => {
8
8
  const fsys = new MapFS({
9
- ".docgov/docgov.yaml": `
9
+ ".docsgov/docsgov.yaml": `
10
10
  code:
11
11
  boundary: [docs/**]
12
12
  source: [internal/**, cmd/**]
@@ -31,7 +31,7 @@ api:
31
31
  // entirely (undefined vs defined is the "is this guard configured?" signal).
32
32
  it("leaves absent sections undefined", async () => {
33
33
  const fsys = new MapFS({
34
- ".docgov/docgov.yaml": `
34
+ ".docsgov/docsgov.yaml": `
35
35
  doc:
36
36
  boundary: [docs/**]
37
37
  `,
@@ -47,7 +47,7 @@ doc:
47
47
  // guard) and "explicitly configured but empty" (run the guard, match nothing).
48
48
  it("yields a defined empty scope for a present-but-null section", async () => {
49
49
  const fsys = new MapFS({
50
- ".docgov/docgov.yaml": `
50
+ ".docsgov/docsgov.yaml": `
51
51
  code:
52
52
  `,
53
53
  });
@@ -74,7 +74,7 @@ code:
74
74
  // docs go unchecked.
75
75
  it("throws on malformed YAML", async () => {
76
76
  const fsys = new MapFS({
77
- ".docgov/docgov.yaml": `
77
+ ".docsgov/docsgov.yaml": `
78
78
  code: {boundary: [not closed
79
79
  `,
80
80
  });
@@ -83,7 +83,7 @@ code: {boundary: [not closed
83
83
  // Unknown top-level keys are silently ignored (forward-compat per the plan).
84
84
  it("silently ignores unknown top-level keys", async () => {
85
85
  const fsys = new MapFS({
86
- ".docgov/docgov.yaml": `
86
+ ".docsgov/docsgov.yaml": `
87
87
  future:
88
88
  boundary: [x/**]
89
89
  doc:
package/dist/config/fs.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Filesystem abstraction for the config package.
2
2
  //
3
- // FS RECONCILIATION (minimize-docgov port): the config package and the repo
3
+ // FS RECONCILIATION (minimize-docsgov port): the config package and the repo
4
4
  // package originally carried two different FS abstractions — config's was
5
5
  // synchronous (readFile + walk), repo's is asynchronous (readFile + readDir +
6
6
  // sub). The check orchestrator composes both, so they are unified here onto
@@ -1,7 +1,7 @@
1
1
  // Port of internal/config/glob.go.
2
2
  //
3
3
  // Go uses github.com/bmatcuk/doublestar; we use picomatch with { dot: true },
4
- // which matches doublestar's semantics for the patterns docgov uses:
4
+ // which matches doublestar's semantics for the patterns docsgov uses:
5
5
  // - "**" matches zero or more path segments (so "docs/**" matches "docs"),
6
6
  // - dotfiles are matched (doublestar matches them by default),
7
7
  // - a malformed pattern contributes no match (doublestar returns an error
@@ -23,7 +23,7 @@ describe("inScope", () => {
23
23
  });
24
24
  // A path matching none of the patterns must be out of scope.
25
25
  it("returns false when no pattern matches", () => {
26
- expect(inScope(["docs/**", "internal/**"], "cmd/docgov/main.go")).toBe(false);
26
+ expect(inScope(["docs/**", "internal/**"], "cmd/docsgov/main.go")).toBe(false);
27
27
  });
28
28
  // No patterns means nothing is ever in scope.
29
29
  it("returns false for an empty pattern list", () => {
@@ -1,5 +1,5 @@
1
1
  // Loads and validates the dedup config: Default() overlaid with any
2
- // .docgov/dedup/config.yml present at repoRoot.
2
+ // .docsgov/dedup/config.yml present at repoRoot.
3
3
  //
4
4
  // Ported from internal/dedup/configload.go. Go used yaml.Unmarshal(data, &cfg),
5
5
  // which sets only the fields present in the YAML (scalars override, list fields
@@ -42,14 +42,14 @@ function quote(s) {
42
42
  return JSON.stringify(s);
43
43
  }
44
44
  /**
45
- * Load returns Default() overlaid with any .docgov/dedup/config.yml present at
45
+ * Load returns Default() overlaid with any .docsgov/dedup/config.yml present at
46
46
  * repoRoot. A missing file is silently skipped. A malformed YAML file throws a
47
47
  * wrapped error (hard error — never falls back to defaults on parse failure).
48
48
  * Validation runs last so user overlays are fully applied before checking.
49
49
  */
50
50
  export async function Load(repoRoot) {
51
51
  const cfg = Default();
52
- const dedupDir = path.join(repoRoot, ".docgov", "dedup");
52
+ const dedupDir = path.join(repoRoot, ".docsgov", "dedup");
53
53
  // Step 1: overlay config.yml onto defaults.
54
54
  const configPath = path.join(dedupDir, "config.yml");
55
55
  let data;
@@ -23,15 +23,15 @@ afterEach(() => {
23
23
  rmSync(d, { recursive: true, force: true });
24
24
  }
25
25
  });
26
- /** newRepo returns a fresh temp repo root with no .docgov/dedup. */
26
+ /** newRepo returns a fresh temp repo root with no .docsgov/dedup. */
27
27
  function newRepo() {
28
28
  const dir = mkdtempSync(join(tmpdir(), "dedup-cfg-"));
29
29
  tmpDirs.push(dir);
30
30
  return dir;
31
31
  }
32
- /** writeConfigYML writes config.yml under repoRoot/.docgov/dedup. */
32
+ /** writeConfigYML writes config.yml under repoRoot/.docsgov/dedup. */
33
33
  function writeConfigYML(repoRoot, yaml) {
34
- const dedupDir = join(repoRoot, ".docgov", "dedup");
34
+ const dedupDir = join(repoRoot, ".docsgov", "dedup");
35
35
  mkdirSync(dedupDir, { recursive: true });
36
36
  writeFileSync(join(dedupDir, "config.yml"), yaml);
37
37
  }
@@ -60,7 +60,7 @@ describe("Default", () => {
60
60
  const cfg = Default();
61
61
  expect(cfg.Markdown.ignored_dirs).toEqual([
62
62
  ".git", "node_modules", "vendor", "dist", "build",
63
- ".next", ".cache", ".docgov", "dedup-poc", ".venv",
63
+ ".next", ".cache", ".docsgov", "dedup-poc", ".venv",
64
64
  ]);
65
65
  expect(cfg.Analyzer.universal_stopwords).toEqual([
66
66
  "the", "a", "an", "of", "and", "or", "to", "with",
@@ -401,7 +401,7 @@ describe("Load", () => {
401
401
  // the cause attached — never silently fall back to defaults (Rule 12).
402
402
  it("throws (not falls back) when config.yml cannot be read for a non-ENOENT reason", async () => {
403
403
  const repo = newRepo();
404
- const dedupDir = join(repo, ".docgov", "dedup");
404
+ const dedupDir = join(repo, ".docsgov", "dedup");
405
405
  mkdirSync(dedupDir, { recursive: true });
406
406
  // Make config.yml a directory so reading it fails with EISDIR, not ENOENT.
407
407
  mkdirSync(join(dedupDir, "config.yml"));