claudex-setup 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -15,6 +15,18 @@
15
15
  - README and docs now reflect snapshot artifacts, governance export, and the Claude-native skill path
16
16
  - packaged content and public-facing counts are now aligned with the current CLAUDEX state
17
17
 
18
+ ## [1.14.0] - 2026-04-03
19
+
20
+ ### Added
21
+ - Check-level test matrix: 327 verified scenarios across all 84 checks
22
+ - Golden matrix: 12 repo profile tests with expected results
23
+
24
+ ### Fixed
25
+ - `hooks` check now detects hooks in settings.json (not only .claude/hooks/ dir)
26
+ - `context7Mcp` check now reads .mcp.json
27
+ - `skillUsesPaths` now traverses skill subdirectories (skills/name/SKILL.md)
28
+ - `lintCommand` now matches npm/yarn/pnpm/bun lint commands
29
+
18
30
  ## [1.13.0] - 2026-04-03
19
31
 
20
32
  ### Added
package/README.md CHANGED
@@ -305,7 +305,7 @@ jobs:
305
305
  runs-on: ubuntu-latest
306
306
  steps:
307
307
  - uses: actions/checkout@v4
308
- - uses: DnaFin/claudex-setup@v1.13.0
308
+ - uses: DnaFin/claudex-setup@v1.14.0
309
309
  with:
310
310
  threshold: 50
311
311
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudex-setup",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "Score your repo's Claude Code setup against 62 checks. See gaps, apply fixes selectively with rollback, govern hooks and permissions, and benchmark impact — without breaking existing config.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/techniques.js CHANGED
@@ -116,7 +116,7 @@ const TECHNIQUES = {
116
116
  name: 'CLAUDE.md contains a lint command',
117
117
  check: (ctx) => {
118
118
  const md = ctx.fileContent('CLAUDE.md') || '';
119
- return /eslint|prettier|ruff|black|clippy|golangci-lint|rubocop/.test(md);
119
+ return /eslint|prettier|ruff|black|clippy|golangci-lint|rubocop|npm run lint|yarn lint|pnpm lint|bun lint/.test(md);
120
120
  },
121
121
  impact: 'high',
122
122
  rating: 4,
@@ -413,7 +413,12 @@ const TECHNIQUES = {
413
413
  hooks: {
414
414
  id: 19,
415
415
  name: 'Hooks for automation',
416
- check: (ctx) => ctx.hasDir('.claude/hooks') && ctx.dirFiles('.claude/hooks').length > 0,
416
+ check: (ctx) => {
417
+ if (ctx.hasDir('.claude/hooks') && ctx.dirFiles('.claude/hooks').length > 0) return true;
418
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
419
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
420
+ return !!(shared.hooks && Object.keys(shared.hooks).length > 0) || !!(local.hooks && Object.keys(local.hooks).length > 0);
421
+ },
417
422
  impact: 'high',
418
423
  rating: 4,
419
424
  category: 'automation',
@@ -717,9 +722,12 @@ const TECHNIQUES = {
717
722
  id: 110,
718
723
  name: 'Context7 MCP for real-time docs',
719
724
  check: (ctx) => {
720
- const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
721
- if (!settings || !settings.mcpServers) return false;
722
- return Object.keys(settings.mcpServers).some(k => /context7/i.test(k));
725
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
726
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
727
+ const mcp = ctx.jsonFile('.mcp.json') || {};
728
+ const all = { ...(shared.mcpServers || {}), ...(local.mcpServers || {}), ...(mcp.mcpServers || {}) };
729
+ if (Object.keys(all).length === 0) return false;
730
+ return Object.keys(all).some(k => /context7/i.test(k));
723
731
  },
724
732
  impact: 'medium',
725
733
  rating: 4,
@@ -1171,11 +1179,14 @@ const TECHNIQUES = {
1171
1179
  name: 'At least one skill uses paths for scoping',
1172
1180
  check: (ctx) => {
1173
1181
  if (!ctx.hasDir('.claude/skills')) return null;
1174
- const files = ctx.dirFiles('.claude/skills');
1175
- if (files.length === 0) return null;
1176
- for (const f of files) {
1177
- const content = ctx.fileContent(`.claude/skills/${f}`) || '';
1178
- if (/paths:/i.test(content)) return true;
1182
+ const entries = ctx.dirFiles('.claude/skills');
1183
+ if (entries.length === 0) return null;
1184
+ for (const entry of entries) {
1185
+ // Skills can be files or dirs with SKILL.md inside
1186
+ const direct = ctx.fileContent(`.claude/skills/${entry}`) || '';
1187
+ if (/paths:/i.test(direct)) return true;
1188
+ const nested = ctx.fileContent(`.claude/skills/${entry}/SKILL.md`) || '';
1189
+ if (/paths:/i.test(nested)) return true;
1179
1190
  }
1180
1191
  return false;
1181
1192
  },