claudex-setup 1.15.1 → 1.16.1

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.
@@ -1,160 +1,226 @@
1
- # Launch Posts — Ready to Publish
1
+ # Launch Posts — Proof-Backed Distribution Assets
2
+
3
+ **Status:** Complete — every asset below is anchored in measured proof, a canonical artifact, or a verified runtime surface
4
+ **Date:** 2026-04-03
5
+
6
+ ## Shared Proof Anchors
7
+
8
+ Use these links as the canonical sources behind public claims:
9
+
10
+ - Proof artifact index: https://github.com/DnaFin/claudex/blob/main/research/proof-artifacts/README.md
11
+ - CLAUDEX self-dogfood trace: https://github.com/DnaFin/claudex/blob/main/research/proof-artifacts/claudex-self-dogfood-proof-trace-2026-04-03.md
12
+ - VTCLE case study: https://github.com/DnaFin/claudex/blob/main/research/case-study-vtcle-2026-04-03.md
13
+ - Social case study: https://github.com/DnaFin/claudex/blob/main/research/case-study-social-2026-04-03.md
14
+ - Polymiro case study: https://github.com/DnaFin/claudex/blob/main/research/case-study-polymiro-2026-04-03.md
15
+ - Public proof metrics source: https://github.com/DnaFin/claudex/blob/main/research/claudex-proof-metrics-source-2026-04-03.md
16
+
17
+ Measured-result boundary to preserve:
18
+
19
+ - before/after scores were measured with `claudex-setup@1.10.3` on `2026-04-03`
20
+ - current npm latest is `1.16.0`
21
+ - current product surface is `85 checks`
2
22
 
3
23
  ## Post 1: Reddit r/ClaudeAI
4
24
 
5
- **Title:** I built a tool that audits your project for Claude Code optimizationscores you 0-100
25
+ **Title:** I built a CLI that audits your Claude Code setup85 checks, measured on 4 real repos
6
26
 
7
27
  **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.
28
+ I built a zero-dependency CLI that audits how well a repo is set up for Claude Code.
9
29
 
10
- Most projects score around 10-20/100. After running setup, they jump to 70+.
30
+ It checks `85` things across `CLAUDE.md`, hooks, commands, agents, skills, MCP config, permissions, diagrams, and verification loops.
11
31
 
12
- ```
32
+ Measured on `2026-04-03` with `claudex-setup@1.10.3`:
33
+ - CLAUDEX: `62 -> 90`
34
+ - VTCLE: `46 -> 64`
35
+ - Social: `40 -> 48`
36
+ - Polymiro: `35 -> 48`
37
+
38
+ ```bash
13
39
  npx claudex-setup
14
40
  ```
15
41
 
16
- It checks for: CLAUDE.md, hooks, custom commands, skills, agents, Mermaid diagrams, XML tags, path rules, MCP config, permissions, and more.
42
+ It starts trust-first:
43
+ - audit first
44
+ - plan / suggest-only before writes
45
+ - apply only what you approve
46
+ - rollback artifacts for every applied batch
17
47
 
18
- Then `npx claudex-setup setup` auto-creates everything that's missing, tailored to your stack (React, Python, TypeScript, etc).
19
-
20
- Zero dependencies. No API keys. Runs entirely local.
48
+ Zero dependencies. No API keys. Runs local.
21
49
 
22
50
  GitHub: https://github.com/DnaFin/claudex-setup
23
51
 
24
- Would love feedback!
52
+ Proof and case studies:
53
+ - https://github.com/DnaFin/claudex/blob/main/research/proof-artifacts/README.md
54
+ - https://github.com/DnaFin/claudex/blob/main/research/case-study-vtcle-2026-04-03.md
55
+ - https://github.com/DnaFin/claudex/blob/main/research/case-study-social-2026-04-03.md
56
+ - https://github.com/DnaFin/claudex/blob/main/research/case-study-polymiro-2026-04-03.md
57
+
58
+ Would love feedback on what checks or rollout surfaces are still missing.
59
+
60
+ **Evidence anchor:** proof artifact index + 3 external case studies + current proof source
25
61
 
26
62
  ---
27
63
 
28
64
  ## Post 2: Reddit r/ChatGPTCoding
29
65
 
30
- **Title:** Your Claude Code project is probably running at 10% efficiency. Here's how to check.
66
+ **Title:** Most Claude Code repos are missing the safety layer, not the model
31
67
 
32
68
  **Body:**
33
- I spent weeks cataloging every Claude Code feature, technique, and best practice — 1,107 total, 948 verified with real evidence.
34
-
35
- Turns out most projects are missing basic stuff that makes a huge difference:
36
- - No CLAUDE.md (Claude doesn't know your project conventions)
37
- - No hooks (no auto-lint, no auto-test)
38
- - No custom commands (repeating the same prompts manually)
39
- - No Mermaid diagrams (wasting 73% more tokens on prose descriptions)
40
-
41
- Built a quick checker:
42
- ```
69
+ The interesting problem with Claude Code is not "can it write code?".
70
+ It's "is the repo actually set up so Claude can work safely and predictably?".
71
+
72
+ I built `claudex-setup` to audit that surface:
73
+ - `85` checks
74
+ - zero dependencies
75
+ - local-only by default
76
+ - trust-first flow: audit -> plan -> apply -> rollback
77
+
78
+ Measured on 4 real repos:
79
+ - FastAPI repo: `46 -> 64`
80
+ - React Native repo: `40 -> 48`
81
+ - Python/Docker repo: `35 -> 48`
82
+ - research engine repo: `62 -> 90`
83
+
84
+ ```bash
43
85
  npx claudex-setup
44
86
  ```
45
87
 
46
- Scores your project 0-100, tells you exactly what to fix, and can auto-apply everything.
88
+ The most common misses were not exotic:
89
+ - no deny rules
90
+ - no secrets protection
91
+ - no mermaid architecture
92
+ - no hooks registered in settings
93
+
94
+ Proof:
95
+ https://github.com/DnaFin/claudex/blob/main/research/proof-artifacts/README.md
47
96
 
48
- Free, open source, zero dependencies: https://github.com/DnaFin/claudex-setup
97
+ **Evidence anchor:** measured before/after traces + common gap summary from public proof set
49
98
 
50
99
  ---
51
100
 
52
101
  ## Post 3: Dev.to Article
53
102
 
54
- **Title:** 1,107 Claude Code Entries: What I Learned Building the Most Comprehensive Catalog
103
+ **Title:** What 4 Real Repos Taught Me About Claude Code Readiness
55
104
 
56
105
  **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.
106
+ I tested `claudex-setup` on 4 real repos and the pattern was clear:
58
107
 
59
- Here are the top 10 things most developers are missing:
108
+ - the best teams still miss permission deny rules
109
+ - mature repos often have hooks in files but not actually registered
110
+ - non-standard settings formats are a real adoption trap
111
+ - shared `settings.json` matters more than personal local overrides
60
112
 
61
- 1. **CLAUDE.md** Claude reads this at the start of every session. Without it, Claude doesn't know your build commands, code style, or project rules.
113
+ Measured on `2026-04-03` with `claudex-setup@1.10.3`:
114
+ - CLAUDEX: `62 -> 90`
115
+ - VTCLE: `46 -> 64`
116
+ - Social: `40 -> 48`
117
+ - Polymiro: `35 -> 48`
62
118
 
63
- 2. **Mermaid diagrams** A Mermaid architecture diagram saves 73% tokens compared to describing your project in prose.
119
+ The product today is strongest as:
64
120
 
65
- 3. **Hooks** Auto-lint after every edit. Auto-test before every commit. Hooks fire 100% of the time, CLAUDE.md rules fire ~80%.
121
+ `audit -> plan -> safe apply -> governance -> benchmark`
66
122
 
67
- 4. **Custom commands** `/test`, `/deploy`, `/review` package your repeated workflows.
123
+ Not a code generator. Not an MCP installer. A trust layer for Claude Code repos.
68
124
 
69
- 5. **Verification loops** — Tell Claude how to verify its own work. Include test commands in CLAUDE.md.
125
+ Proof packet:
126
+ https://github.com/DnaFin/claudex/blob/main/research/proof-artifacts/README.md
70
127
 
71
- 6. **Path-specific rules** Different conventions for frontend vs backend files.
72
-
73
- 7. **XML tags** — `<constraints>`, `<validation>` in CLAUDE.md = unambiguous instructions.
74
-
75
- 8. **Custom agents** — Security reviewer, test writer — specialized subagents for focused tasks.
76
-
77
- 9. **Skills** — Domain-specific workflows that load on demand, not every session.
78
-
79
- 10. **MCP servers** — Connect Claude to your database, ticket system, Slack.
80
-
81
- I packaged this into a CLI that checks your project:
82
- ```
83
- npx claudex-setup
84
- ```
85
-
86
- Full catalog: https://github.com/DnaFin/claudex-setup
128
+ **Evidence anchor:** proof artifact index + case-study docs + current proof source
87
129
 
88
130
  ---
89
131
 
90
132
  ## Post 4: Twitter/X Thread
91
133
 
92
134
  **Tweet 1:**
93
- I cataloged 1,107 Claude Code entries and verified 948 of them with evidence.
94
-
95
- Most projects use less than 5% of what Claude Code can do.
135
+ I built a zero-dependency CLI that audits Claude Code readiness across `85` checks.
96
136
 
97
- Here's a free tool that checks your project and tells you exactly what's missing:
137
+ Measured on 4 real repos:
138
+ - `62 -> 90`
139
+ - `46 -> 64`
140
+ - `40 -> 48`
141
+ - `35 -> 48`
98
142
 
99
- npx claudex-setup
143
+ `npx claudex-setup`
100
144
 
101
- Thread 🧵👇
145
+ Proof: github.com/DnaFin/claudex/blob/main/research/proof-artifacts/README.md
102
146
 
103
147
  **Tweet 2:**
104
- The #1 thing you're probably missing: CLAUDE.md
105
-
106
- It's a file Claude reads at the start of every session. Without it, Claude doesn't know your:
107
- - Build commands
108
- - Code style
109
- - Testing framework
110
- - Project architecture
148
+ The most common misses were boring and important:
149
+ - no deny rules
150
+ - no secrets protection
151
+ - no mermaid diagram
152
+ - no hooks registered in settings
111
153
 
112
- Takes 2 minutes to create. Impact: massive.
154
+ It is much more "trust layer" than "AI magic".
113
155
 
114
156
  **Tweet 3:**
115
- #2: Mermaid diagrams in CLAUDE.md
116
-
117
- A few hundred tokens of Mermaid syntax conveys what takes thousands of tokens in prose.
118
-
119
- 73% token savings = faster responses, lower cost, better context.
157
+ What it does well today:
158
+ - audit first
159
+ - suggest / plan before writes
160
+ - apply selectively
161
+ - emit rollback artifacts
162
+ - benchmark on isolated copy
120
163
 
121
164
  **Tweet 4:**
122
- #3: Hooks > CLAUDE.md rules
123
-
124
- CLAUDE.md instructions = ~80% compliance
125
- Hooks = 100% enforcement
165
+ Best result so far:
166
+ - CLAUDEX self-dogfood: `62 -> 90`
126
167
 
127
- Auto-lint after edits. Block commits without tests. Prevent force-push.
168
+ Best external proof:
169
+ - VTCLE: `46 -> 64`
128
170
 
129
- Hooks are deterministic. Instructions are advisory.
171
+ Case studies:
172
+ - github.com/DnaFin/claudex/blob/main/research/case-study-vtcle-2026-04-03.md
173
+ - github.com/DnaFin/claudex/blob/main/research/case-study-social-2026-04-03.md
174
+ - github.com/DnaFin/claudex/blob/main/research/case-study-polymiro-2026-04-03.md
130
175
 
131
176
  **Tweet 5:**
132
- Want to check your project in 10 seconds?
177
+ Measured results were captured on `claudex-setup@1.10.3` on `2026-04-03`.
178
+ Current npm latest is `1.16.0`, so exact scores can move slightly, but the proof packet is explicit about that boundary.
133
179
 
134
- npx claudex-setup
135
-
136
- Scores 0-100. Shows what's missing. Auto-fixes with `setup`.
137
-
138
- Free. Open source. Zero dependencies.
139
-
140
- https://github.com/DnaFin/claudex-setup
180
+ **Evidence anchor:** proof artifact index + per-repo traces
141
181
 
142
182
  ---
143
183
 
144
184
  ## Post 5: Hacker News (Show HN)
145
185
 
146
- **Title:** Show HN: claudex-setup Audit any project for Claude Code optimization (1,107 entries)
186
+ **Title:** Show HN: claudex-setup audit Claude Code readiness with 85 checks
147
187
 
148
188
  **Body:**
149
- I built a CLI tool that scores your project against Claude Code best practices.
150
-
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.
152
-
153
- npx claudex-setup → audit (0-100 score)
154
- npx claudex-setup setup → auto-fix
155
-
156
- Detects your stack (React, Python, TS, Rust, Go, etc) and tailors recommendations.
157
-
158
- Zero dependencies, no API keys, runs locally.
159
-
160
- https://github.com/DnaFin/claudex-setup
189
+ I built a CLI that audits how well a repo is set up for Claude Code.
190
+
191
+ This is not a code-quality linter and not an MCP installer.
192
+ It focuses on Claude workflow quality:
193
+ - `CLAUDE.md`
194
+ - hooks
195
+ - commands
196
+ - agents
197
+ - skills
198
+ - MCP config
199
+ - permissions / deny rules
200
+ - diagrams
201
+ - verification loops
202
+
203
+ Core workflow:
204
+ - `npx claudex-setup`
205
+ - `npx claudex-setup suggest-only`
206
+ - `npx claudex-setup plan`
207
+ - `npx claudex-setup apply`
208
+ - `npx claudex-setup benchmark`
209
+
210
+ Measured on 4 real repos on `2026-04-03` with `claudex-setup@1.10.3`:
211
+ - CLAUDEX: `62 -> 90`
212
+ - VTCLE: `46 -> 64`
213
+ - Social: `40 -> 48`
214
+ - Polymiro: `35 -> 48`
215
+
216
+ Trust decisions that mattered:
217
+ - zero dependencies
218
+ - audit before write
219
+ - rollback artifacts
220
+ - cross-platform Node hooks
221
+ - explicit proof packets instead of vague claims
222
+
223
+ Proof packet:
224
+ https://github.com/DnaFin/claudex/blob/main/research/proof-artifacts/README.md
225
+
226
+ **Evidence anchor:** proof artifact index + current npm proof source
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claudex-setup",
3
- "version": "1.15.1",
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.",
3
+ "version": "1.16.1",
4
+ "description": "Score your repo's Claude Code setup against 85 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": {
7
7
  "claudex-setup": "bin/cli.js"
@@ -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
@@ -21,10 +21,12 @@ function ensureArtifactDirs(dir) {
21
21
  const activityDir = path.join(root, 'activity');
22
22
  const rollbackDir = path.join(root, 'rollbacks');
23
23
  const snapshotDir = path.join(root, 'snapshots');
24
+ const outcomesDir = path.join(root, 'outcomes');
24
25
  fs.mkdirSync(activityDir, { recursive: true });
25
26
  fs.mkdirSync(rollbackDir, { recursive: true });
26
27
  fs.mkdirSync(snapshotDir, { recursive: true });
27
- return { root, activityDir, rollbackDir, snapshotDir };
28
+ fs.mkdirSync(outcomesDir, { recursive: true });
29
+ return { root, activityDir, rollbackDir, snapshotDir, outcomesDir };
28
30
  }
29
31
 
30
32
  function writeJson(filePath, payload) {
@@ -140,6 +142,14 @@ function updateSnapshotIndex(snapshotDir, record) {
140
142
  fs.writeFileSync(indexPath, JSON.stringify(entries, null, 2), 'utf8');
141
143
  }
142
144
 
145
+ /**
146
+ * Write a normalized snapshot artifact to .claude/claudex-setup/snapshots/ and update the index.
147
+ * @param {string} dir - Project root directory.
148
+ * @param {string} snapshotKind - Snapshot type ('audit', 'benchmark', 'governance', 'augment', 'suggest-only').
149
+ * @param {Object} payload - Full result payload to persist.
150
+ * @param {Object} [meta={}] - Optional metadata fields merged into the envelope.
151
+ * @returns {Object} Artifact record with id, filePath, relativePath, indexPath, and summary.
152
+ */
143
153
  function writeSnapshotArtifact(dir, snapshotKind, payload, meta = {}) {
144
154
  const id = timestampId();
145
155
  const { snapshotDir } = ensureArtifactDirs(dir);
@@ -189,6 +199,12 @@ function readSnapshotIndex(dir) {
189
199
  }
190
200
  }
191
201
 
202
+ /**
203
+ * Get the audit score history from saved snapshots, most recent first.
204
+ * @param {string} dir - Project root directory.
205
+ * @param {number} [limit=20] - Maximum number of entries to return.
206
+ * @returns {Object[]} Array of snapshot index entries for audit snapshots.
207
+ */
192
208
  function getHistory(dir, limit = 20) {
193
209
  const entries = readSnapshotIndex(dir);
194
210
  return entries
@@ -197,6 +213,11 @@ function getHistory(dir, limit = 20) {
197
213
  .slice(0, limit);
198
214
  }
199
215
 
216
+ /**
217
+ * Compare the two most recent audit snapshots and return the delta.
218
+ * @param {string} dir - Project root directory.
219
+ * @returns {Object|null} Comparison with current/previous scores, delta, regressions, improvements, and trend. Null if fewer than 2 snapshots.
220
+ */
200
221
  function compareLatest(dir) {
201
222
  const audits = getHistory(dir, 2);
202
223
  if (audits.length < 2) return null;
@@ -303,6 +324,192 @@ function exportTrendReport(dir) {
303
324
  return lines.join('\n');
304
325
  }
305
326
 
327
+ function readOutcomeIndex(dir) {
328
+ const indexPath = path.join(dir, '.claude', 'claudex-setup', 'outcomes', 'index.json');
329
+ if (!fs.existsSync(indexPath)) return [];
330
+ try {
331
+ const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
332
+ return Array.isArray(entries) ? entries : [];
333
+ } catch {
334
+ return [];
335
+ }
336
+ }
337
+
338
+ function updateOutcomeIndex(outcomesDir, record) {
339
+ const indexPath = path.join(outcomesDir, 'index.json');
340
+ let entries = [];
341
+
342
+ if (fs.existsSync(indexPath)) {
343
+ try {
344
+ entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
345
+ if (!Array.isArray(entries)) entries = [];
346
+ } catch {
347
+ entries = [];
348
+ }
349
+ }
350
+
351
+ entries.push(record);
352
+ const MAX_INDEX_ENTRIES = 500;
353
+ if (entries.length > MAX_INDEX_ENTRIES) {
354
+ entries = entries.slice(entries.length - MAX_INDEX_ENTRIES);
355
+ }
356
+ fs.writeFileSync(indexPath, JSON.stringify(entries, null, 2), 'utf8');
357
+ }
358
+
359
+ function normalizeOutcomeStatus(value) {
360
+ const normalized = `${value || ''}`.trim().toLowerCase();
361
+ if (!['accepted', 'rejected', 'deferred'].includes(normalized)) {
362
+ throw new Error('feedback status must be one of: accepted, rejected, deferred');
363
+ }
364
+ return normalized;
365
+ }
366
+
367
+ function normalizeOutcomeEffect(value) {
368
+ const normalized = `${value || ''}`.trim().toLowerCase();
369
+ if (!['positive', 'neutral', 'negative'].includes(normalized)) {
370
+ throw new Error('feedback effect must be one of: positive, neutral, negative');
371
+ }
372
+ return normalized;
373
+ }
374
+
375
+ function recordRecommendationOutcome(dir, payload) {
376
+ const key = `${payload.key || ''}`.trim();
377
+ if (!key) {
378
+ throw new Error('feedback requires a recommendation key');
379
+ }
380
+
381
+ const status = normalizeOutcomeStatus(payload.status);
382
+ const effect = normalizeOutcomeEffect(payload.effect || 'neutral');
383
+ const scoreDelta = Number.isFinite(payload.scoreDelta) ? payload.scoreDelta : (
384
+ payload.scoreDelta === null || payload.scoreDelta === undefined || payload.scoreDelta === ''
385
+ ? null
386
+ : Number(payload.scoreDelta)
387
+ );
388
+
389
+ if (scoreDelta !== null && !Number.isFinite(scoreDelta)) {
390
+ throw new Error('feedback scoreDelta must be a number when provided');
391
+ }
392
+
393
+ const id = timestampId();
394
+ const { outcomesDir } = ensureArtifactDirs(dir);
395
+ const filePath = path.join(outcomesDir, `${id}.json`);
396
+ const record = {
397
+ id,
398
+ createdAt: new Date().toISOString(),
399
+ key,
400
+ status,
401
+ effect,
402
+ source: `${payload.source || 'manual-cli'}`.trim() || 'manual-cli',
403
+ notes: `${payload.notes || ''}`.trim(),
404
+ scoreDelta,
405
+ };
406
+
407
+ writeJson(filePath, record);
408
+ updateOutcomeIndex(outcomesDir, {
409
+ ...record,
410
+ relativePath: path.relative(dir, filePath),
411
+ });
412
+
413
+ return {
414
+ id,
415
+ filePath,
416
+ relativePath: path.relative(dir, filePath),
417
+ record,
418
+ };
419
+ }
420
+
421
+ function summarizeOutcomeEntries(entries = []) {
422
+ const byKey = {};
423
+
424
+ for (const entry of entries) {
425
+ if (!entry || !entry.key) continue;
426
+ const bucket = byKey[entry.key] || {
427
+ key: entry.key,
428
+ total: 0,
429
+ accepted: 0,
430
+ rejected: 0,
431
+ deferred: 0,
432
+ positive: 0,
433
+ neutral: 0,
434
+ negative: 0,
435
+ scoreDeltaTotal: 0,
436
+ scoreDeltaCount: 0,
437
+ latestAt: null,
438
+ };
439
+
440
+ bucket.total += 1;
441
+ if (bucket[entry.status] !== undefined) bucket[entry.status] += 1;
442
+ if (bucket[entry.effect] !== undefined) bucket[entry.effect] += 1;
443
+ if (Number.isFinite(entry.scoreDelta)) {
444
+ bucket.scoreDeltaTotal += entry.scoreDelta;
445
+ bucket.scoreDeltaCount += 1;
446
+ }
447
+ if (!bucket.latestAt || new Date(entry.createdAt) > new Date(bucket.latestAt)) {
448
+ bucket.latestAt = entry.createdAt;
449
+ }
450
+
451
+ byKey[entry.key] = bucket;
452
+ }
453
+
454
+ for (const bucket of Object.values(byKey)) {
455
+ bucket.avgScoreDelta = bucket.scoreDeltaCount > 0
456
+ ? Number((bucket.scoreDeltaTotal / bucket.scoreDeltaCount).toFixed(2))
457
+ : null;
458
+ bucket.evidenceClass = bucket.total > 0 ? 'measured' : 'estimated';
459
+ }
460
+
461
+ return {
462
+ totalEntries: entries.length,
463
+ byKey,
464
+ keys: Object.keys(byKey).sort(),
465
+ };
466
+ }
467
+
468
+ function getRecommendationOutcomeSummary(dir) {
469
+ return summarizeOutcomeEntries(readOutcomeIndex(dir));
470
+ }
471
+
472
+ function getRecommendationAdjustment(summaryByKey, key) {
473
+ const bucket = summaryByKey && summaryByKey[key];
474
+ if (!bucket) return 0;
475
+
476
+ let adjustment = 0;
477
+ adjustment += bucket.accepted * 2;
478
+ adjustment += bucket.positive * 3;
479
+ adjustment -= bucket.rejected * 3;
480
+ adjustment -= bucket.negative * 4;
481
+
482
+ if (Number.isFinite(bucket.avgScoreDelta)) {
483
+ if (bucket.avgScoreDelta > 0) adjustment += Math.min(4, Math.round(bucket.avgScoreDelta / 4));
484
+ if (bucket.avgScoreDelta < 0) adjustment -= Math.min(4, Math.round(Math.abs(bucket.avgScoreDelta) / 4));
485
+ }
486
+
487
+ if (adjustment > 8) return 8;
488
+ if (adjustment < -8) return -8;
489
+ return adjustment;
490
+ }
491
+
492
+ function formatRecommendationOutcomeSummary(dir) {
493
+ const summary = getRecommendationOutcomeSummary(dir);
494
+ if (summary.totalEntries === 0) {
495
+ return 'No recommendation outcomes recorded yet. Use `npx claudex-setup feedback --key permissionDeny --status accepted --effect positive` after a real run.';
496
+ }
497
+
498
+ const lines = [
499
+ 'Recommendation outcome summary:',
500
+ '',
501
+ ];
502
+
503
+ for (const key of summary.keys) {
504
+ const bucket = summary.byKey[key];
505
+ const avg = Number.isFinite(bucket.avgScoreDelta) ? ` | avg score delta ${bucket.avgScoreDelta >= 0 ? '+' : ''}${bucket.avgScoreDelta}` : '';
506
+ const adjustment = getRecommendationAdjustment(summary.byKey, key);
507
+ lines.push(` ${key}: total ${bucket.total} | accepted ${bucket.accepted} | rejected ${bucket.rejected} | deferred ${bucket.deferred} | positive ${bucket.positive} | negative ${bucket.negative}${avg} | ranking ${adjustment >= 0 ? '+' : ''}${adjustment}`);
508
+ }
509
+
510
+ return lines.join('\n');
511
+ }
512
+
306
513
  module.exports = {
307
514
  ensureArtifactDirs,
308
515
  writeActivityArtifact,
@@ -313,4 +520,10 @@ module.exports = {
313
520
  compareLatest,
314
521
  formatHistory,
315
522
  exportTrendReport,
523
+ readOutcomeIndex,
524
+ recordRecommendationOutcome,
525
+ summarizeOutcomeEntries,
526
+ getRecommendationOutcomeSummary,
527
+ getRecommendationAdjustment,
528
+ formatRecommendationOutcomeSummary,
316
529
  };
package/src/analyze.js CHANGED
@@ -244,12 +244,15 @@ function toGaps(results) {
244
244
  }
245
245
 
246
246
  function toRecommendations(auditResult) {
247
- const failed = auditResult.results
248
- .filter(r => r.passed === false)
249
- .sort((a, b) => {
250
- const order = { critical: 3, high: 2, medium: 1, low: 0 };
251
- return (order[b.impact] || 0) - (order[a.impact] || 0);
252
- });
247
+ const failed = auditResult.results.filter(r => r.passed === false);
248
+ const topActionOrder = new Map((auditResult.topNextActions || []).map((item, index) => [item.key, index]));
249
+ failed.sort((a, b) => {
250
+ const rankedA = topActionOrder.has(a.key) ? topActionOrder.get(a.key) : Number.MAX_SAFE_INTEGER;
251
+ const rankedB = topActionOrder.has(b.key) ? topActionOrder.get(b.key) : Number.MAX_SAFE_INTEGER;
252
+ if (rankedA !== rankedB) return rankedA - rankedB;
253
+ const order = { critical: 3, high: 2, medium: 1, low: 0 };
254
+ return (order[b.impact] || 0) - (order[a.impact] || 0);
255
+ });
253
256
 
254
257
  return failed.slice(0, 10).map((r, index) => ({
255
258
  priority: index + 1,
@@ -259,6 +262,8 @@ function toRecommendations(auditResult) {
259
262
  module: moduleFromCategory(r.category),
260
263
  risk: riskFromImpact(r.impact),
261
264
  why: r.fix,
265
+ evidenceClass: (auditResult.topNextActions || []).find(item => item.key === r.key)?.evidenceClass || 'estimated',
266
+ rankingAdjustment: (auditResult.topNextActions || []).find(item => item.key === r.key)?.rankingAdjustment || 0,
262
267
  }));
263
268
  }
264
269
 
@@ -308,6 +313,13 @@ function buildRolloutOrder(report) {
308
313
  return steps;
309
314
  }
310
315
 
316
+ /**
317
+ * Analyze a project's Claude Code setup and produce a structured recommendation report.
318
+ * @param {Object} options - Analysis options.
319
+ * @param {string} options.dir - Project directory to analyze.
320
+ * @param {string} [options.mode='augment'] - Analysis mode ('augment' or 'suggest-only').
321
+ * @returns {Promise<Object>} Structured report with project summary, gaps, strengths, and recommendations.
322
+ */
311
323
  async function analyzeProject(options) {
312
324
  const mode = options.mode || 'augment';
313
325
  const ctx = new ProjectContext(options.dir);
@@ -472,6 +484,11 @@ function printAnalysis(report, options = {}) {
472
484
  }
473
485
  }
474
486
 
487
+ /**
488
+ * Export an analysis report as a formatted markdown string.
489
+ * @param {Object} report - The report object returned by analyzeProject().
490
+ * @returns {string} Markdown-formatted report content.
491
+ */
475
492
  function exportMarkdown(report) {
476
493
  const lines = [];
477
494
  lines.push(`# Claudex Setup Analysis Report`);