claudex-setup 1.10.3 → 1.12.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,32 @@
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.12.0] - 2026-04-03
19
+
20
+ ### Added
21
+ - 12 new checks (62→74): test coverage, agent tool restrictions, auto-memory, sandbox, deny rule depth, git attribution, effort level, snapshot history, worktree, negative instructions, output style, CI variants
22
+ - 8 new stacks (22→30): Deno, Bun, Elixir, Astro, Remix, NestJS, Laravel, .NET
23
+ - Deeper domain detection: llamaindex, crewai, autogen, ollama for AI/ML; paypal, square, adyen, medusa for ecommerce; chromatic, style-dictionary for design; capacitor, ionic for mobile
24
+
25
+ ### Fixed
26
+ - `githubActionsOrCI` check used non-existent `ctx.hasFile()` — now uses `ctx.fileContent()`
27
+ - `.NET` stack detection no longer uses glob patterns
28
+
29
+ ## [1.11.0] - 2026-04-03
30
+
31
+ ### Added
32
+ - `history` command — show score timeline from saved snapshots
33
+ - `compare` command — diff latest vs previous snapshot with delta, regressions, improvements
34
+ - `trend --out report.md` — export trend report as shareable markdown
35
+ - `--require A,B` CI flag — exit code 1 if named checks fail (policy guardrails)
36
+ - Agentic DX positioning in README
37
+ - Real results table (4 case studies) in README
38
+ - Claude-native integration guide (skill, hook, agent examples)
39
+ - Trust-first help text reordering
40
+
41
+ ### Fixed
42
+ - Hook checks (hooksInSettings, preToolUse, postToolUse, sessionStart) now OR across settings.json and settings.local.json
43
+
18
44
  ## [1.10.2] - 2026-04-02
19
45
 
20
46
  ### Fixed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # claudex-setup
2
2
 
3
- > Score your repo's Claude Code setup against 62 checks. See what's missing, apply only what you approve with rollback, and benchmark the impact — without breaking existing config.
3
+ > Score your repo's Claude Code setup against 74 checks. See what's missing, apply only what you approve with rollback, and benchmark the impact — without breaking existing config.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/claudex-setup)](https://www.npmjs.com/package/claudex-setup)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/claudex-setup)](https://www.npmjs.com/package/claudex-setup)
@@ -8,6 +8,7 @@
8
8
 
9
9
  ### What this is
10
10
 
11
+ - The **Agentic DX layer for Claude Code** — audit, improve, govern, and benchmark how Claude works with your repo
11
12
  - A **Claude Code workflow audit and improvement tool** — not an MCP installer, not a code generator
12
13
  - Scores your repo 0-100 across CLAUDE.md, hooks, commands, agents, skills, MCP, security, and more
13
14
  - Proposes changes as diffs you review — applies only what you approve, with rollback for every change
@@ -37,6 +38,19 @@ npx claudex-setup --threshold 60 # Fail CI if score is below 60
37
38
 
38
39
  No install. No config. No dependencies.
39
40
 
41
+ ## Real Results
42
+
43
+ Tested on 4 real projects — not demos:
44
+
45
+ | Project | Type | Before | After | Delta |
46
+ |---------|------|--------|-------|-------|
47
+ | CLAUDEX | Research engine, Python | 62 | 90 | **+28** |
48
+ | VTCLE | Marketing automation, FastAPI | 46 | 64 | **+18** |
49
+ | Social | Mobile app, React Native | 40 | 48 | **+8** |
50
+ | Polymiro | Prediction system, Python/Docker | 35 | 48 | **+13** |
51
+
52
+ Most common gaps found: missing secrets protection, no deny rules, no mermaid diagram, no hooks in settings.
53
+
40
54
  ## What You Get
41
55
 
42
56
  ```
@@ -75,7 +89,7 @@ No install. No config. No dependencies.
75
89
  design: none (0/2)
76
90
  devops: none (0/4)
77
91
 
78
- 29/62 checks passing
92
+ 29/74 checks passing
79
93
  Next command: npx claudex-setup setup
80
94
  ```
81
95
 
@@ -91,7 +105,7 @@ That prints a compact top-3 quick scan with one clear next command.
91
105
 
92
106
  | Command | What it does |
93
107
  |---------|-------------|
94
- | `npx claudex-setup` | **Discover** - Score 0-100 against 62 checks |
108
+ | `npx claudex-setup` | **Discover** - Score 0-100 against 74 checks |
95
109
  | `npx claudex-setup discover` | **Discover** - Alias for audit mode |
96
110
  | `npx claudex-setup setup` | **Starter** - Smart CLAUDE.md + hooks + commands + agents |
97
111
  | `npx claudex-setup starter` | **Starter** - Alias for setup mode |
@@ -291,7 +305,7 @@ jobs:
291
305
  runs-on: ubuntu-latest
292
306
  steps:
293
307
  - uses: actions/checkout@v4
294
- - uses: DnaFin/claudex-setup@v1.10.3
308
+ - uses: DnaFin/claudex-setup@v1.12.0
295
309
  with:
296
310
  threshold: 50
297
311
  ```
package/bin/cli.js CHANGED
@@ -19,7 +19,7 @@ const COMMAND_ALIASES = {
19
19
  suggest: 'suggest-only',
20
20
  gov: 'governance',
21
21
  };
22
- const KNOWN_COMMANDS = ['audit', 'setup', 'augment', 'suggest-only', 'plan', 'apply', 'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'badge', 'insights', 'help', 'version'];
22
+ const KNOWN_COMMANDS = ['audit', 'setup', 'augment', 'suggest-only', 'plan', 'apply', 'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'badge', 'insights', 'history', 'compare', 'trend', 'help', 'version'];
23
23
 
24
24
  function levenshtein(a, b) {
25
25
  const matrix = Array.from({ length: a.length + 1 }, () => Array(b.length + 1).fill(0));
@@ -61,12 +61,13 @@ function parseArgs(rawArgs) {
61
61
  let only = [];
62
62
  let profile = 'safe-write';
63
63
  let mcpPacks = [];
64
+ let requireChecks = [];
64
65
  let commandSet = false;
65
66
 
66
67
  for (let i = 0; i < rawArgs.length; i++) {
67
68
  const arg = rawArgs[i];
68
69
 
69
- if (arg === '--threshold' || arg === '--out' || arg === '--plan' || arg === '--only' || arg === '--profile' || arg === '--mcp-pack') {
70
+ if (arg === '--threshold' || arg === '--out' || arg === '--plan' || arg === '--only' || arg === '--profile' || arg === '--mcp-pack' || arg === '--require') {
70
71
  const value = rawArgs[i + 1];
71
72
  if (!value || value.startsWith('--')) {
72
73
  throw new Error(`${arg} requires a value`);
@@ -77,10 +78,16 @@ function parseArgs(rawArgs) {
77
78
  if (arg === '--only') only = value.split(',').map(item => item.trim()).filter(Boolean);
78
79
  if (arg === '--profile') profile = value.trim();
79
80
  if (arg === '--mcp-pack') mcpPacks = value.split(',').map(item => item.trim()).filter(Boolean);
81
+ if (arg === '--require') requireChecks = value.split(',').map(item => item.trim()).filter(Boolean);
80
82
  i++;
81
83
  continue;
82
84
  }
83
85
 
86
+ if (arg.startsWith('--require=')) {
87
+ requireChecks = arg.split('=').slice(1).join('=').split(',').map(item => item.trim()).filter(Boolean);
88
+ continue;
89
+ }
90
+
84
91
  if (arg.startsWith('--threshold=')) {
85
92
  threshold = arg.split('=')[1];
86
93
  continue;
@@ -124,35 +131,41 @@ function parseArgs(rawArgs) {
124
131
 
125
132
  const normalizedCommand = COMMAND_ALIASES[command] || command;
126
133
 
127
- return { flags, command, normalizedCommand, threshold, out, planFile, only, profile, mcpPacks };
134
+ return { flags, command, normalizedCommand, threshold, out, planFile, only, profile, mcpPacks, requireChecks };
128
135
  }
129
136
 
130
137
  const HELP = `
131
138
  claudex-setup v${version}
132
- Audit and optimize any project for Claude Code.
133
- Backed by CLAUDEX research and evidence.
134
-
135
- Usage:
136
- npx claudex-setup Run audit on current directory
137
- npx claudex-setup --lite Run the quick-scan beginner view
138
- npx claudex-setup discover Discover the highest-value improvements
139
- npx claudex-setup audit Same as above
140
- npx claudex-setup starter Alias for setup
141
- npx claudex-setup setup Apply recommended configuration
142
- npx claudex-setup setup --auto Apply all without prompts
143
- npx claudex-setup augment Repo-aware augment plan (no writes)
144
- npx claudex-setup suggest-only Structured suggestion report (no writes)
145
- npx claudex-setup plan Exportable proposal bundles with file previews
146
- npx claudex-setup apply Apply ready proposal bundles with rollback manifest
147
- npx claudex-setup governance Profiles, hooks, and pilot rollout guidance
148
- npx claudex-setup benchmark Measure before/after impact in an isolated temp copy
149
- npx claudex-setup deep-review AI-powered config review (uses Claude Code or API key)
139
+ Score your repo's Claude Code setup. Fix gaps safely. Benchmark the impact.
140
+
141
+ Start here (read-only, nothing changes):
142
+ npx claudex-setup Audit your project (10 seconds)
143
+ npx claudex-setup --lite Quick scan: top 3 gaps + next command
144
+ npx claudex-setup augment Repo-aware analysis, no writes
145
+ npx claudex-setup suggest-only Structured report, no writes
146
+
147
+ Plan and apply (when you're ready to change things):
148
+ npx claudex-setup plan Export proposal bundles with previews
149
+ npx claudex-setup apply Apply proposals selectively with rollback
150
+ npx claudex-setup setup Generate starter-safe baseline
151
+ npx claudex-setup setup --auto Apply all generated files without prompts
152
+
153
+ Track progress over time:
154
+ npx claudex-setup history Show score history from saved snapshots
155
+ npx claudex-setup compare Compare latest vs previous snapshot
156
+ npx claudex-setup trend --out r.md Export trend report as markdown
157
+
158
+ Advanced:
159
+ npx claudex-setup governance Permission profiles, hooks, policy packs
160
+ npx claudex-setup benchmark Before/after in isolated temp copy
161
+ npx claudex-setup deep-review AI-powered config review (opt-in, uses API)
150
162
  npx claudex-setup interactive Step-by-step guided wizard
151
- npx claudex-setup watch Monitor changes and re-audit live
163
+ npx claudex-setup watch Live monitoring on config changes
152
164
  npx claudex-setup badge Generate shields.io badge markdown
153
165
 
154
166
  Options:
155
167
  --threshold N Exit with code 1 if score is below N (useful for CI)
168
+ --require A,B Exit with code 1 if named checks fail (e.g. --require secretsProtection,permissionDeny)
156
169
  --out FILE Write JSON or markdown output to a file
157
170
  --plan FILE Load a previously exported plan file
158
171
  --only A,B Limit plan/apply to selected proposal ids or technique keys
@@ -227,6 +240,7 @@ async function main() {
227
240
  only: parsed.only,
228
241
  profile: parsed.profile,
229
242
  mcpPacks: parsed.mcpPacks,
243
+ require: parsed.requireChecks,
230
244
  dir: process.cwd()
231
245
  };
232
246
 
@@ -261,7 +275,48 @@ async function main() {
261
275
  }
262
276
 
263
277
  try {
264
- if (normalizedCommand === 'badge') {
278
+ if (normalizedCommand === 'history') {
279
+ const { formatHistory } = require('../src/activity');
280
+ console.log('');
281
+ console.log(formatHistory(options.dir));
282
+ console.log('');
283
+ process.exit(0);
284
+ } else if (normalizedCommand === 'compare') {
285
+ const { compareLatest } = require('../src/activity');
286
+ const result = compareLatest(options.dir);
287
+ if (!result) {
288
+ console.log('\n Need at least 2 snapshots to compare. Run `npx claudex-setup --snapshot` twice.\n');
289
+ process.exit(0);
290
+ }
291
+ if (options.json) {
292
+ console.log(JSON.stringify(result, null, 2));
293
+ } else {
294
+ const sign = result.delta.score >= 0 ? '+' : '';
295
+ console.log('');
296
+ console.log(` Previous: ${result.previous.score}/100 (${result.previous.date?.split('T')[0]})`);
297
+ console.log(` Current: ${result.current.score}/100 (${result.current.date?.split('T')[0]})`);
298
+ console.log(` Delta: ${sign}${result.delta.score} points`);
299
+ console.log(` Trend: ${result.trend}`);
300
+ if (result.improvements.length > 0) console.log(` Fixed: ${result.improvements.join(', ')}`);
301
+ if (result.regressions.length > 0) console.log(` New gaps: ${result.regressions.join(', ')}`);
302
+ console.log('');
303
+ }
304
+ process.exit(0);
305
+ } else if (normalizedCommand === 'trend') {
306
+ const { exportTrendReport } = require('../src/activity');
307
+ const report = exportTrendReport(options.dir);
308
+ if (!report) {
309
+ console.log('\n No snapshots found. Run `npx claudex-setup --snapshot` to start tracking.\n');
310
+ process.exit(0);
311
+ }
312
+ if (options.out) {
313
+ require('fs').writeFileSync(options.out, report, 'utf8');
314
+ console.log(`\n Trend report exported to ${options.out}\n`);
315
+ } else {
316
+ console.log(report);
317
+ }
318
+ process.exit(0);
319
+ } else if (normalizedCommand === 'badge') {
265
320
  const { getBadgeMarkdown } = require('../src/badge');
266
321
  const result = await audit({ ...options, silent: true });
267
322
  console.log(getBadgeMarkdown(result.score));
@@ -406,6 +461,19 @@ async function main() {
406
461
  }
407
462
  process.exit(1);
408
463
  }
464
+ if (options.require && options.require.length > 0) {
465
+ const failedRequired = options.require.filter(key => {
466
+ const check = result.results.find(r => r.key === key);
467
+ return !check || check.passed !== true;
468
+ });
469
+ if (failedRequired.length > 0) {
470
+ if (!options.json) {
471
+ console.error(`\n Required checks failed: ${failedRequired.join(', ')}`);
472
+ console.error(' These must pass for CI to succeed.\n');
473
+ }
474
+ process.exit(1);
475
+ }
476
+ }
409
477
  }
410
478
  } catch (err) {
411
479
  console.error(`\n Error: ${err.message}`);
@@ -0,0 +1,64 @@
1
+ # Using claudex-setup from inside Claude Code
2
+
3
+ ## Skill: Audit Repo
4
+
5
+ Add this to `.claude/skills/audit-repo.md` in any project:
6
+
7
+ ```markdown
8
+ ---
9
+ name: audit-repo
10
+ description: Run claudex-setup audit on the current project and show score + top gaps
11
+ ---
12
+
13
+ Run `npx claudex-setup --json` on the current project directory.
14
+ Parse the JSON output and present:
15
+ 1. Score X/100
16
+ 2. Top 3 critical/high gaps with fix descriptions
17
+ 3. Suggest next command based on score
18
+
19
+ $ARGUMENTS — optional: --lite for quick scan
20
+ ```
21
+
22
+ ## Hook: Auto-audit on SessionStart
23
+
24
+ Add to `.claude/settings.json`:
25
+
26
+ ```json
27
+ {
28
+ "hooks": {
29
+ "SessionStart": [
30
+ {
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "node -e \"try{const r=require('child_process').execSync('npx claudex-setup --json 2>/dev/null',{timeout:15000}).toString();const d=JSON.parse(r);if(d.score<50)console.log(JSON.stringify({systemMessage:'⚠️ Claude Code setup score: '+d.score+'/100. Consider running: npx claudex-setup --lite'}))}catch(e){console.log('{}')}\"",
35
+ "timeout": 20,
36
+ "statusMessage": "Checking Claude Code setup..."
37
+ }
38
+ ]
39
+ }
40
+ ]
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Agent: Setup Advisor
46
+
47
+ Add to `.claude/agents/setup-advisor.md`:
48
+
49
+ ```markdown
50
+ ---
51
+ name: setup-advisor
52
+ description: Analyzes Claude Code setup and recommends improvements
53
+ tools: [Bash, Read, Glob, Grep]
54
+ model: haiku
55
+ maxTurns: 10
56
+ ---
57
+
58
+ You are a Claude Code setup advisor.
59
+
60
+ 1. Run `npx claudex-setup augment --json` on the current project
61
+ 2. Analyze gaps and strengths
62
+ 3. Recommend top 5 improvements with rationale
63
+ 4. If user approves, guide them through applying changes
64
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudex-setup",
3
- "version": "1.10.3",
3
+ "version": "1.12.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/activity.js CHANGED
@@ -163,9 +163,139 @@ function writeSnapshotArtifact(dir, snapshotKind, payload, meta = {}) {
163
163
  };
164
164
  }
165
165
 
166
+ function readSnapshotIndex(dir) {
167
+ const indexPath = path.join(dir, '.claude', 'claudex-setup', 'snapshots', 'index.json');
168
+ if (!fs.existsSync(indexPath)) return [];
169
+ try {
170
+ const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
171
+ return Array.isArray(entries) ? entries : [];
172
+ } catch {
173
+ return [];
174
+ }
175
+ }
176
+
177
+ function getHistory(dir, limit = 20) {
178
+ const entries = readSnapshotIndex(dir);
179
+ return entries
180
+ .filter(e => e.snapshotKind === 'audit')
181
+ .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
182
+ .slice(0, limit);
183
+ }
184
+
185
+ function compareLatest(dir) {
186
+ const audits = getHistory(dir, 2);
187
+ if (audits.length < 2) return null;
188
+
189
+ const current = audits[0];
190
+ const previous = audits[1];
191
+
192
+ const delta = {
193
+ score: (current.summary?.score || 0) - (previous.summary?.score || 0),
194
+ organic: (current.summary?.organicScore || 0) - (previous.summary?.organicScore || 0),
195
+ passed: (current.summary?.passed || 0) - (previous.summary?.passed || 0),
196
+ };
197
+
198
+ const regressions = [];
199
+ const improvements = [];
200
+
201
+ const prevKeys = new Set(previous.summary?.topActionKeys || []);
202
+ const currKeys = new Set(current.summary?.topActionKeys || []);
203
+
204
+ for (const key of currKeys) {
205
+ if (!prevKeys.has(key)) regressions.push(key);
206
+ }
207
+ for (const key of prevKeys) {
208
+ if (!currKeys.has(key)) improvements.push(key);
209
+ }
210
+
211
+ return {
212
+ current: { date: current.createdAt, score: current.summary?.score, passed: current.summary?.passed },
213
+ previous: { date: previous.createdAt, score: previous.summary?.score, passed: previous.summary?.passed },
214
+ delta,
215
+ regressions,
216
+ improvements,
217
+ trend: delta.score > 0 ? 'improving' : delta.score < 0 ? 'regressing' : 'stable',
218
+ };
219
+ }
220
+
221
+ function formatHistory(dir) {
222
+ const history = getHistory(dir, 10);
223
+ if (history.length === 0) return 'No snapshots found. Run `npx claudex-setup --snapshot` to save one.';
224
+
225
+ const lines = ['Score history (most recent first):', ''];
226
+ for (const entry of history) {
227
+ const date = entry.createdAt?.split('T')[0] || 'unknown';
228
+ const score = entry.summary?.score ?? '?';
229
+ const passed = entry.summary?.passed ?? '?';
230
+ const total = entry.summary?.checkCount ?? '?';
231
+ lines.push(` ${date} ${score}/100 (${passed}/${total} passing)`);
232
+ }
233
+
234
+ const comparison = compareLatest(dir);
235
+ if (comparison) {
236
+ lines.push('');
237
+ const sign = comparison.delta.score >= 0 ? '+' : '';
238
+ lines.push(` Trend: ${comparison.trend} (${sign}${comparison.delta.score} since previous)`);
239
+ if (comparison.improvements.length > 0) {
240
+ lines.push(` Fixed: ${comparison.improvements.join(', ')}`);
241
+ }
242
+ if (comparison.regressions.length > 0) {
243
+ lines.push(` New gaps: ${comparison.regressions.join(', ')}`);
244
+ }
245
+ }
246
+
247
+ return lines.join('\n');
248
+ }
249
+
250
+ function exportTrendReport(dir) {
251
+ const history = getHistory(dir, 50);
252
+ if (history.length === 0) return null;
253
+
254
+ const comparison = compareLatest(dir);
255
+ const lines = [
256
+ '# Claude Code Setup Trend Report',
257
+ '',
258
+ `**Project:** ${path.basename(dir)}`,
259
+ `**Generated:** ${new Date().toISOString().split('T')[0]}`,
260
+ `**Snapshots:** ${history.length}`,
261
+ '',
262
+ '## Score History',
263
+ '',
264
+ '| Date | Score | Passed | Checks |',
265
+ '|------|-------|--------|--------|',
266
+ ];
267
+
268
+ for (const entry of history) {
269
+ const date = entry.createdAt?.split('T')[0] || '?';
270
+ lines.push(`| ${date} | ${entry.summary?.score ?? '?'}/100 | ${entry.summary?.passed ?? '?'} | ${entry.summary?.checkCount ?? '?'} |`);
271
+ }
272
+
273
+ if (comparison) {
274
+ lines.push('');
275
+ lines.push('## Latest Comparison');
276
+ lines.push('');
277
+ lines.push(`- **Previous:** ${comparison.previous.score}/100 (${comparison.previous.date?.split('T')[0]})`);
278
+ lines.push(`- **Current:** ${comparison.current.score}/100 (${comparison.current.date?.split('T')[0]})`);
279
+ lines.push(`- **Delta:** ${comparison.delta.score >= 0 ? '+' : ''}${comparison.delta.score} points`);
280
+ lines.push(`- **Trend:** ${comparison.trend}`);
281
+ if (comparison.improvements.length > 0) lines.push(`- **Fixed:** ${comparison.improvements.join(', ')}`);
282
+ if (comparison.regressions.length > 0) lines.push(`- **New gaps:** ${comparison.regressions.join(', ')}`);
283
+ }
284
+
285
+ lines.push('');
286
+ lines.push(`---`);
287
+ lines.push(`*Generated by claudex-setup v${version}*`);
288
+ return lines.join('\n');
289
+ }
290
+
166
291
  module.exports = {
167
292
  ensureArtifactDirs,
168
293
  writeActivityArtifact,
169
294
  writeRollbackArtifact,
170
295
  writeSnapshotArtifact,
296
+ readSnapshotIndex,
297
+ getHistory,
298
+ compareLatest,
299
+ formatHistory,
300
+ exportTrendReport,
171
301
  };
@@ -231,6 +231,7 @@ function detectDomainPacks(ctx, stacks, assets = null) {
231
231
 
232
232
  // Mobile detection
233
233
  const isMobile = deps['react-native'] || deps.expo || deps.flutter ||
234
+ deps['@capacitor/core'] || deps['@ionic/angular'] || deps['@ionic/react'] ||
234
235
  ctx.files.includes('Podfile') || ctx.files.includes('build.gradle') ||
235
236
  ctx.files.includes('build.gradle.kts') || ctx.hasDir('ios') || ctx.hasDir('android');
236
237
  if (isMobile) {
@@ -257,7 +258,9 @@ function detectDomainPacks(ctx, stacks, assets = null) {
257
258
 
258
259
  // E-commerce detection
259
260
  const isEcommerce = deps.stripe || deps['@stripe/stripe-js'] || deps.shopify || deps['@shopify/shopify-api'] ||
260
- deps.woocommerce || ctx.hasDir('products') || ctx.hasDir('checkout') || ctx.hasDir('cart');
261
+ deps.woocommerce || deps.paypal || deps['@paypal/react-paypal-js'] || deps.square || deps['@adyen/adyen-web'] ||
262
+ deps.medusa || deps.saleor ||
263
+ ctx.hasDir('products') || ctx.hasDir('checkout') || ctx.hasDir('cart');
261
264
  if (isEcommerce) {
262
265
  addMatch('ecommerce', [
263
266
  'Detected e-commerce dependencies or storefront structure.',
@@ -269,6 +272,8 @@ function detectDomainPacks(ctx, stacks, assets = null) {
269
272
  // AI/ML detection
270
273
  const isAiMl = deps.langchain || deps['@langchain/core'] || deps.openai || deps.anthropic ||
271
274
  deps['@anthropic-ai/sdk'] || deps.transformers || deps.torch || deps.tensorflow ||
275
+ deps.llamaindex || deps['llama-index'] || deps.crewai || deps.autogen ||
276
+ deps['@ai-sdk/core'] || deps.ollama ||
272
277
  ctx.hasDir('chains') || ctx.hasDir('agents') || ctx.hasDir('models') || ctx.hasDir('prompts');
273
278
  if (isAiMl && !hasData) {
274
279
  addMatch('ai-ml', [
@@ -292,8 +297,9 @@ function detectDomainPacks(ctx, stacks, assets = null) {
292
297
 
293
298
  // Design system detection
294
299
  const isDesignSystem = deps.storybook || deps['@storybook/react'] || deps['@storybook/vue3'] ||
300
+ deps.chromatic || deps['style-dictionary'] || deps['@tokens-studio/sd-transforms'] ||
295
301
  ctx.hasDir('tokens') || ctx.hasDir('design-tokens') ||
296
- (ctx.hasDir('components') && ctx.hasDir('.storybook'));
302
+ ctx.hasDir('.storybook') || (ctx.hasDir('components') && ctx.hasDir('.storybook'));
297
303
  if (isDesignSystem) {
298
304
  addMatch('design-system', [
299
305
  'Detected design system or component library signals.',
package/src/techniques.js CHANGED
@@ -425,9 +425,11 @@ const TECHNIQUES = {
425
425
  id: 8801,
426
426
  name: 'Hooks configured in settings',
427
427
  check: (ctx) => {
428
- const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
429
- if (!settings || !settings.hooks) return false;
430
- return Object.keys(settings.hooks).length > 0;
428
+ const shared = ctx.jsonFile('.claude/settings.json');
429
+ const local = ctx.jsonFile('.claude/settings.local.json');
430
+ const hasSharedHooks = shared && shared.hooks && Object.keys(shared.hooks).length > 0;
431
+ const hasLocalHooks = local && local.hooks && Object.keys(local.hooks).length > 0;
432
+ return hasSharedHooks || hasLocalHooks;
431
433
  },
432
434
  impact: 'high',
433
435
  rating: 4,
@@ -440,9 +442,9 @@ const TECHNIQUES = {
440
442
  id: 8802,
441
443
  name: 'PreToolUse hook configured',
442
444
  check: (ctx) => {
443
- const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
444
- if (!settings || !settings.hooks) return false;
445
- return !!settings.hooks.PreToolUse;
445
+ const shared = ctx.jsonFile('.claude/settings.json');
446
+ const local = ctx.jsonFile('.claude/settings.local.json');
447
+ return !!(shared?.hooks?.PreToolUse || local?.hooks?.PreToolUse);
446
448
  },
447
449
  impact: 'high',
448
450
  rating: 4,
@@ -455,9 +457,9 @@ const TECHNIQUES = {
455
457
  id: 8803,
456
458
  name: 'PostToolUse hook configured',
457
459
  check: (ctx) => {
458
- const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
459
- if (!settings || !settings.hooks) return false;
460
- return !!settings.hooks.PostToolUse;
460
+ const shared = ctx.jsonFile('.claude/settings.json');
461
+ const local = ctx.jsonFile('.claude/settings.local.json');
462
+ return !!(shared?.hooks?.PostToolUse || local?.hooks?.PostToolUse);
461
463
  },
462
464
  impact: 'high',
463
465
  rating: 4,
@@ -470,9 +472,10 @@ const TECHNIQUES = {
470
472
  id: 8804,
471
473
  name: 'SessionStart hook configured',
472
474
  check: (ctx) => {
473
- const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
474
- if (!settings || !settings.hooks) return false;
475
- return !!settings.hooks.SessionStart;
475
+ const shared = ctx.jsonFile('.claude/settings.json');
476
+ const local = ctx.jsonFile('.claude/settings.local.json');
477
+ if (!(shared?.hooks || local?.hooks)) return false;
478
+ return !!(shared?.hooks?.SessionStart || local?.hooks?.SessionStart);
476
479
  },
477
480
  impact: 'medium',
478
481
  rating: 4,
@@ -943,6 +946,174 @@ const TECHNIQUES = {
943
946
  template: null
944
947
  },
945
948
 
949
+ // --- New checks: testing depth ---
950
+ testCoverage: {
951
+ id: 2010,
952
+ name: 'Test coverage or strategy mentioned',
953
+ check: (ctx) => {
954
+ const md = ctx.fileContent('CLAUDE.md') || '';
955
+ return /coverage|test.*strateg|e2e|integration test|unit test/i.test(md);
956
+ },
957
+ impact: 'medium', rating: 3, category: 'quality',
958
+ fix: 'Mention your testing strategy in CLAUDE.md (unit, integration, E2E, coverage targets).',
959
+ template: null
960
+ },
961
+
962
+ // --- New checks: agent depth ---
963
+ agentHasAllowedTools: {
964
+ id: 2011,
965
+ name: 'At least one agent restricts tools',
966
+ check: (ctx) => {
967
+ if (!ctx.hasDir('.claude/agents')) return null;
968
+ const files = ctx.dirFiles('.claude/agents');
969
+ if (files.length === 0) return null;
970
+ for (const f of files) {
971
+ const content = ctx.fileContent(`.claude/agents/${f}`) || '';
972
+ if (/tools:\s*\[/.test(content)) return true;
973
+ }
974
+ return false;
975
+ },
976
+ impact: 'medium', rating: 3, category: 'workflow',
977
+ fix: 'Add a tools restriction to agent frontmatter (e.g. tools: [Read, Grep]) for safer delegation.',
978
+ template: null
979
+ },
980
+
981
+ // --- New checks: memory / auto-memory ---
982
+ autoMemoryAwareness: {
983
+ id: 2012,
984
+ name: 'Auto-memory or memory management mentioned',
985
+ check: (ctx) => {
986
+ const md = ctx.fileContent('CLAUDE.md') || '';
987
+ return /auto.?memory|memory.*manage|remember|persistent.*context/i.test(md);
988
+ },
989
+ impact: 'low', rating: 3, category: 'memory',
990
+ fix: 'Claude Code supports auto-memory for cross-session learning. Mention your memory strategy if relevant.',
991
+ template: null
992
+ },
993
+
994
+ // --- New checks: sandbox / security depth ---
995
+ sandboxAwareness: {
996
+ id: 2013,
997
+ name: 'Sandbox or isolation mentioned',
998
+ check: (ctx) => {
999
+ const md = ctx.fileContent('CLAUDE.md') || '';
1000
+ const settings = ctx.jsonFile('.claude/settings.json') || {};
1001
+ return /sandbox|isolat/i.test(md) || !!settings.sandbox;
1002
+ },
1003
+ impact: 'medium', rating: 3, category: 'security',
1004
+ fix: 'Claude Code supports sandboxed command execution. Consider enabling it for untrusted operations.',
1005
+ template: null
1006
+ },
1007
+
1008
+ denyRulesDepth: {
1009
+ id: 2014,
1010
+ name: 'Deny rules cover 3+ patterns',
1011
+ check: (ctx) => {
1012
+ const shared = ctx.jsonFile('.claude/settings.json');
1013
+ const local = ctx.jsonFile('.claude/settings.local.json');
1014
+ const deny = (shared?.permissions?.deny || []).concat(local?.permissions?.deny || []);
1015
+ return deny.length >= 3;
1016
+ },
1017
+ impact: 'high', rating: 4, category: 'security',
1018
+ fix: 'Add at least 3 deny rules: rm -rf, force-push, and .env reads. More patterns = safer Claude.',
1019
+ template: null
1020
+ },
1021
+
1022
+ // --- New checks: git depth ---
1023
+ gitAttributionDecision: {
1024
+ id: 2015,
1025
+ name: 'Git attribution configured',
1026
+ check: (ctx) => {
1027
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1028
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1029
+ return shared.attribution !== undefined || local.attribution !== undefined ||
1030
+ shared.includeCoAuthoredBy !== undefined || local.includeCoAuthoredBy !== undefined;
1031
+ },
1032
+ impact: 'low', rating: 3, category: 'git',
1033
+ fix: 'Decide on git attribution: set attribution.commit or includeCoAuthoredBy in settings.',
1034
+ template: null
1035
+ },
1036
+
1037
+ // --- New checks: performance ---
1038
+ effortLevelConfigured: {
1039
+ id: 2016,
1040
+ name: 'Effort level or thinking configuration',
1041
+ check: (ctx) => {
1042
+ const md = ctx.fileContent('CLAUDE.md') || '';
1043
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1044
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1045
+ return /effort|thinking/i.test(md) || shared.effortLevel || local.effortLevel ||
1046
+ shared.alwaysThinkingEnabled !== undefined || local.alwaysThinkingEnabled !== undefined;
1047
+ },
1048
+ impact: 'low', rating: 3, category: 'performance',
1049
+ fix: 'Configure effortLevel or mention thinking strategy in CLAUDE.md for task-appropriate reasoning depth.',
1050
+ template: null
1051
+ },
1052
+
1053
+ // --- New checks: workflow depth ---
1054
+ hasSnapshotHistory: {
1055
+ id: 2017,
1056
+ name: 'Audit snapshot history exists',
1057
+ check: (ctx) => {
1058
+ return !!ctx.fileContent('.claude/claudex-setup/snapshots/index.json');
1059
+ },
1060
+ impact: 'low', rating: 3, category: 'workflow',
1061
+ fix: 'Run `npx claudex-setup --snapshot` to start tracking your setup score over time.',
1062
+ template: null
1063
+ },
1064
+
1065
+ worktreeAwareness: {
1066
+ id: 2018,
1067
+ name: 'Worktree or parallel sessions mentioned',
1068
+ check: (ctx) => {
1069
+ const md = ctx.fileContent('CLAUDE.md') || '';
1070
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1071
+ return /worktree|parallel.*session/i.test(md) || !!shared.worktree;
1072
+ },
1073
+ impact: 'low', rating: 3, category: 'features',
1074
+ fix: 'Claude Code supports git worktrees for parallel isolated sessions. Mention if relevant.',
1075
+ template: null
1076
+ },
1077
+
1078
+ // --- New checks: prompting depth ---
1079
+ negativeInstructions: {
1080
+ id: 2019,
1081
+ name: 'CLAUDE.md includes "do not" instructions',
1082
+ check: (ctx) => {
1083
+ const md = ctx.fileContent('CLAUDE.md') || '';
1084
+ return /do not|don't|never|avoid|must not/i.test(md);
1085
+ },
1086
+ impact: 'medium', rating: 4, category: 'prompting',
1087
+ fix: 'Add explicit "do not" rules to CLAUDE.md. Negative constraints reduce common mistakes.',
1088
+ template: null
1089
+ },
1090
+
1091
+ outputStyleGuidance: {
1092
+ id: 2020,
1093
+ name: 'CLAUDE.md includes output or style guidance',
1094
+ check: (ctx) => {
1095
+ const md = ctx.fileContent('CLAUDE.md') || '';
1096
+ return /style|format|convention|naming|pattern|prefer/i.test(md);
1097
+ },
1098
+ impact: 'medium', rating: 3, category: 'prompting',
1099
+ fix: 'Add coding style and naming conventions to CLAUDE.md so Claude matches your project patterns.',
1100
+ template: null
1101
+ },
1102
+
1103
+ // --- New checks: devops depth ---
1104
+ githubActionsOrCI: {
1105
+ id: 2021,
1106
+ name: 'GitHub Actions or CI configured',
1107
+ check: (ctx) => {
1108
+ return ctx.hasDir('.github/workflows') || !!ctx.fileContent('.circleci/config.yml') ||
1109
+ !!ctx.fileContent('.gitlab-ci.yml') || !!ctx.fileContent('Jenkinsfile') ||
1110
+ !!ctx.fileContent('.travis.yml') || !!ctx.fileContent('bitbucket-pipelines.yml');
1111
+ },
1112
+ impact: 'medium', rating: 3, category: 'devops',
1113
+ fix: 'Add CI pipeline for automated testing. Claude Code has a GitHub Action for audit gates.',
1114
+ template: null
1115
+ },
1116
+
946
1117
  noDeprecatedPatterns: {
947
1118
  id: 2009,
948
1119
  name: 'No deprecated patterns detected',
@@ -989,6 +1160,14 @@ const STACKS = {
989
1160
  kubernetes: { files: ['k8s', 'kubernetes', 'helm'], content: {}, label: 'Kubernetes' },
990
1161
  cpp: { files: ['CMakeLists.txt', 'Makefile', '.clang-format'], content: {}, label: 'C++' },
991
1162
  bazel: { files: ['BUILD', 'WORKSPACE', 'BUILD.bazel', 'WORKSPACE.bazel'], content: {}, label: 'Bazel' },
1163
+ deno: { files: ['deno.json', 'deno.jsonc', 'deno.lock'], content: {}, label: 'Deno' },
1164
+ bun: { files: ['bun.lockb', 'bunfig.toml'], content: {}, label: 'Bun' },
1165
+ elixir: { files: ['mix.exs'], content: {}, label: 'Elixir' },
1166
+ astro: { files: ['astro.config.mjs', 'astro.config.ts'], content: {}, label: 'Astro' },
1167
+ remix: { files: ['remix.config.js', 'remix.config.ts'], content: {}, label: 'Remix' },
1168
+ nestjs: { files: ['nest-cli.json'], content: {}, label: 'NestJS' },
1169
+ laravel: { files: ['artisan'], content: {}, label: 'Laravel' },
1170
+ dotnet: { files: ['global.json', 'Directory.Build.props'], content: {}, label: '.NET' },
992
1171
  };
993
1172
 
994
1173
  module.exports = { TECHNIQUES, STACKS };