claudex-setup 1.15.1 → 1.16.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/README.md CHANGED
@@ -51,6 +51,8 @@ Tested on 4 real projects — not demos:
51
51
 
52
52
  Most common gaps found: missing secrets protection, no deny rules, no mermaid diagram, no hooks in settings.
53
53
 
54
+ > Scores measured with claudex-setup@1.10.3 on 2026-04-03. Full case studies: [VTCLE](https://github.com/DnaFin/claudex/blob/main/research/case-study-vtcle-2026-04-03.md) | [Social](https://github.com/DnaFin/claudex/blob/main/research/case-study-social-2026-04-03.md) | [Polymiro](https://github.com/DnaFin/claudex/blob/main/research/case-study-polymiro-2026-04-03.md)
55
+
54
56
  ## What You Get
55
57
 
56
58
  ```
@@ -259,7 +261,7 @@ If you are using `npx` only, copy the same file from the GitHub repo at `content
259
261
 
260
262
  The skill runs `npx claudex-setup --json`, summarizes the score, shows the top next actions, and points to the right next command without applying changes.
261
263
 
262
- ## 62 Checks Across 14 Categories
264
+ ## 84 Checks Across 14 Categories
263
265
 
264
266
  The exact applicable count can be lower on a given repo because stack-specific checks are skipped when they do not apply.
265
267
 
@@ -268,30 +270,30 @@ The exact applicable count can be lower on a given repo because stack-specific c
268
270
  | Memory | 8 | CLAUDE.md, architecture, conventions |
269
271
  | Quality | 7 | verification loops, self-correction |
270
272
  | Git Safety | 5 | hooks, force-push protection |
271
- | Workflow | 6 | commands, skills, rules, agents |
272
- | Security | 5 | permissions, secrets, deny rules |
273
+ | Workflow | 8 | commands, skills, rules, agents |
274
+ | Security | 6 | permissions, secrets, deny rules |
273
275
  | Automation | 5 | PreToolUse, PostToolUse, SessionStart |
274
276
  | Design | 4 | Mermaid, XML tags, structured prompts |
275
- | DevOps | 4 | Docker, CI, Terraform, K8s |
276
- | Hygiene | 6 | .gitignore, cleanup, structure |
277
+ | DevOps | 6 | Docker, CI, Terraform, K8s, pipelines |
278
+ | Hygiene | 7 | .gitignore, cleanup, structure |
277
279
  | Performance | 3 | context management, compaction |
278
280
  | MCP | 3 | servers, Context7, integrations |
279
- | Prompting | 3 | constraints, validation, patterns |
280
- | Features | 2 | /security-review, Channels |
281
- | **Quality Deep** | **9** | **freshness, contradictions, deprecated patterns, maxTurns, $ARGUMENTS** |
281
+ | Prompting | 5 | constraints, validation, patterns, style |
282
+ | Features | 3 | /security-review, Channels, modern features |
283
+ | **Quality Deep** | **14** | **freshness, contradictions, deprecated patterns, maxTurns, $ARGUMENTS, hook specificity** |
282
284
 
283
285
  ## Stack Detection
284
286
 
285
- Auto-detects and tailors output for 22 stacks:
287
+ Auto-detects and tailors output for 30 stacks:
286
288
 
287
289
  | | |
288
290
  |--|--|
289
- | **Frontend** | React, Vue, Angular, Next.js, Svelte |
290
- | **Backend** | Node.js, Python, Django, FastAPI |
291
- | **Mobile** | Flutter, Swift, Kotlin |
292
- | **Systems** | Rust, Go, Java, Ruby, C++, Bazel |
291
+ | **Frontend** | React, Vue, Angular, Next.js, Svelte, Astro |
292
+ | **Backend** | Node.js, Python, Django, FastAPI, Express, NestJS, Spring Boot |
293
+ | **Mobile** | React Native, Expo, Flutter, Swift, Kotlin |
294
+ | **Systems** | Rust, Go, Java, Ruby, C++, Bazel, Deno, Bun |
293
295
  | **Language** | TypeScript |
294
- | **Infra** | Docker, Terraform, Kubernetes |
296
+ | **Infra** | Docker, Terraform, Kubernetes, Wrangler |
295
297
 
296
298
  ## GitHub Action
297
299
 
@@ -305,7 +307,7 @@ jobs:
305
307
  runs-on: ubuntu-latest
306
308
  steps:
307
309
  - uses: actions/checkout@v4
308
- - uses: DnaFin/claudex-setup@v1.14.0
310
+ - uses: DnaFin/claudex-setup@v1.15.1
309
311
  with:
310
312
  threshold: 50
311
313
  ```
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', 'history', 'compare', 'trend', 'help', 'version'];
22
+ const KNOWN_COMMANDS = ['audit', 'setup', 'augment', 'suggest-only', 'plan', 'apply', 'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'badge', 'insights', 'history', 'compare', 'trend', 'scan', '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));
@@ -63,6 +63,7 @@ function parseArgs(rawArgs) {
63
63
  let mcpPacks = [];
64
64
  let requireChecks = [];
65
65
  let commandSet = false;
66
+ let extraArgs = [];
66
67
 
67
68
  for (let i = 0; i < rawArgs.length; i++) {
68
69
  const arg = rawArgs[i];
@@ -126,12 +127,14 @@ function parseArgs(rawArgs) {
126
127
  if (!commandSet) {
127
128
  command = arg;
128
129
  commandSet = true;
130
+ } else {
131
+ extraArgs.push(arg);
129
132
  }
130
133
  }
131
134
 
132
135
  const normalizedCommand = COMMAND_ALIASES[command] || command;
133
136
 
134
- return { flags, command, normalizedCommand, threshold, out, planFile, only, profile, mcpPacks, requireChecks };
137
+ return { flags, command, normalizedCommand, threshold, out, planFile, only, profile, mcpPacks, requireChecks, extraArgs };
135
138
  }
136
139
 
137
140
  const HELP = `
@@ -155,6 +158,9 @@ const HELP = `
155
158
  npx claudex-setup compare Compare latest vs previous snapshot
156
159
  npx claudex-setup trend --out r.md Export trend report as markdown
157
160
 
161
+ Multi-repo:
162
+ npx claudex-setup scan dir1 dir2 Compare multiple repos side-by-side
163
+
158
164
  Advanced:
159
165
  npx claudex-setup governance Permission profiles, hooks, policy packs
160
166
  npx claudex-setup benchmark Before/after in isolated temp copy
@@ -249,7 +255,7 @@ async function main() {
249
255
  process.exit(1);
250
256
  }
251
257
 
252
- if (options.require && normalizedCommand !== 'audit' && !['audit', 'discover'].includes(command)) {
258
+ if (options.require && options.require.length > 0 && normalizedCommand !== 'audit' && !['audit', 'discover'].includes(command)) {
253
259
  console.error(`\n Warning: --require is only supported with the audit command. Ignoring for '${normalizedCommand}'.\n`);
254
260
  }
255
261
 
@@ -279,7 +285,74 @@ async function main() {
279
285
  }
280
286
 
281
287
  try {
282
- if (normalizedCommand === 'history') {
288
+ if (normalizedCommand === 'scan') {
289
+ const scanDirs = parsed.extraArgs;
290
+ if (scanDirs.length === 0) {
291
+ console.error('\n Error: scan requires at least one directory argument.');
292
+ console.error(' Usage: npx claudex-setup scan dir1 dir2 dir3\n');
293
+ process.exit(1);
294
+ }
295
+ const fs = require('fs');
296
+ const pathMod = require('path');
297
+ const rows = [];
298
+ for (const rawDir of scanDirs) {
299
+ const dir = pathMod.resolve(rawDir);
300
+ if (!fs.existsSync(dir)) {
301
+ rows.push({ name: pathMod.basename(rawDir), dir: rawDir, score: null, passed: '-', failed: '-', suggested: '-', error: 'directory not found' });
302
+ continue;
303
+ }
304
+ try {
305
+ const result = await audit({ dir, silent: true });
306
+ rows.push({
307
+ name: pathMod.basename(dir),
308
+ dir: rawDir,
309
+ score: result.score,
310
+ passed: result.passed,
311
+ failed: result.failed,
312
+ suggested: result.suggestedNextCommand || '-',
313
+ error: null,
314
+ });
315
+ } catch (err) {
316
+ rows.push({ name: pathMod.basename(dir), dir: rawDir, score: null, passed: '-', failed: '-', suggested: '-', error: err.message });
317
+ }
318
+ }
319
+
320
+ if (options.json) {
321
+ console.log(JSON.stringify(rows, null, 2));
322
+ } else {
323
+ // Find weakest
324
+ const validRows = rows.filter(r => r.score !== null);
325
+ const minScore = validRows.length > 0 ? Math.min(...validRows.map(r => r.score)) : null;
326
+ const weakest = validRows.length > 1 && validRows.filter(r => r.score > minScore).length > 0
327
+ ? validRows.find(r => r.score === minScore)
328
+ : null;
329
+
330
+ console.log('');
331
+ console.log('\x1b[1m claudex-setup multi-repo scan\x1b[0m');
332
+ console.log('\x1b[2m ═══════════════════════════════════════\x1b[0m');
333
+ console.log('');
334
+
335
+ // Table header
336
+ const nameW = Math.max(8, ...rows.map(r => r.name.length)) + 2;
337
+ const header = ` ${'Project'.padEnd(nameW)} ${'Score'.padStart(5)} ${'Pass'.padStart(4)} ${'Fail'.padStart(4)} Suggested Command`;
338
+ console.log('\x1b[1m' + header + '\x1b[0m');
339
+ console.log(' ' + '─'.repeat(header.trim().length));
340
+
341
+ for (const row of rows) {
342
+ if (row.error) {
343
+ console.log(` ${row.name.padEnd(nameW)} \x1b[31m${('ERR').padStart(5)}\x1b[0m ${String(row.passed).padStart(4)} ${String(row.failed).padStart(4)} ${row.error}`);
344
+ continue;
345
+ }
346
+ const isWeak = weakest && row.name === weakest.name && row.dir === weakest.dir;
347
+ const scoreColor = row.score >= 70 ? '\x1b[32m' : row.score >= 40 ? '\x1b[33m' : '\x1b[31m';
348
+ const prefix = isWeak ? '\x1b[31m⚠ ' : ' ';
349
+ const suffix = isWeak ? ' ← weakest\x1b[0m' : '';
350
+ console.log(`${prefix}${row.name.padEnd(nameW)} ${scoreColor}${String(row.score).padStart(5)}\x1b[0m ${String(row.passed).padStart(4)} ${String(row.failed).padStart(4)} ${row.suggested}${suffix}`);
351
+ }
352
+ console.log('');
353
+ }
354
+ process.exit(0);
355
+ } else if (normalizedCommand === 'history') {
283
356
  const { formatHistory } = require('../src/activity');
284
357
  console.log('');
285
358
  console.log(formatHistory(options.dir));
@@ -5,16 +5,14 @@
5
5
  **Title:** I built a tool that audits your project for Claude Code optimization — scores you 0-100
6
6
 
7
7
  **Body:**
8
- After cataloging 1,107 Claude Code entries and verifying 948 of them with evidence, I built a CLI that checks if your project is actually set up to get the most out of Claude Code.
8
+ After cataloging 1,107 Claude Code entries and verifying 948 of them with evidence, I built a CLI that checks if your project is actually set up to get the most out of Claude Code. It runs 84 checks across CLAUDE.md, hooks, commands, agents, diagrams, and more.
9
9
 
10
- Most projects score around 10-20/100. After running setup, they jump to 70+.
10
+ I tested it on 4 real repos. A FastAPI marketing engine went from 46 to 64. A React Native social app went from 40 to 48. A Polymiro project jumped from 35 to 48. The CLAUDEX catalog repo itself: 62 to 90.
11
11
 
12
12
  ```
13
13
  npx claudex-setup
14
14
  ```
15
15
 
16
- It checks for: CLAUDE.md, hooks, custom commands, skills, agents, Mermaid diagrams, XML tags, path rules, MCP config, permissions, and more.
17
-
18
16
  Then `npx claudex-setup setup` auto-creates everything that's missing, tailored to your stack (React, Python, TypeScript, etc).
19
17
 
20
18
  Zero dependencies. No API keys. Runs entirely local.
@@ -38,7 +36,8 @@ Turns out most projects are missing basic stuff that makes a huge difference:
38
36
  - No custom commands (repeating the same prompts manually)
39
37
  - No Mermaid diagrams (wasting 73% more tokens on prose descriptions)
40
38
 
41
- Built a quick checker:
39
+ I tested 4 real repos with 84 checks. Before optimization: scores ranged from 35 to 62. After: 48 to 90. A VTCLE FastAPI project jumped from 46→64 just from adding missing hooks and commands.
40
+
42
41
  ```
43
42
  npx claudex-setup
44
43
  ```
@@ -54,7 +53,7 @@ Free, open source, zero dependencies: https://github.com/DnaFin/claudex-setup
54
53
  **Title:** 1,107 Claude Code Entries: What I Learned Building the Most Comprehensive Catalog
55
54
 
56
55
  **Body (excerpt):**
57
- I set out to catalog every single Claude Code capability, technique, and best practice. After repeated research cycles, I have 1,107 entries — 948 verified with real evidence.
56
+ I set out to catalog every single Claude Code capability, technique, and best practice. After repeated research cycles, I have 1,107 entries — 948 verified with real evidence. I packaged this into an 84-check CLI audit and tested it on 4 real projects — scores before optimization ranged from 35 to 62, and after: 48 to 90.
58
57
 
59
58
  Here are the top 10 things most developers are missing:
60
59
 
@@ -94,7 +93,7 @@ I cataloged 1,107 Claude Code entries and verified 948 of them with evidence.
94
93
 
95
94
  Most projects use less than 5% of what Claude Code can do.
96
95
 
97
- Here's a free tool that checks your project and tells you exactly what's missing:
96
+ Tested on 4 real repos — a React Native app scored 40, a FastAPI engine scored 46. After auto-setup: 48 and 64. Here's the free 84-check audit:
98
97
 
99
98
  npx claudex-setup
100
99
 
@@ -148,9 +147,9 @@ https://github.com/DnaFin/claudex-setup
148
147
  **Body:**
149
148
  I built a CLI tool that scores your project against Claude Code best practices.
150
149
 
151
- After researching 1,107 entries (948 verified with evidence), most projects score 10-20 out of 100 because they're missing basic optimizations like CLAUDE.md files, hooks, custom commands, and architecture diagrams.
150
+ After researching 1,107 entries (948 verified with evidence), I tested 4 real repos with 84 checks. Scores before optimization: 35–62. After auto-setup: 48–90. The biggest jump was a research catalog repo going from 62 to 90.
152
151
 
153
- npx claudex-setup → audit (0-100 score)
152
+ npx claudex-setup → audit (84 checks, 0-100 score)
154
153
  npx claudex-setup setup → auto-fix
155
154
 
156
155
  Detects your stack (React, Python, TS, Rust, Go, etc) and tailors recommendations.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudex-setup",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "Score your repo's Claude Code setup against 84 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": {
@@ -16,7 +16,10 @@
16
16
  "scripts": {
17
17
  "start": "node bin/cli.js",
18
18
  "build": "npm pack --dry-run",
19
- "test": "node test/run.js"
19
+ "test": "node test/run.js",
20
+ "test:jest": "jest",
21
+ "test:coverage": "jest --coverage",
22
+ "test:all": "node test/run.js && node test/check-matrix.js && node test/golden-matrix.js && node test/security-tests.js && jest"
20
23
  },
21
24
  "keywords": [
22
25
  "claude",
@@ -42,5 +45,8 @@
42
45
  },
43
46
  "engines": {
44
47
  "node": ">=18.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "jest": "^30.3.0"
45
51
  }
46
52
  }
package/src/activity.js CHANGED
@@ -140,6 +140,14 @@ function updateSnapshotIndex(snapshotDir, record) {
140
140
  fs.writeFileSync(indexPath, JSON.stringify(entries, null, 2), 'utf8');
141
141
  }
142
142
 
143
+ /**
144
+ * Write a normalized snapshot artifact to .claude/claudex-setup/snapshots/ and update the index.
145
+ * @param {string} dir - Project root directory.
146
+ * @param {string} snapshotKind - Snapshot type ('audit', 'benchmark', 'governance', 'augment', 'suggest-only').
147
+ * @param {Object} payload - Full result payload to persist.
148
+ * @param {Object} [meta={}] - Optional metadata fields merged into the envelope.
149
+ * @returns {Object} Artifact record with id, filePath, relativePath, indexPath, and summary.
150
+ */
143
151
  function writeSnapshotArtifact(dir, snapshotKind, payload, meta = {}) {
144
152
  const id = timestampId();
145
153
  const { snapshotDir } = ensureArtifactDirs(dir);
@@ -189,6 +197,12 @@ function readSnapshotIndex(dir) {
189
197
  }
190
198
  }
191
199
 
200
+ /**
201
+ * Get the audit score history from saved snapshots, most recent first.
202
+ * @param {string} dir - Project root directory.
203
+ * @param {number} [limit=20] - Maximum number of entries to return.
204
+ * @returns {Object[]} Array of snapshot index entries for audit snapshots.
205
+ */
192
206
  function getHistory(dir, limit = 20) {
193
207
  const entries = readSnapshotIndex(dir);
194
208
  return entries
@@ -197,6 +211,11 @@ function getHistory(dir, limit = 20) {
197
211
  .slice(0, limit);
198
212
  }
199
213
 
214
+ /**
215
+ * Compare the two most recent audit snapshots and return the delta.
216
+ * @param {string} dir - Project root directory.
217
+ * @returns {Object|null} Comparison with current/previous scores, delta, regressions, improvements, and trend. Null if fewer than 2 snapshots.
218
+ */
200
219
  function compareLatest(dir) {
201
220
  const audits = getHistory(dir, 2);
202
221
  if (audits.length < 2) return null;
package/src/analyze.js CHANGED
@@ -308,6 +308,13 @@ function buildRolloutOrder(report) {
308
308
  return steps;
309
309
  }
310
310
 
311
+ /**
312
+ * Analyze a project's Claude Code setup and produce a structured recommendation report.
313
+ * @param {Object} options - Analysis options.
314
+ * @param {string} options.dir - Project directory to analyze.
315
+ * @param {string} [options.mode='augment'] - Analysis mode ('augment' or 'suggest-only').
316
+ * @returns {Promise<Object>} Structured report with project summary, gaps, strengths, and recommendations.
317
+ */
311
318
  async function analyzeProject(options) {
312
319
  const mode = options.mode || 'augment';
313
320
  const ctx = new ProjectContext(options.dir);
@@ -472,6 +479,11 @@ function printAnalysis(report, options = {}) {
472
479
  }
473
480
  }
474
481
 
482
+ /**
483
+ * Export an analysis report as a formatted markdown string.
484
+ * @param {Object} report - The report object returned by analyzeProject().
485
+ * @returns {string} Markdown-formatted report content.
486
+ */
475
487
  function exportMarkdown(report) {
476
488
  const lines = [];
477
489
  lines.push(`# Claudex Setup Analysis Report`);
package/src/audit.js CHANGED
@@ -179,6 +179,16 @@ function printLiteAudit(result, dir) {
179
179
  console.log('');
180
180
  }
181
181
 
182
+ /**
183
+ * Run a full audit of a project's Claude Code setup against the CLAUDEX technique database.
184
+ * @param {Object} options - Audit options.
185
+ * @param {string} options.dir - Project directory to audit.
186
+ * @param {boolean} [options.silent] - Skip all console output, return result only.
187
+ * @param {boolean} [options.json] - Output result as JSON.
188
+ * @param {boolean} [options.lite] - Show short top-3 quick scan.
189
+ * @param {boolean} [options.verbose] - Show all recommendations including medium-impact.
190
+ * @returns {Promise<Object>} Audit result with score, passed/failed counts, quickWins, and topNextActions.
191
+ */
182
192
  async function audit(options) {
183
193
  const silent = options.silent || false;
184
194
  const ctx = new ProjectContext(options.dir);
package/src/benchmark.js CHANGED
@@ -114,6 +114,21 @@ function buildExecutiveSummary(before, after, workflowEvidence) {
114
114
  };
115
115
  }
116
116
 
117
+ function buildPracticalValue(before, after, applyResult) {
118
+ const written = applyResult.writtenFiles || [];
119
+ return {
120
+ denyRulesAdded: written.includes('.claude/settings.json') ? 'yes' : 'no',
121
+ hooksCreated: written.filter(f => f.includes('hooks/')).length,
122
+ commandsCreated: written.filter(f => f.includes('commands/')).length,
123
+ agentsCreated: written.filter(f => f.includes('agents/')).length,
124
+ skillsCreated: written.filter(f => f.includes('skills/')).length,
125
+ rulesCreated: written.filter(f => f.includes('rules/')).length,
126
+ claudeMdCreated: written.includes('CLAUDE.md') ? 'yes' : 'no',
127
+ totalFilesCreated: written.length,
128
+ totalFilesPreserved: (applyResult.preservedFiles || []).length,
129
+ };
130
+ }
131
+
117
132
  function buildCaseStudy(before, after, applyResult) {
118
133
  return {
119
134
  initialState: `Baseline score ${before.score}/100, organic ${before.organicScore}/100.`,
@@ -125,6 +140,7 @@ function buildCaseStudy(before, after, applyResult) {
125
140
  organicDelta: after.organicScore - before.organicScore,
126
141
  passedDelta: after.passed - before.passed,
127
142
  },
143
+ practicalValue: buildPracticalValue(before, after, applyResult),
128
144
  };
129
145
  }
130
146
 
@@ -172,6 +188,14 @@ function renderBenchmarkMarkdown(report) {
172
188
  ].join('\n');
173
189
  }
174
190
 
191
+ /**
192
+ * Run a before/after benchmark on an isolated copy of the project.
193
+ * @param {Object} options - Benchmark options.
194
+ * @param {string} options.dir - Project directory to benchmark.
195
+ * @param {string} [options.profile] - Permission profile to use during setup.
196
+ * @param {string[]} [options.mcpPacks] - MCP pack keys to include in setup.
197
+ * @returns {Promise<Object>} Benchmark report with before/after scores, delta, and workflow evidence.
198
+ */
175
199
  async function runBenchmark(options) {
176
200
  const before = await audit({ dir: options.dir, silent: true });
177
201
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'claudex-benchmark-'));
package/src/context.js CHANGED
@@ -5,6 +5,10 @@
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
 
8
+ /**
9
+ * Scans and caches project files to provide fast lookups for technique checks.
10
+ * Reads the project directory on construction and exposes helpers for file content, JSON, and stack detection.
11
+ */
8
12
  class ProjectContext {
9
13
  constructor(dir) {
10
14
  this.dir = dir;
@@ -67,10 +71,19 @@ class ProjectContext {
67
71
  }
68
72
  }
69
73
 
74
+ /**
75
+ * Return the contents of the project's CLAUDE.md (root or .claude/ location).
76
+ * @returns {string|null} File content or null if not found.
77
+ */
70
78
  claudeMdContent() {
71
79
  return this.fileContent('CLAUDE.md') || this.fileContent('.claude/CLAUDE.md');
72
80
  }
73
81
 
82
+ /**
83
+ * Read and cache the content of a file relative to the project root.
84
+ * @param {string} filePath - Relative path from the project root.
85
+ * @returns {string|null} File content or null if not readable.
86
+ */
74
87
  fileContent(filePath) {
75
88
  if (this._cache[filePath] !== undefined) return this._cache[filePath];
76
89
  const fullPath = path.join(this.dir, filePath);
package/src/governance.js CHANGED
@@ -332,6 +332,10 @@ function buildSettingsForProfile({ profileKey = 'safe-write', hookFiles = [], ex
332
332
  return base;
333
333
  }
334
334
 
335
+ /**
336
+ * Return the full governance surface: permission profiles, hooks, policy packs, and pilot kit.
337
+ * @returns {Object} Summary containing permissionProfiles, hookRegistry, policyPacks, domainPacks, mcpPacks, and pilotRolloutKit.
338
+ */
335
339
  function getGovernanceSummary() {
336
340
  return {
337
341
  permissionProfiles: PERMISSION_PROFILES,
@@ -396,6 +400,11 @@ function printGovernanceSummary(summary, options = {}) {
396
400
  console.log('');
397
401
  }
398
402
 
403
+ /**
404
+ * Render a governance summary as a formatted markdown string.
405
+ * @param {Object} summary - The summary object returned by getGovernanceSummary().
406
+ * @returns {string} Markdown-formatted governance report.
407
+ */
399
408
  function renderGovernanceMarkdown(summary) {
400
409
  const lines = [
401
410
  '# Claudex Setup Governance Report',
@@ -98,7 +98,14 @@ async function interactive(options) {
98
98
  }
99
99
 
100
100
  console.log('');
101
- console.log(c(` Applying ${toFix.length} fixes...`, 'bold'));
101
+ console.log(c(' ── Summary ──', 'magenta'));
102
+ console.log(` Selected ${c(String(toFix.length), 'bold')} improvements to apply:`);
103
+ for (const key of toFix) {
104
+ const item = results.find(r => r.key === key);
105
+ console.log(c(` • ${item ? item.name : key}`, 'dim'));
106
+ }
107
+ console.log('');
108
+ console.log(c(` Applying...`, 'bold'));
102
109
  console.log('');
103
110
 
104
111
  // Run setup in auto mode
package/src/techniques.js CHANGED
@@ -1295,6 +1295,24 @@ const TECHNIQUES = {
1295
1295
  fix: 'CLAUDE.md references deprecated patterns (old model names or API formats). Update to current Claude 4.x conventions.',
1296
1296
  template: null
1297
1297
  },
1298
+
1299
+ claudeMdQuality: {
1300
+ id: 102502,
1301
+ name: 'CLAUDE.md has substantive content',
1302
+ check: (ctx) => {
1303
+ const md = ctx.claudeMdContent();
1304
+ if (!md) return null;
1305
+ const lines = md.split('\n').filter(l => l.trim());
1306
+ const sections = (md.match(/^##\s/gm) || []).length;
1307
+ const hasCommand = /\b(npm|yarn|pnpm|pytest|go |make |ruff |cargo |dotnet )\b/i.test(md);
1308
+ return lines.length >= 15 && sections >= 2 && hasCommand;
1309
+ },
1310
+ impact: 'medium',
1311
+ rating: 4,
1312
+ category: 'quality-deep',
1313
+ fix: 'CLAUDE.md exists but lacks substance. Add at least 2 sections (## headings) and include your test/build/lint commands.',
1314
+ template: null
1315
+ },
1298
1316
  };
1299
1317
 
1300
1318
  // Stack detection