code-auditor-mcp 3.9.11 → 4.0.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 (261) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +200 -0
  3. package/dist/analyzers/analyzerUtils.js +2 -2
  4. package/dist/analyzers/analyzerUtils.js.map +1 -1
  5. package/dist/analyzers/applicability.d.ts.map +1 -1
  6. package/dist/analyzers/applicability.js +1 -0
  7. package/dist/analyzers/applicability.js.map +1 -1
  8. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +1 -1
  9. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  10. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +3 -3
  11. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  12. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +2 -2
  13. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
  14. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +39 -15
  15. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  16. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  17. package/dist/analyzers/documentationAnalyzer.js +14 -16
  18. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  19. package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
  20. package/dist/analyzers/invariantsAnalyzer.js +30 -25
  21. package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
  22. package/dist/analyzers/reactAnalyzer.d.ts +1 -1
  23. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  24. package/dist/analyzers/reactAnalyzer.js +34 -116
  25. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  26. package/dist/analyzers/ruleRegistry.d.ts +5 -3
  27. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  28. package/dist/analyzers/ruleRegistry.js +198 -54
  29. package/dist/analyzers/ruleRegistry.js.map +1 -1
  30. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +2 -2
  31. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  32. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +10 -17
  33. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  34. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +6 -6
  35. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +13 -13
  36. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  37. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  38. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +22 -64
  39. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  40. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +3 -2
  41. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  42. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +14 -13
  43. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  44. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +11 -11
  45. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  46. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +1 -1
  47. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  48. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +18 -7
  49. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  50. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -2
  51. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  52. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +38 -26
  53. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  54. package/dist/analyzers/universal/schema/codeAnalysis.d.ts +37 -13
  55. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
  56. package/dist/analyzers/universal/schema/codeAnalysis.js +42 -54
  57. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  58. package/dist/analyzers/universal/schema/jsonSchema.js +1 -1
  59. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
  60. package/dist/analyzers/universal/schema/violations.d.ts +1 -1
  61. package/dist/analyzers/universal/schema/violations.d.ts.map +1 -1
  62. package/dist/auditRouter.js +7 -7
  63. package/dist/auditRouter.js.map +1 -1
  64. package/dist/auditRunner.d.ts.map +1 -1
  65. package/dist/auditRunner.js +36 -6
  66. package/dist/auditRunner.js.map +1 -1
  67. package/dist/cli.js +23 -17
  68. package/dist/cli.js.map +1 -1
  69. package/dist/codeIndexDB.d.ts +1 -1
  70. package/dist/codeIndexDB.d.ts.map +1 -1
  71. package/dist/codeIndexDB.js +148 -18
  72. package/dist/codeIndexDB.js.map +1 -1
  73. package/dist/componentScanner.d.ts.map +1 -1
  74. package/dist/componentScanner.js +89 -28
  75. package/dist/componentScanner.js.map +1 -1
  76. package/dist/config/configLoader.js +1 -1
  77. package/dist/config/configLoader.js.map +1 -1
  78. package/dist/config/defaults.js +3 -3
  79. package/dist/config/defaults.js.map +1 -1
  80. package/dist/constants.d.ts +1 -1
  81. package/dist/constants.d.ts.map +1 -1
  82. package/dist/conventions/conventionMiner.d.ts.map +1 -1
  83. package/dist/conventions/conventionMiner.js +3 -10
  84. package/dist/conventions/conventionMiner.js.map +1 -1
  85. package/dist/daemon/core.d.ts.map +1 -1
  86. package/dist/daemon/core.js +33 -38
  87. package/dist/daemon/core.js.map +1 -1
  88. package/dist/daemon/lspServer.js +1 -1
  89. package/dist/daemon/lspServer.js.map +1 -1
  90. package/dist/daemon/main.d.ts.map +1 -1
  91. package/dist/daemon/main.js +14 -4
  92. package/dist/daemon/main.js.map +1 -1
  93. package/dist/enforcement/gate.js +2 -2
  94. package/dist/functionScanner.d.ts.map +1 -1
  95. package/dist/functionScanner.js +47 -42
  96. package/dist/functionScanner.js.map +1 -1
  97. package/dist/graph/importClassification.d.ts +76 -0
  98. package/dist/graph/importClassification.d.ts.map +1 -0
  99. package/dist/graph/importClassification.js +221 -0
  100. package/dist/graph/importClassification.js.map +1 -0
  101. package/dist/graph/importGraph.d.ts +1 -0
  102. package/dist/graph/importGraph.d.ts.map +1 -1
  103. package/dist/graph/importGraph.js +1 -1
  104. package/dist/graph/importGraph.js.map +1 -1
  105. package/dist/hooks/codex.d.ts.map +1 -1
  106. package/dist/hooks/codex.js +1 -1
  107. package/dist/hooks/codex.js.map +1 -1
  108. package/dist/hooks/core.d.ts +1 -1
  109. package/dist/hooks/core.d.ts.map +1 -1
  110. package/dist/hooks/core.js +4 -4
  111. package/dist/hooks/core.js.map +1 -1
  112. package/dist/hooks/cursor.d.ts.map +1 -1
  113. package/dist/hooks/cursor.js +2 -2
  114. package/dist/hooks/cursor.js.map +1 -1
  115. package/dist/index.d.ts +1 -1
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js.map +1 -1
  118. package/dist/installer.d.ts +20 -0
  119. package/dist/installer.d.ts.map +1 -1
  120. package/dist/installer.js +58 -0
  121. package/dist/installer.js.map +1 -1
  122. package/dist/invariants/invariant-rules.schema.json +1 -1
  123. package/dist/invariants/ruleValidator.js +1 -1
  124. package/dist/invariants/ruleValidator.js.map +1 -1
  125. package/dist/invariants/types.d.ts +1 -1
  126. package/dist/invariants/types.d.ts.map +1 -1
  127. package/dist/languages/LanguageOrchestrator.d.ts +3 -2
  128. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  129. package/dist/languages/LanguageOrchestrator.js +1 -1
  130. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  131. package/dist/languages/RuntimeManager.d.ts +20 -11
  132. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  133. package/dist/languages/RuntimeManager.js +151 -51
  134. package/dist/languages/RuntimeManager.js.map +1 -1
  135. package/dist/languages/adapterBridge.d.ts +10 -0
  136. package/dist/languages/adapterBridge.d.ts.map +1 -1
  137. package/dist/languages/adapterBridge.js +30 -7
  138. package/dist/languages/adapterBridge.js.map +1 -1
  139. package/dist/languages/go/GoAdapter.d.ts +1 -19
  140. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  141. package/dist/languages/go/GoAdapter.js +33 -116
  142. package/dist/languages/go/GoAdapter.js.map +1 -1
  143. package/dist/languages/go/analyzer +0 -0
  144. package/dist/languages/go/analyzer-src/analyzer.go +8 -8
  145. package/dist/languages/go/analyzer-src/solid.go +5 -5
  146. package/dist/languages/goBinary.d.ts +46 -0
  147. package/dist/languages/goBinary.d.ts.map +1 -0
  148. package/dist/languages/goBinary.js +169 -0
  149. package/dist/languages/goBinary.js.map +1 -0
  150. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +1 -28
  151. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
  152. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +3 -42
  153. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
  154. package/dist/languages/tree-sitter/converter.d.ts.map +1 -1
  155. package/dist/languages/tree-sitter/converter.js +2 -1
  156. package/dist/languages/tree-sitter/converter.js.map +1 -1
  157. package/dist/languages/tree-sitter/rawNode.d.ts +31 -0
  158. package/dist/languages/tree-sitter/rawNode.d.ts.map +1 -0
  159. package/dist/languages/tree-sitter/rawNode.js +38 -0
  160. package/dist/languages/tree-sitter/rawNode.js.map +1 -0
  161. package/dist/languages/types.d.ts +0 -21
  162. package/dist/languages/types.d.ts.map +1 -1
  163. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +1 -32
  164. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  165. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +69 -203
  166. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  167. package/dist/ledger.d.ts +3 -0
  168. package/dist/ledger.d.ts.map +1 -1
  169. package/dist/ledger.js +45 -9
  170. package/dist/ledger.js.map +1 -1
  171. package/dist/mcp-tools/projectTasks.js +2 -2
  172. package/dist/mcp-tools/projectTasks.js.map +1 -1
  173. package/dist/mcp-tools/workflowGuide.js +3 -3
  174. package/dist/mcp-tools/workflowGuide.js.map +1 -1
  175. package/dist/mcp-tools-shared.js +13 -13
  176. package/dist/mcp-tools-shared.js.map +1 -1
  177. package/dist/mcp-ui-simple.js +7 -7
  178. package/dist/mcp-ui-simple.js.map +1 -1
  179. package/dist/mcp.js +14 -14
  180. package/dist/mcp.js.map +1 -1
  181. package/dist/mcpAuditJobs.js +7 -7
  182. package/dist/mcpAuditJobs.js.map +1 -1
  183. package/dist/mcpAutoIndex.js +1 -1
  184. package/dist/mcpAutoIndex.js.map +1 -1
  185. package/dist/nextFile.d.ts +2 -2
  186. package/dist/nextFile.d.ts.map +1 -1
  187. package/dist/nextFile.js +19 -5
  188. package/dist/nextFile.js.map +1 -1
  189. package/dist/nextFileIncremental.d.ts +3 -2
  190. package/dist/nextFileIncremental.d.ts.map +1 -1
  191. package/dist/nextFileIncremental.js +20 -7
  192. package/dist/nextFileIncremental.js.map +1 -1
  193. package/dist/pipelineAdapters.d.ts +17 -0
  194. package/dist/pipelineAdapters.d.ts.map +1 -1
  195. package/dist/pipelineAdapters.js +279 -178
  196. package/dist/pipelineAdapters.js.map +1 -1
  197. package/dist/reporting/csvReportGenerator.js +6 -6
  198. package/dist/reporting/csvReportGenerator.js.map +1 -1
  199. package/dist/reporting/htmlReportGenerator.js +11 -11
  200. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  201. package/dist/reporting/jsonReportGenerator.js +2 -2
  202. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  203. package/dist/reporting/sarifReportGenerator.js +1 -1
  204. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  205. package/dist/scripts/benchmarkWorkers.js +1 -1
  206. package/dist/scripts/benchmarkWorkers.js.map +1 -1
  207. package/dist/styles/cssAstExtractor.d.ts +2 -2
  208. package/dist/styles/cssAstExtractor.d.ts.map +1 -1
  209. package/dist/styles/cssAstExtractor.js +67 -111
  210. package/dist/styles/cssAstExtractor.js.map +1 -1
  211. package/dist/styles/styleIndexer.d.ts.map +1 -1
  212. package/dist/styles/styleIndexer.js +19 -6
  213. package/dist/styles/styleIndexer.js.map +1 -1
  214. package/dist/telemetry.d.ts +1 -1
  215. package/dist/telemetry.d.ts.map +1 -1
  216. package/dist/types/crossLanguage.d.ts +1 -1
  217. package/dist/types/crossLanguage.d.ts.map +1 -1
  218. package/dist/types.d.ts +59 -19
  219. package/dist/types.d.ts.map +1 -1
  220. package/dist/types.js +6 -5
  221. package/dist/types.js.map +1 -1
  222. package/dist/utils/astParser.d.ts +1 -17
  223. package/dist/utils/astParser.d.ts.map +1 -1
  224. package/dist/utils/astParser.js +18 -60
  225. package/dist/utils/astParser.js.map +1 -1
  226. package/dist/utils/astUtils.d.ts +12 -12
  227. package/dist/utils/astUtils.d.ts.map +1 -1
  228. package/dist/utils/astUtils.js +83 -82
  229. package/dist/utils/astUtils.js.map +1 -1
  230. package/dist/utils/componentResponsibility.d.ts +8 -8
  231. package/dist/utils/componentResponsibility.d.ts.map +1 -1
  232. package/dist/utils/componentResponsibility.js +33 -38
  233. package/dist/utils/componentResponsibility.js.map +1 -1
  234. package/dist/utils/dependencyExtractor.d.ts +3 -3
  235. package/dist/utils/dependencyExtractor.d.ts.map +1 -1
  236. package/dist/utils/dependencyExtractor.js +26 -30
  237. package/dist/utils/dependencyExtractor.js.map +1 -1
  238. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  239. package/dist/utils/fileDiscovery.js +65 -0
  240. package/dist/utils/fileDiscovery.js.map +1 -1
  241. package/dist/utils/jsDocParser.d.ts +6 -6
  242. package/dist/utils/jsDocParser.d.ts.map +1 -1
  243. package/dist/utils/jsDocParser.js +18 -21
  244. package/dist/utils/jsDocParser.js.map +1 -1
  245. package/dist/utils/reactDetection.d.ts +7 -7
  246. package/dist/utils/reactDetection.d.ts.map +1 -1
  247. package/dist/utils/reactDetection.js +42 -49
  248. package/dist/utils/reactDetection.js.map +1 -1
  249. package/dist/version.generated.d.ts +1 -1
  250. package/dist/version.generated.d.ts.map +1 -1
  251. package/dist/version.generated.js +1 -1
  252. package/dist/version.generated.js.map +1 -1
  253. package/package.json +1 -1
  254. package/plugin/.claude-plugin/plugin.json +1 -1
  255. package/plugin/README.md +5 -4
  256. package/plugin/hooks/hooks.json +11 -0
  257. package/plugin/scripts/hook-common.sh +129 -26
  258. package/plugin/scripts/hook-warm.sh +44 -0
  259. package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +28 -21
  260. package/plugin/skills/code-auditor/SKILL.md +10 -10
  261. package/server.json +2 -2
@@ -7,42 +7,126 @@
7
7
  #
8
8
  # Two rules enforced here are the fix for "the hook died quietly" (three times:
9
9
  # unset CLAUDE_PLUGIN_ROOT, a stale global binary, a removed CLI flag):
10
- # 1. prefer the plugin's bundled CLI when it is shipped (npm installs) so a
11
- # stale global/project binary can never drive the hook, and
10
+ # 1. prefer a bundled CLI when it is shipped (npm installs) AND its version
11
+ # matches the manifest — nothing is trusted on presence alone, and
12
12
  # 2. a non-zero CLI exit that is NOT a finding (2) is a broken hook and must
13
13
  # fail loudly, never degrade to a silent no-op.
14
14
  #
15
15
  # The plugin cache does NOT ship a bundled CLI (dist/ is gitignored, so a
16
16
  # marketplace install from `./plugin` has no `../dist/`), which means the
17
- # fallback paths (project-local, global/PATH, npx) are the common case. For those,
18
- # `assert_compatible` pins the resolved binary's REAL version against the plugin
19
- # manifest and fails loudly on mismatch — see below. This pin is what stopped the
20
- # third quiet failure: a 3.9.6 global silently driving a 3.9.9 plugin.
17
+ # fallback paths (project-local, global/PATH, pinned install) are the common case —
18
+ # but a checkout where a developer *did* build dist/ locally ships a `../dist/cli.js`
19
+ # that is a local, possibly stale build, not the npm-paired dist/. The two files
20
+ # differ in more than freshness: npm's bin-links chmod the packaged `dist/cli.js`
21
+ # to `-rwxr-xr-x` at install, while local `tsc` output stays `-rw-r--r--`, so a
22
+ # marketplace checkout's sibling can be both stale AND non-executable — a file the
23
+ # old presence-only check would have trusted and then failed to run. Resolution is
24
+ # version-aware: EVERY candidate — the bundled sibling included — is used only
25
+ # when its `--version` matches the manifest, otherwise it is warned about and
26
+ # skipped, so a mismatched binary falls through to the pinned install instead
27
+ # of hard-failing. `assert_compatible` remains the final loud backstop on whatever
28
+ # resolve_code_audit returns. Together they stop the third quiet failure: a stale
29
+ # binary silently driving a newer plugin.
21
30
  #
22
31
  # The sourcing hook runs with `set -euo pipefail`.
23
32
 
24
33
  # resolve_code_audit — emit the CLI invocation to use.
25
34
  #
26
- # 1. The plugin's bundled CLI (dist/cli.js ships in the same npm package, so it
27
- # is always the exact version this plugin was built against) — present only
28
- # when installed from npm, not from the marketplace.
29
- # 2. Project-local install (consumer project's own node_modules).
30
- # 3. Global install / PATH.
31
- # 4. npx auto-install (only if nothing else resolves).
35
+ # Resolution is version-aware: EVERY candidate — bundled sibling, project-local,
36
+ # global — is used only when its `--version` matches this plugin's manifest
37
+ # version. A stale candidate is warned about and skipped, so a mismatched binary
38
+ # no longer turns the hook into a hard failure; the pinned install below resolves
39
+ # the correct CLI on its own (and warn_stale tells the user to update so the fast
40
+ # path comes back).
41
+ #
42
+ # 1. The plugin's bundled CLI (`${CLAUDE_PLUGIN_ROOT}/../dist/cli.js` ships in the
43
+ # same npm package, so it usually matches) — but a marketplace checkout has no
44
+ # npm-paired dist/, and a locally built one can be stale, so it is
45
+ # version-checked like everything else.
46
+ # 2. Project-local install (consumer project's own node_modules) — if compatible.
47
+ # 3. Global install / PATH — if compatible.
48
+ # 4. Pinned install, exact manifest version — never a range — the guaranteed-
49
+ # correct fallback when nothing compatible is installed. The package is
50
+ # installed to a deterministic dir and its bin invoked by absolute path; npx is
51
+ # deliberately NOT used for execution (see resolve_pinned_bin).
32
52
  resolve_code_audit() {
53
+ local candidate
33
54
  if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/../dist/cli.js" ]; then
34
- echo "${CLAUDE_PLUGIN_ROOT}/../dist/cli.js"
35
- return
55
+ candidate="${CLAUDE_PLUGIN_ROOT}/../dist/cli.js"
56
+ if cli_is_compatible "${candidate}"; then
57
+ echo "${candidate}"
58
+ return
59
+ fi
60
+ warn_stale "${candidate}"
36
61
  fi
37
62
  if [ -n "${CLAUDE_PROJECT_DIR:-}" ] && [ -x "${CLAUDE_PROJECT_DIR}/node_modules/.bin/code-audit" ]; then
38
- echo "${CLAUDE_PROJECT_DIR}/node_modules/.bin/code-audit"
39
- return
63
+ candidate="${CLAUDE_PROJECT_DIR}/node_modules/.bin/code-audit"
64
+ if cli_is_compatible "${candidate}"; then
65
+ echo "${candidate}"
66
+ return
67
+ fi
68
+ warn_stale "${candidate}"
40
69
  fi
41
70
  if command -v code-audit &>/dev/null; then
42
- echo "code-audit"
43
- return
71
+ candidate="code-audit"
72
+ if cli_is_compatible "${candidate}"; then
73
+ echo "${candidate}"
74
+ return
75
+ fi
76
+ warn_stale "${candidate}"
77
+ fi
78
+ # Pin to the plugin's exact version, not a range: `@^3.0.0` could resolve a
79
+ # cached older CLI and silently drive this plugin with the wrong analyzer code.
80
+ local pv bin
81
+ pv="$(plugin_version)"
82
+ if [ -n "${pv}" ]; then
83
+ if bin="$(resolve_pinned_bin)"; then
84
+ echo "${bin}"
85
+ else
86
+ # Install failed (offline, registry error, npm missing). Emit the npx form
87
+ # as a last-ditch command so the hook still has something to run;
88
+ # assert_compatible rejects it loudly if it cannot be verified — the same
89
+ # treatment as the unreadable-manifest case below.
90
+ echo "npx -y -p code-auditor-mcp@${pv} code-audit"
91
+ fi
92
+ else
93
+ # Manifest unreadable — assert_compatible will reject whatever this fetches,
94
+ # so `@latest` is only a last-ditch command that never survives the pin.
95
+ echo "npx -y -p code-auditor-mcp@latest code-audit"
44
96
  fi
45
- echo "npx -y -p code-auditor-mcp@^3.0.0 code-audit"
97
+ }
98
+
99
+ # pin_dir — the deterministic directory the pinned CLI is installed into. The
100
+ # version is part of the path so a plugin update installs a fresh copy instead of
101
+ # reusing (and possibly mis-matching) the previous version's install.
102
+ pin_dir() {
103
+ printf '%s' "${XDG_CACHE_HOME:-$HOME/.cache}/code-auditor/cli/$(plugin_version)"
104
+ }
105
+
106
+ # resolve_pinned_bin — ensure the pinned package is installed to pin_dir and echo
107
+ # the absolute path to its bin. Silent: prints only the path on success, nothing
108
+ # on failure (return 1).
109
+ #
110
+ # Installing (not `npx -p <pkg>@<ver> <bin>`) is the whole point. npx's `-p` puts
111
+ # the package's bin on PATH and runs the *name*, so a same-named binary earlier in
112
+ # PATH — a global shim, or a volta shim — shadows the pin, and the "fallback"
113
+ # silently routes back to the stale global it was meant to replace. Installing to
114
+ # a known dir and invoking `node_modules/.bin/code-audit` by absolute path removes
115
+ # PATH from the equation entirely.
116
+ resolve_pinned_bin() {
117
+ local pv dir bin
118
+ pv="$(plugin_version)"
119
+ [ -n "$pv" ] || return 1
120
+ dir="$(pin_dir)"
121
+ bin="${dir}/node_modules/.bin/code-audit"
122
+ if [ ! -x "$bin" ]; then
123
+ mkdir -p "$dir" || return 1
124
+ # --ignore-scripts is safe here (the CLI uses node:sqlite, not better-sqlite3,
125
+ # and ships prebuilt binaries) and avoids any install-script work.
126
+ npm install --prefer-offline --prefix "$dir" "code-auditor-mcp@${pv}" \
127
+ --no-audit --no-fund --ignore-scripts --silent >/dev/null 2>&1 || return 1
128
+ fi
129
+ echo "$bin"
46
130
  }
47
131
 
48
132
  # plugin_version — the version this plugin declares in its manifest, or ''.
@@ -60,21 +144,40 @@ semver_of() {
60
144
  printf '%s' "$1" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?' | head -n 1 || true
61
145
  }
62
146
 
147
+ # cli_is_compatible <cmd> — silent; 0 when `<cmd> --version` reports this plugin's
148
+ # exact version, non-zero otherwise (mismatch or undetermined). Resolution uses
149
+ # this to decide fall-through; assert_compatible remains the loud backstop.
150
+ cli_is_compatible() {
151
+ local cmd="$1" pv cv pv_sem cv_sem
152
+ pv="$(plugin_version)"
153
+ cv="$($cmd --version 2>/dev/null || true)"
154
+ pv_sem="$(semver_of "${pv}")"
155
+ cv_sem="$(semver_of "${cv}")"
156
+ [ -n "${pv_sem}" ] && [ -n "${cv_sem}" ] && [ "${pv_sem}" = "${cv_sem}" ]
157
+ }
158
+
159
+ # warn_stale <cmd> — one stderr line naming a stale installed CLI, so the user
160
+ # knows why the hook is paying the pinned install and how to restore the fast path.
161
+ warn_stale() {
162
+ local cmd="$1" cv pv
163
+ pv="$(semver_of "$(plugin_version)")"
164
+ cv="$(semver_of "$($cmd --version 2>/dev/null || true)")"
165
+ echo "[code-auditor] warn: ${cmd} is ${cv:-unidentified} but this plugin needs ${pv:-its version} — using the pinned install instead; update the install to restore the fast path" >&2
166
+ }
167
+
63
168
  # assert_compatible <bin> — pin the plugin to a compatible CLI.
64
169
  #
65
- # The bundled CLI always matches (same package), so it needs no check. Any
66
- # fallback path can drift — a stale global, a project-local pin, or a wider npx
67
- # range — and a 3.4.0 plugin silently driving a 3.5.0 CLI is exactly the
68
- # failure this guards.
170
+ # Every candidate can drift — the bundled sibling in a marketplace checkout, a
171
+ # stale global, a project-local pin, or a stale pinned install — and a 3.4.0
172
+ # plugin silently driving a 3.5.0 CLI is exactly the failure this guards. No
173
+ # candidate is trusted on presence alone: `resolve_code_audit` version-checks up
174
+ # front, and this is the loud backstop that re-checks whatever actually resolves.
69
175
  #
70
176
  # The comparison is semver-vs-semver (the CLI's real `--version`, not its full
71
177
  # banner), and it fails loudly on a mismatch OR when either version cannot be
72
178
  # determined — an unidentified binary is never trusted.
73
179
  assert_compatible() {
74
180
  local bin="$1" pv cv pv_sem cv_sem
75
- case "${bin}" in
76
- "${CLAUDE_PLUGIN_ROOT}/../dist/cli.js") return 0 ;; # pinned by construction
77
- esac
78
181
  pv="$(plugin_version)"
79
182
  cv="$($bin --version 2>/dev/null || true)"
80
183
  pv_sem="$(semver_of "${pv}")"
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+ # code-auditor SessionStart hook — warm the pinned CLI install before the first edit.
3
+ #
4
+ # A marketplace install has no lifecycle step, so the pinned fallback's cold fetch
5
+ # (~5.7s download of the package's native binaries) would otherwise land on the
6
+ # first Write/Edit after install — the kind of apparent hang people disable hooks
7
+ # over. This hook installs the pinned CLI at session start, before any edit.
8
+ #
9
+ # Deliberately non-blocking and silent:
10
+ # - the install is backgrounded (nohup + &) and this script returns immediately,
11
+ # so it never delays session start;
12
+ # - every failure (offline, npm missing, unreadable manifest) is a quiet no-op —
13
+ # a warm-the-cache nicety must never complain or fail the session.
14
+ # `--prefer-offline` makes a warm npm cache a pure cache hit (no registry metadata
15
+ # re-check on every launch) while still fetching on a cold cache. When the CLI is
16
+ # already installed at its deterministic dir, the script exits without touching npm
17
+ # at all — a warm session must not re-check on every launch.
18
+ set -uo pipefail
19
+
20
+ # Belt-and-suspenders: the hooks.json command already guards an unset
21
+ # CLAUDE_PLUGIN_ROOT, but keep the warm a no-op if it is somehow absent here.
22
+ [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] || exit 0
23
+
24
+ # Shared version lookup (plugin_version / semver_of / pin_dir).
25
+ . "${CLAUDE_PLUGIN_ROOT}/scripts/hook-common.sh"
26
+
27
+ # Nothing safe to warm if the manifest version can't be read: warming @latest
28
+ # could pin a different version than resolve_code_audit's fallback would fetch.
29
+ pv="$(plugin_version)"
30
+ [ -n "${pv}" ] || exit 0
31
+
32
+ dir="$(pin_dir)"
33
+ bin="${dir}/node_modules/.bin/code-audit"
34
+
35
+ # Already installed — nothing to warm. Re-running npm install here would re-check
36
+ # the registry on every session, which is exactly the cost this hook exists to avoid.
37
+ [ -x "${bin}" ] && exit 0
38
+
39
+ # Background the exact install the hook's last-resort path runs. Output to
40
+ # /dev/null (silent), stdin from /dev/null (don't hold the hook's stdin open),
41
+ # nohup so the install survives this hook's exit.
42
+ nohup npm install --prefer-offline --prefix "${dir}" "code-auditor-mcp@${pv}" \
43
+ --no-audit --no-fund --ignore-scripts --silent >/dev/null 2>&1 </dev/null &
44
+ exit 0
@@ -103,7 +103,7 @@ Exported symbols in files matching the `path` glob must match the `exports` rege
103
103
  {
104
104
  "id": "constants-upper",
105
105
  "kind": "naming",
106
- "severity": "high",
106
+ "severity": "advisory",
107
107
  "path": "src/**/constants.ts",
108
108
  "exports": "^[A-Z][A-Z0-9_]*$",
109
109
  "message": "Exported constants should use UPPER_SNAKE_CASE."
@@ -176,35 +176,42 @@ Require designated CSS properties to reference a design token instead of a raw v
176
176
 
177
177
  ## Severity Levels
178
178
 
179
- Severity is urgency, not permission. There are three levels — all defects,
180
- none optional — and the axis is *how fast a finding bites you*:
179
+ Severity is urgency, not permission. There are three levels, and the axis is
180
+ *how fast a reading bites you*:
181
181
 
182
182
  | Severity | What it means |
183
183
  |----------|---------------|
184
- | `critical` | Exploitable or broken now |
185
- | `severe` | Wrong, and it will surface |
186
- | `high` | Wrong, and it has not bitten yet |
187
-
188
- Every severity blocks. The edit hook gates on any finding from any rule —
189
- there is no non-blocking tier and no per-rule opt-in. A `high` finding blocks
190
- the edit exactly like a `critical` one; urgency only sets the order you fix
191
- things, never whether they gate.
192
-
193
- > **Severity ranks urgency, never whether a finding is real.** There is no
194
- > "noise" tier — every finding is a defect to resolve, and every finding blocks
195
- > the edit until it is fixed, or the rule that produces it is edited in
196
- > `.codeauditor.json`. There is no "waive" — a finding leaves the queue only by
197
- > being resolved or by changing the rule that fires it. The `next-file` queue
198
- > orders work worst-first; that ordering is triage, not permission — a finding
199
- > that surfaces later in the queue still gates. Documentation findings are not
200
- > stylistic: missing JSDoc is a maintainability defect, not a nicety.
184
+ | `critical` | Already wrong in production, or will fail when this code runs |
185
+ | `severe` | A real defect that has not bitten yet |
186
+ | `advisory` | Correct, but it does not match a convention |
187
+
188
+ `critical` and `severe` are defects; `advisory` is a convention reading — the
189
+ code works, but it deviates from a documented norm (docs, style, naming).
190
+ Every severity blocks by default. The edit hook gates on any finding from any
191
+ rule — there is no non-blocking tier and no per-rule opt-in. An `advisory`
192
+ finding blocks the edit exactly like a `critical` one; urgency only sets the
193
+ order you fix things, never whether they gate.
194
+
195
+ > **Severity ranks urgency, never whether a finding is real.** `advisory` is
196
+ > not a "noise" tier — a convention reading still blocks the edit until it is
197
+ > resolved or the rule that produces it is edited in `.codeauditor.json`. There
198
+ > is no "waive" — a finding leaves the queue only by being resolved or by
199
+ > changing the rule that fires it. The `next-file` queue orders work worst-first;
200
+ > that ordering is triage, not permission — a finding that surfaces later in the
201
+ > queue still gates. Documentation findings ship at `advisory`: missing JSDoc is
202
+ > a maintainability convention, not a runtime defect — but it still blocks.
203
+
204
+ A fourth channel, **diagnostic**, sits outside the severity ladder. It is not a
205
+ severity tier: it carries tool-failure and coverage notices (`engine-error`,
206
+ `config-error`, `undefined-class-disabled`) that are surfaced regardless of
207
+ `--fail-on` and never counted as findings.
201
208
 
202
209
  ## Validation
203
210
 
204
211
  Rules are validated against `invariant-rules.schema.json` on startup. Common errors:
205
212
 
206
213
  - **Missing required field**: each kind has required fields (e.g., `import-ban` requires `module`)
207
- - **Invalid severity**: must be one of `critical`, `severe`, `high`
214
+ - **Invalid severity**: must be one of `critical`, `severe`, `advisory`
208
215
  - **Invalid kind**: must be one of the seven kinds above
209
216
  - **Both allowFrom and denyFrom**: `call-constraint` requires exactly one
210
217
  - **Empty pattern**: `ast-pattern` requires a non-empty `pattern` string
@@ -5,7 +5,7 @@ description: Audit code quality, search the codebase semantically, enforce invar
5
5
 
6
6
  # Code Auditor Skill
7
7
 
8
- > **Version 3.9.11** • Run `code-audit --version` to check your installed version.
8
+ > **Version 4.0.0** • Run `code-audit --version` to check your installed version.
9
9
  > If versions differ, the CLI is authoritative — use `code-audit <command> --help` to see what your install actually supports.
10
10
 
11
11
  You have the `code-audit` CLI available. It indexes every function, component, and struct in the codebase for semantic search and invariant enforcement. Use these commands instead of raw grep/find whenever possible.
@@ -16,7 +16,7 @@ You have the `code-audit` CLI available. It indexes every function, component, a
16
16
 
17
17
  - **Reading** — the human-facing name for one rule observation. The machine contract calls the same thing a **violation** (a "finding" in the JSON). The audit *takes* readings; it does not issue verdicts.
18
18
  - **Coverage panel** — the report leads with what was measured (which rules fired, which were clean, which were not applicable), so a zero-reading run is not mistaken for a clean tree.
19
- - **Triage** — severity is urgency, not permission. Three levels, all defects, none optional: **critical** (exploitable or broken now), **severe** (wrong, and it will surface), **high** (wrong, and it has not bitten yet). The axis is how fast a reading bites you, not whether it matters — every reading blocks the edit gate. Queue order (`critical` → `severe` → `high`) is the order to act, not a license to skip.
19
+ - **Triage** — severity is urgency, not permission. Three levels, and the axis is how fast a reading bites you: **critical** (already wrong in production, or will fail when this code runs), **severe** (a real defect that has not bitten yet), **advisory** (correct, but it does not match a convention). `critical` and `severe` are defects; `advisory` is a convention reading. Every reading blocks the edit gate by default. Queue order (`critical` → `severe` → `advisory`) is the order to act, not a license to skip.
20
20
 
21
21
  ## When to use which command
22
22
 
@@ -51,9 +51,9 @@ code-audit changed --json # Diff-scoped audit (hook c
51
51
 
52
52
  Use `code-audit changed` after edits to confirm you haven't introduced violations. If the hook is active it already runs `code-audit changed` automatically on Write/Edit — pay attention to its output.
53
53
 
54
- **Every reading is a measurement, not a verdict.** The audit is a diagnostic instrument: it reports what it measured (the coverage panel) and takes one reading per rule violation. Work readings in urgency order — critical first, then severe, then high — and resolve them all. Severity is urgency, the order to act, never a judgment on whether a reading is real; there is no "noise" tier. Documentation readings (missing JSDoc) are maintainability gaps, not stylistic niceties. If you choose not to resolve one, record why before moving on — never silently dismiss it.
54
+ **Every reading is a measurement, not a verdict.** The audit is a diagnostic instrument: it reports what it measured (the coverage panel) and takes one reading per rule violation. Work readings in urgency order — critical first, then severe, then advisory — and resolve them all. Severity is urgency, the order to act, never a judgment on whether a reading is real; there is no "noise" tier — an advisory reading still blocks. Documentation readings (missing JSDoc) ship at advisory: maintainability conventions, not stylistic niceties, and still gating. If you choose not to resolve one, record why before moving on — never silently dismiss it.
55
55
 
56
- Expected output: JSON violation list (with `--json`) or colored terminal summary. The full `audit` command exits non-zero when violations at or above `--fail-on` severity exist. Every severity blocks: `critical`, `severe`, and `high` are all gating. The `changed` hook blocks on any violation from any rule — there is no non-blocking tier — and enforcement is not diff-scoped (a pre-existing violation in the audited file blocks exactly like a new one).
56
+ Expected output: JSON violation list (with `--json`) or colored terminal summary. The full `audit` command exits non-zero when violations at or above `--fail-on` severity exist. Every severity blocks: `critical`, `severe`, and `advisory` are all gating. The `changed` hook blocks on any violation from any rule — there is no non-blocking tier — and enforcement is not diff-scoped (a pre-existing violation in the audited file blocks exactly like a new one).
57
57
 
58
58
  ### `code-audit next-file` — fix violations one file at a time
59
59
 
@@ -62,7 +62,7 @@ code-audit next-file --path . # Highest-priority file + all its readings
62
62
  code-audit next-file --path . --json # Machine-readable
63
63
  ```
64
64
 
65
- This is the refactoring loop. `next-file` audits the project and returns the single highest-priority file — ranked by highest-severity reading, then total reading count — with every reading on it, ordered critical → severe → high. Fix that file, then run it again: a still-broken file comes back, otherwise the next-worst file surfaces. `{done:true}` means the tree is clean.
65
+ This is the refactoring loop. `next-file` audits the project and returns the single highest-priority file — ranked by highest-severity reading, then total reading count — with every reading on it, ordered critical → severe → advisory. Fix that file, then run it again: a still-broken file comes back, otherwise the next-worst file surfaces. `{done:true}` means the tree is clean.
66
66
 
67
67
  There is **no skip or decline affordance** in `next-file`. A reading leaves the queue only by being fixed, by editing the rule that produces it in `.codeauditor.json` (your rules editor), or — if it is a genuine false positive — by dismissing that one instance with a written reason (`code-audit dismiss`, below). If a rule keeps firing on something you judge correct, change the rule — never work around it.
68
68
 
@@ -117,7 +117,7 @@ Path profiles are an ordered array — files matching multiple profiles merge ov
117
117
 
118
118
  A **built-in** `scripts-and-tests` profile ships with every install — it excludes `scripts/**`, `tests/**`, `__tests__/**`, `fixtures/**`, and `*.test.*`/`*.spec.*` files from the gate. Disable it with `"builtin": false` in `.codeauditor.json`.
119
119
 
120
- Invariant violations are **immune** to path profile gate exclusion — invariants enforce declared laws and block on the same gate as every other rule (all of `critical`, `severe`, and `high`).
120
+ Invariant violations are **immune** to path profile gate exclusion — invariants enforce declared laws and block on the same gate as every other rule (all of `critical`, `severe`, and `advisory`).
121
121
 
122
122
  ### `code-audit index` — refresh the index after structural changes
123
123
 
@@ -145,7 +145,7 @@ Creates a `.codeauditor.json` configuration file with invariant rules for your p
145
145
 
146
146
  ### `code-audit conventions` — mine and propose rules
147
147
 
148
- Code Auditor learns your codebase's unwritten conventions from the function index and flags deviations at high severity. Use these to discover norms an unfamiliar agent would otherwise break:
148
+ Code Auditor learns your codebase's unwritten conventions from the function index and flags deviations at advisory severity. Use these to discover norms an unfamiliar agent would otherwise break:
149
149
 
150
150
  ```bash
151
151
  code-audit conventions list # See what conventions were mined
@@ -167,7 +167,7 @@ code-audit conventions propose --json # JSON proposal array
167
167
 
168
168
  **Usage:** Run a full audit or `code-audit index sync` to mine conventions from the codebase index. Then `code-audit conventions list` to see what was found, and `code-audit conventions propose` to get the rules. Paste the proposals into the `rules` array in `.codeauditor.json`.
169
169
 
170
- Convention readings ship at `high` severity by default. Severity is urgency — how fast a violation bites, not whether it matters. Every severity blocks the edit gate, so a `high` convention reading is a real defect to resolve, not a hint to ignore.
170
+ Convention readings ship at `advisory` severity by default. Severity is urgency — how fast a reading bites, not whether it matters. `advisory` is a convention reading, not a defect, but it still blocks the edit gate by default — resolve it or edit the rule, never ignore it.
171
171
 
172
172
  ### `code-audit hotspots` — identify churn-prone code
173
173
 
@@ -209,9 +209,9 @@ When an edit hook blocks your edit with a violation message:
209
209
  1. **Read the violation** — it includes the invariant rule's `message` field explaining *why* the edit was blocked
210
210
  2. **Fix the violation** — change your approach to comply with the invariant
211
211
  3. **Do NOT retry the same edit** — the hook will block it again
212
- 4. The hook runs `code-audit changed`, and its gate blocks on every violation from any rule — `critical`, `severe`, and `high` all block; there is no non-blocking severity tier. A `high` reading blocks the edit exactly like a `critical` one; urgency only sets the order you fix things, never whether they gate.
212
+ 4. The hook runs `code-audit changed`, and its gate blocks on every violation from any rule — `critical`, `severe`, and `advisory` all block; there is no non-blocking severity tier. An `advisory` reading blocks the edit exactly like a `critical` one; urgency only sets the order you fix things, never whether they gate.
213
213
 
214
- The hook auto-installs the package via npx on first use — no manual npm step needed. If the hook reports `[code-auditor] code-audit could not run`, the npx auto-install failed (network, unsupported platform). The agent should try again; if it persists, `npm install code-auditor-mcp` is the manual fix.
214
+ The hook auto-installs the package to a cache dir on first use — no manual npm step needed. If the hook reports `[code-auditor] code-audit could not run`, the auto-install failed (network, unsupported platform). The agent should try again; if it persists, `npm install code-auditor-mcp` is the manual fix.
215
215
 
216
216
  ## Host-specific notes
217
217
 
package/server.json CHANGED
@@ -6,13 +6,13 @@
6
6
  "url": "https://github.com/BenAHammond/code-auditor-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.9.11",
9
+ "version": "4.0.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "registryBaseUrl": "https://registry.npmjs.org",
14
14
  "identifier": "code-auditor-mcp",
15
- "version": "3.9.11",
15
+ "version": "4.0.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  }