@descent-vtt/spec-graph 0.12.0 → 0.12.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 (3) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/README.md +46 -18
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -11,6 +11,28 @@ the family's
11
11
  [versioning policy](https://github.com/DescentVTT/spec-core/blob/main/docs/adr/0009-versions-before-1-0.md)
12
12
  records.
13
13
 
14
+ ## 0.12.1
15
+
16
+ The README's commands gave `npx` the command's bare name, which on npm is
17
+ not this project's package. spec-graph itself is unchanged.
18
+
19
+ ### Security
20
+
21
+ - Every command in the README gives `npx` the package's full name behind
22
+ `--no-install`, as in `npx --no-install @descent-vtt/spec-graph ...`.
23
+ `spec-graph` without the scope belongs to nobody on npm (2026-10-07), so
24
+ anyone can register it.
25
+ `npx` given a name the project has not installed fetches the package of
26
+ that name and runs it, unasked when no terminal is attached: a fresh
27
+ clone, a worktree before `npm ci`, a CI job with no install step.
28
+ The CI examples install first, and [Names](README.md#names) says whose the
29
+ names are; what was measured is in the family's
30
+ [adopting guide](https://github.com/DescentVTT/spec-core/blob/main/docs/adopting.md#names).
31
+ Upgrading: where a CI job or a script gives `npx` the command's name
32
+ alone, write `npx --no-install @descent-vtt/spec-graph`. `--no-install`
33
+ before the bare name is not enough: npm still runs a copy of that name's
34
+ package an earlier fetch left in its cache.
35
+
14
36
  ## 0.12.0
15
37
 
16
38
  Names every JavaScript object answers to - `constructor`, `__proto__` - are
@@ -1410,7 +1432,7 @@ reference.
1410
1432
  `$GITHUB_STEP_SUMMARY` or a pull-request comment:
1411
1433
 
1412
1434
  ```yaml
1413
- - run: npx spec-graph --format markdown >> "$GITHUB_STEP_SUMMARY"
1435
+ - run: npx --no-install @descent-vtt/spec-graph --format markdown >> "$GITHUB_STEP_SUMMARY"
1414
1436
  ```
1415
1437
 
1416
1438
  SARIF puts a finding on the line that caused it, which is where somebody fixing
package/README.md CHANGED
@@ -53,22 +53,44 @@ document and obvious when you can query all of them at once.
53
53
 
54
54
  ```bash
55
55
  npm install --save-dev @descent-vtt/spec-graph
56
- npx spec-graph
56
+ npx --no-install @descent-vtt/spec-graph
57
57
  ```
58
58
 
59
59
  No configuration, no annotations, no migration. It reads what your repository
60
60
  already looks like:
61
61
 
62
62
  ```bash
63
- npx spec-graph "docs/**/*.md"
63
+ npx --no-install @descent-vtt/spec-graph "docs/**/*.md"
64
64
  ```
65
65
 
66
- **The package is scoped; the command is not.** After a local install the binary
67
- is plain `spec-graph`. Without one, `npx` needs the full name:
66
+ ## Names
68
67
 
69
- ```bash
70
- npx @descent-vtt/spec-graph "docs/**/*.md"
71
- ```
68
+ The package is `@descent-vtt/spec-graph`, and the command it installs is
69
+ `spec-graph`. The name without the scope is not this project: on npm,
70
+ `spec-graph` belonged to nobody on 2026-10-07, and whoever registers it decides
71
+ what it runs.
72
+
73
+ `npx` fetches and runs the package of whatever name it is given when the
74
+ project has none installed - a fresh clone, a worktree before `npm ci`, a CI job
75
+ without the install step - and without a terminal it does not ask first. So
76
+ give `npx` the full name:
77
+
78
+ - `npx --no-install @descent-vtt/spec-graph` in a project that installed it: it
79
+ runs that install, the version the lockfile pins, and where there is none it
80
+ stops with an error that names this package.
81
+ - `npx @descent-vtt/spec-graph`, without `--no-install`, where nothing is
82
+ installed: it fetches this package and runs it.
83
+
84
+ <!-- bare-name: the two forms in the next sentence are shown as what not to write -->
85
+ Never `npx spec-graph`, and not `npx --no-install spec-graph` either:
86
+ `--no-install` stops a download, and npm still runs a copy of the bare name's
87
+ package that an earlier fetch left in its cache. The family's
88
+ [adopting guide](https://github.com/DescentVTT/spec-core/blob/main/docs/adopting.md#names)
89
+ has what was measured, under npm 10, 11 and 12.
90
+
91
+ Where this page writes the command alone, as in `spec-graph query ...`, it is
92
+ what a `package.json` script holds - npm fetches nothing for a script - and what
93
+ follows `npx --no-install @descent-vtt/` at a prompt.
72
94
 
73
95
  ## What it checks
74
96
 
@@ -630,7 +652,7 @@ gate without writing any code:
630
652
  ```yaml
631
653
  - name: No PRD may depend on a draft decision
632
654
  run: |
633
- ! npx spec-graph query 'document[path^=docs/prd] -depends-on-> document[phase=draft]'
655
+ ! npx --no-install @descent-vtt/spec-graph query 'document[path^=docs/prd] -depends-on-> document[phase=draft]'
634
656
  ```
635
657
 
636
658
  That shell line is a rule wearing a disguise. Give it a name and a sentence and
@@ -1033,7 +1055,7 @@ loop that would justify a resident process is one line of shell, and it belongs
1033
1055
  to whatever the developer already uses rather than to this tool:
1034
1056
 
1035
1057
  ```bash
1036
- npx spec-graph --format json | jq -r '.summary'
1058
+ npx --no-install @descent-vtt/spec-graph --format json | jq -r '.summary'
1037
1059
  ```
1038
1060
 
1039
1061
  ## In CI
@@ -1041,6 +1063,11 @@ npx spec-graph --format json | jq -r '.summary'
1041
1063
  The exit code is the contract: `0` clean, `1` findings, `2` the tool could not
1042
1064
  run. That is all most pipelines need.
1043
1065
 
1066
+ Every job below installs the project first, with `npm ci`, and gives `npx` the
1067
+ package's [full name](#names) behind `--no-install`: a job that lost its install
1068
+ step then stops, where the command's name alone would fetch whatever package
1069
+ has that name.
1070
+
1044
1071
  Beyond that, a format puts the findings where somebody will look:
1045
1072
 
1046
1073
  | Format | Where the findings land |
@@ -1070,7 +1097,7 @@ steps:
1070
1097
  with:
1071
1098
  node-version: '24'
1072
1099
  - run: npm ci
1073
- - run: npx spec-graph --format sarif > spec-graph.sarif
1100
+ - run: npx --no-install @descent-vtt/spec-graph --format sarif > spec-graph.sarif
1074
1101
  continue-on-error: true
1075
1102
  - uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
1076
1103
  with:
@@ -1093,7 +1120,7 @@ command per finding, and the job's log turns each into an annotation on the
1093
1120
  diff, with no upload step:
1094
1121
 
1095
1122
  ```yaml
1096
- - run: npx spec-graph --format github
1123
+ - run: npx --no-install @descent-vtt/spec-graph --format github
1097
1124
  ```
1098
1125
 
1099
1126
  ```text
@@ -1117,7 +1144,8 @@ resolved:
1117
1144
  ```yaml
1118
1145
  spec-graph:
1119
1146
  script:
1120
- - npx spec-graph --format gitlab > gl-code-quality-report.json
1147
+ - npm ci
1148
+ - npx --no-install @descent-vtt/spec-graph --format gitlab > gl-code-quality-report.json
1121
1149
  artifacts:
1122
1150
  when: always
1123
1151
  reports:
@@ -1148,7 +1176,7 @@ actually look:
1148
1176
  ```yaml
1149
1177
  - name: Summarise the specification graph
1150
1178
  if: always()
1151
- run: npx spec-graph --format markdown >> "$GITHUB_STEP_SUMMARY"
1179
+ run: npx --no-install @descent-vtt/spec-graph --format markdown >> "$GITHUB_STEP_SUMMARY"
1152
1180
  ```
1153
1181
 
1154
1182
  It leads with the verdict, counts the corpus, gives every finding its hint, and
@@ -1163,7 +1191,7 @@ per-file detail that SARIF and Code Quality have nowhere to put.
1163
1191
 
1164
1192
  ```yaml
1165
1193
  - name: Check the specification graph
1166
- run: npx spec-graph "docs/**/*.md" --format json > spec-graph.json
1194
+ run: npx --no-install @descent-vtt/spec-graph "docs/**/*.md" --format json > spec-graph.json
1167
1195
  ```
1168
1196
 
1169
1197
  The JSON report is versioned, flat, and carries start and end positions for
@@ -1199,9 +1227,9 @@ binary, so CI makes one from the base branch and one from the pull request:
1199
1227
 
1200
1228
  ```yaml
1201
1229
  - run: git fetch --depth 1 origin "$GITHUB_BASE_REF" && git worktree add ../base FETCH_HEAD
1202
- - run: npx spec-graph graph --root ../base --graph-format json > base.json
1203
- - run: npx spec-graph graph --graph-format json > head.json
1204
- - run: npx spec-graph diff base.json head.json --format markdown >> "$GITHUB_STEP_SUMMARY"
1230
+ - run: npx --no-install @descent-vtt/spec-graph graph --root ../base --graph-format json > base.json
1231
+ - run: npx --no-install @descent-vtt/spec-graph graph --graph-format json > head.json
1232
+ - run: npx --no-install @descent-vtt/spec-graph diff base.json head.json --format markdown >> "$GITHUB_STEP_SUMMARY"
1205
1233
  ```
1206
1234
 
1207
1235
  It names only what it can tell apart:
@@ -1289,7 +1317,7 @@ tools share, whose code is copied into `src/vendor/` and checked by hash rather
1289
1317
  than installed. So the whole package is auditable in an afternoon — and nothing
1290
1318
  in the pipeline can take longer than its input.
1291
1319
 
1292
- **Verified, not just covered.** 1,918 tests; 99.4% statement and 99.8% line
1320
+ **Verified, not just covered.** 1,995 tests; 99.4% statement and 99.8% line
1293
1321
  coverage. Coverage says a line ran, so the suite is also held to a mutation
1294
1322
  score - 96.38% over 8,539 mutants, measured by CI's full sweep, and a build
1295
1323
  fails under 93 - because a vocabulary entry or a boundary
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descent-vtt/spec-graph",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Turn Markdown specs into a verifiable relational graph. Catches ghost handovers, stale premises and broken references in CI.",
5
5
  "keywords": [
6
6
  "adr",