claudex-setup 1.10.3 → 1.11.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,21 @@
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.11.0] - 2026-04-03
19
+
20
+ ### Added
21
+ - `history` command — show score timeline from saved snapshots
22
+ - `compare` command — diff latest vs previous snapshot with delta, regressions, improvements
23
+ - `trend --out report.md` — export trend report as shareable markdown
24
+ - `--require A,B` CI flag — exit code 1 if named checks fail (policy guardrails)
25
+ - Agentic DX positioning in README
26
+ - Real results table (4 case studies) in README
27
+ - Claude-native integration guide (skill, hook, agent examples)
28
+ - Trust-first help text reordering
29
+
30
+ ### Fixed
31
+ - Hook checks (hooksInSettings, preToolUse, postToolUse, sessionStart) now OR across settings.json and settings.local.json
32
+
18
33
  ## [1.10.2] - 2026-04-02
19
34
 
20
35
  ### Fixed
package/README.md CHANGED
@@ -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
  ```
@@ -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.11.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.11.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
  };
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,