claudex-setup 1.10.2 → 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/src/audit.js CHANGED
@@ -30,10 +30,60 @@ function progressBar(score, max = 100, width = 20) {
30
30
  }
31
31
 
32
32
  const IMPACT_ORDER = { critical: 3, high: 2, medium: 1, low: 0 };
33
+ const CATEGORY_MODULES = {
34
+ memory: 'CLAUDE.md',
35
+ quality: 'verification',
36
+ git: 'safety',
37
+ workflow: 'commands-agents-skills',
38
+ security: 'permissions',
39
+ automation: 'hooks',
40
+ design: 'design-rules',
41
+ devops: 'ci-devops',
42
+ hygiene: 'project-hygiene',
43
+ performance: 'context-management',
44
+ tools: 'mcp-tools',
45
+ prompting: 'prompt-structure',
46
+ features: 'modern-claude-features',
47
+ 'quality-deep': 'quality-deep',
48
+ };
49
+ const ACTION_RATIONALES = {
50
+ noBypassPermissions: 'bypassPermissions skips the main safety layer. Explicit allow and deny rules create safer autonomy.',
51
+ secretsProtection: 'Without secret protection, Claude can accidentally inspect sensitive files and leak them into outputs.',
52
+ permissionDeny: 'Deny rules are the strongest way to prevent dangerous reads and destructive operations.',
53
+ settingsPermissions: 'Explicit permission settings make the workflow safer, more governable, and easier to review.',
54
+ testCommand: 'Without a test command, Claude cannot verify that its changes actually work before handoff.',
55
+ lintCommand: 'Without a lint command, Claude will miss formatting and style regressions that teams expect to catch automatically.',
56
+ buildCommand: 'Without a build command, compile and packaging failures stay invisible until later in the workflow.',
57
+ ciPipeline: 'CI is what turns a local setup improvement into a repeatable team-wide standard.',
58
+ securityReview: 'If you do not wire in security review guidance, high-risk changes are easier to ship without the right scrutiny.',
59
+ skills: 'Skills package reusable expertise so Claude does not need the same context re-explained every session.',
60
+ multipleAgents: 'Specialized agents unlock role-based work such as security review, implementation, and QA in parallel.',
61
+ multipleMcpServers: 'A richer MCP surface gives Claude access to live tools and documentation instead of stale assumptions.',
62
+ roleDefinition: 'A clear role definition calibrates how Claude thinks, explains, and validates work in this repo.',
63
+ importSyntax: 'Imported modules keep CLAUDE.md maintainable as the workflow grows more sophisticated.',
64
+ claudeMd: 'CLAUDE.md is the foundation of project-specific context. Without it, Claude starts every task half-blind.',
65
+ hooks: 'Hooks enforce the rules programmatically, which is much more reliable than relying on instructions alone.',
66
+ pathRules: 'Path-specific rules help Claude behave differently in different parts of the repo without global noise.',
67
+ context7Mcp: 'Live documentation reduces version drift and cuts down on confident but outdated answers.',
68
+ };
33
69
 
34
- function getQuickWins(failed) {
70
+ function riskFromImpact(impact) {
71
+ if (impact === 'critical') return 'high';
72
+ if (impact === 'high') return 'medium';
73
+ return 'low';
74
+ }
75
+
76
+ function confidenceFromImpact(impact) {
77
+ return impact === 'critical' || impact === 'high' ? 'high' : 'medium';
78
+ }
79
+
80
+ function getPrioritizedFailed(failed) {
35
81
  const prioritized = failed.filter(r => !(r.category === 'hygiene' && r.impact === 'low'));
36
- const pool = prioritized.length > 0 ? prioritized : failed;
82
+ return prioritized.length > 0 ? prioritized : failed;
83
+ }
84
+
85
+ function getQuickWins(failed) {
86
+ const pool = getPrioritizedFailed(failed);
37
87
 
38
88
  return [...pool]
39
89
  .sort((a, b) => {
@@ -45,6 +95,87 @@ function getQuickWins(failed) {
45
95
  .slice(0, 3);
46
96
  }
47
97
 
98
+ function buildTopNextActions(failed, limit = 5) {
99
+ const pool = getPrioritizedFailed(failed);
100
+
101
+ return [...pool]
102
+ .sort((a, b) => {
103
+ const impactA = IMPACT_ORDER[a.impact] ?? 0;
104
+ const impactB = IMPACT_ORDER[b.impact] ?? 0;
105
+ if (impactA !== impactB) return impactB - impactA;
106
+ return (a.fix || '').length - (b.fix || '').length;
107
+ })
108
+ .slice(0, limit)
109
+ .map(({ key, name, impact, fix, category }) => ({
110
+ key,
111
+ name,
112
+ impact,
113
+ category,
114
+ module: CATEGORY_MODULES[category] || category,
115
+ fix,
116
+ why: ACTION_RATIONALES[key] || fix,
117
+ risk: riskFromImpact(impact),
118
+ confidence: confidenceFromImpact(impact),
119
+ signals: [
120
+ `failed-check:${key}`,
121
+ `impact:${impact}`,
122
+ `category:${category}`,
123
+ ],
124
+ }));
125
+ }
126
+
127
+ function inferSuggestedNextCommand(result) {
128
+ const actionKeys = new Set((result.topNextActions || []).map(item => item.key));
129
+
130
+ if (result.failed === 0) {
131
+ return 'npx claudex-setup augment';
132
+ }
133
+
134
+ if (
135
+ result.score < 50 ||
136
+ actionKeys.has('claudeMd') ||
137
+ actionKeys.has('hooks') ||
138
+ actionKeys.has('settingsPermissions') ||
139
+ actionKeys.has('permissionDeny')
140
+ ) {
141
+ return 'npx claudex-setup setup';
142
+ }
143
+
144
+ if (result.score < 80) {
145
+ return 'npx claudex-setup suggest-only';
146
+ }
147
+
148
+ return 'npx claudex-setup augment';
149
+ }
150
+
151
+ function printLiteAudit(result, dir) {
152
+ console.log('');
153
+ console.log(colorize(' claudex-setup quick scan', 'bold'));
154
+ console.log(colorize(' ═══════════════════════════════════════', 'dim'));
155
+ console.log(colorize(` Scanning: ${dir}`, 'dim'));
156
+ console.log('');
157
+ console.log(` Score: ${colorize(`${result.score}/100`, 'bold')}`);
158
+ console.log('');
159
+
160
+ if (result.failed === 0) {
161
+ console.log(colorize(' Your Claude setup looks solid.', 'green'));
162
+ console.log(` Next: ${colorize(result.suggestedNextCommand, 'bold')}`);
163
+ console.log('');
164
+ return;
165
+ }
166
+
167
+ console.log(colorize(' Top 3 things to fix right now:', 'magenta'));
168
+ console.log('');
169
+ result.liteSummary.topNextActions.forEach((item, index) => {
170
+ console.log(` ${index + 1}. ${colorize(item.name, 'bold')}`);
171
+ console.log(colorize(` Why: ${item.why}`, 'dim'));
172
+ console.log(colorize(` Fix: ${item.fix}`, 'dim'));
173
+ });
174
+ console.log('');
175
+ console.log(` Ready? Run: ${colorize(result.suggestedNextCommand, 'bold')}`);
176
+ console.log('');
177
+ }
178
+
48
179
  async function audit(options) {
49
180
  const silent = options.silent || false;
50
181
  const ctx = new ProjectContext(options.dir);
@@ -91,6 +222,7 @@ async function audit(options) {
91
222
  const organicEarned = organicPassed.reduce((sum, r) => sum + (weights[r.impact] || 5), 0);
92
223
  const organicScore = maxScore > 0 ? Math.round((organicEarned / maxScore) * 100) : 0;
93
224
  const quickWins = getQuickWins(failed);
225
+ const topNextActions = buildTopNextActions(failed, 5);
94
226
  const result = {
95
227
  score,
96
228
  organicScore,
@@ -102,6 +234,12 @@ async function audit(options) {
102
234
  stacks,
103
235
  results,
104
236
  quickWins: quickWins.map(({ key, name, impact, fix, category }) => ({ key, name, impact, category, fix })),
237
+ topNextActions,
238
+ };
239
+ result.suggestedNextCommand = inferSuggestedNextCommand(result);
240
+ result.liteSummary = {
241
+ topNextActions: topNextActions.slice(0, 3),
242
+ nextCommand: result.suggestedNextCommand,
105
243
  };
106
244
 
107
245
  // Silent mode: skip all output, just return result
@@ -119,6 +257,12 @@ async function audit(options) {
119
257
  return result;
120
258
  }
121
259
 
260
+ if (options.lite) {
261
+ printLiteAudit(result, options.dir);
262
+ sendInsights(result);
263
+ return result;
264
+ }
265
+
122
266
  // Display results
123
267
  console.log('');
124
268
  console.log(colorize(' claudex-setup audit', 'bold'));
@@ -178,13 +322,16 @@ async function audit(options) {
178
322
  console.log('');
179
323
  }
180
324
 
181
- // Quick wins
182
- if (failed.length > 0) {
183
- console.log(colorize(' ⚡ Best next fixes', 'magenta'));
184
- for (let i = 0; i < quickWins.length; i++) {
185
- const r = quickWins[i];
186
- console.log(` ${i + 1}. ${colorize(r.name, 'bold')}`);
187
- console.log(colorize(` ${r.fix}`, 'dim'));
325
+ // Top next actions
326
+ if (topNextActions.length > 0) {
327
+ console.log(colorize(' ⚡ Top 5 Next Actions', 'magenta'));
328
+ for (let i = 0; i < topNextActions.length; i++) {
329
+ const item = topNextActions[i];
330
+ console.log(` ${i + 1}. ${colorize(item.name, 'bold')}`);
331
+ console.log(colorize(` Why: ${item.why}`, 'dim'));
332
+ console.log(colorize(` Trace: ${item.signals.join(' | ')}`, 'dim'));
333
+ console.log(colorize(` Risk: ${item.risk} | Confidence: ${item.confidence}`, 'dim'));
334
+ console.log(colorize(` Fix: ${item.fix}`, 'dim'));
188
335
  }
189
336
  console.log('');
190
337
  }
@@ -194,7 +341,7 @@ async function audit(options) {
194
341
  console.log(` ${colorize(`${passed.length}/${applicable.length}`, 'bold')} checks passing${skipped.length > 0 ? colorize(` (${skipped.length} not applicable)`, 'dim') : ''}`);
195
342
 
196
343
  if (failed.length > 0) {
197
- console.log(` Run ${colorize('npx claudex-setup setup', 'bold')} to create starter-safe defaults`);
344
+ console.log(` Next command: ${colorize(result.suggestedNextCommand, 'bold')}`);
198
345
  }
199
346
 
200
347
  console.log('');
@@ -1,11 +1,7 @@
1
1
  {
2
2
  "synced_from": "claudex",
3
- "synced_at": "2026-03-31T19:30:00Z",
3
+ "synced_at": "2026-04-02T15:12:04Z",
4
4
  "total_items": 1107,
5
5
  "tested": 948,
6
- "last_id": 1157,
7
- "domain_packs": 16,
8
- "mcp_packs": 26,
9
- "anti_patterns": 53,
10
- "contract_version": "1.0.0"
6
+ "last_id": 1157
11
7
  }
package/src/governance.js CHANGED
@@ -386,6 +386,74 @@ function printGovernanceSummary(summary, options = {}) {
386
386
  console.log('');
387
387
  }
388
388
 
389
+ function renderGovernanceMarkdown(summary) {
390
+ const lines = [
391
+ '# Claudex Setup Governance Report',
392
+ '',
393
+ 'This report summarizes the shipped governance surface for Claude Code rollout, review, and pilot approval.',
394
+ '',
395
+ '## Permission Profiles',
396
+ ];
397
+
398
+ for (const profile of summary.permissionProfiles) {
399
+ lines.push(`- **${profile.label}** \`${profile.key}\` | risk: \`${profile.risk}\` | defaultMode: \`${profile.defaultMode}\``);
400
+ lines.push(` - Use when: ${profile.useWhen}`);
401
+ lines.push(` - Behavior: ${profile.behavior}`);
402
+ if (Array.isArray(profile.deny) && profile.deny.length > 0) {
403
+ lines.push(` - Deny rules: ${profile.deny.join(', ')}`);
404
+ }
405
+ }
406
+
407
+ lines.push('', '## Hook Registry');
408
+ for (const hook of summary.hookRegistry) {
409
+ lines.push(`- **${hook.key}** \`${hook.triggerPoint}${hook.matcher ? ` ${hook.matcher}` : ''}\` | risk: \`${hook.risk}\``);
410
+ lines.push(` - File: ${hook.file}`);
411
+ lines.push(` - Purpose: ${hook.purpose}`);
412
+ lines.push(` - Dry run: ${hook.dryRunExample}`);
413
+ lines.push(` - Rollback: ${hook.rollbackPath}`);
414
+ }
415
+
416
+ lines.push('', '## Policy Packs');
417
+ for (const pack of summary.policyPacks) {
418
+ lines.push(`- **${pack.label}**`);
419
+ lines.push(` - Use when: ${pack.useWhen}`);
420
+ lines.push(` - Modules: ${pack.modules.join(', ')}`);
421
+ }
422
+
423
+ lines.push('', `## Domain Packs (${summary.domainPacks.length})`);
424
+ for (const pack of summary.domainPacks) {
425
+ lines.push(`- **${pack.label}**: ${pack.useWhen}`);
426
+ }
427
+
428
+ lines.push('', `## MCP Packs (${summary.mcpPacks.length})`);
429
+ for (const pack of summary.mcpPacks) {
430
+ lines.push(`- **${pack.label}**: ${Object.keys(pack.servers).join(', ')}`);
431
+ }
432
+
433
+ lines.push('', '## Pilot Rollout Kit', '### Recommended Scope');
434
+ for (const item of summary.pilotRolloutKit.recommendedScope) {
435
+ lines.push(`- ${item}`);
436
+ }
437
+
438
+ lines.push('', '### Approvals');
439
+ for (const item of summary.pilotRolloutKit.approvals) {
440
+ lines.push(`- ${item}`);
441
+ }
442
+
443
+ lines.push('', '### Success Metrics');
444
+ for (const item of summary.pilotRolloutKit.successMetrics) {
445
+ lines.push(`- ${item}`);
446
+ }
447
+
448
+ lines.push('', '### Rollback Expectations');
449
+ for (const item of summary.pilotRolloutKit.rollbackExpectations) {
450
+ lines.push(`- ${item}`);
451
+ }
452
+
453
+ lines.push('');
454
+ return lines.join('\n');
455
+ }
456
+
389
457
  module.exports = {
390
458
  PERMISSION_PROFILES,
391
459
  getPermissionProfile,
@@ -394,4 +462,5 @@ module.exports = {
394
462
  buildSettingsForProfile,
395
463
  getGovernanceSummary,
396
464
  printGovernanceSummary,
465
+ renderGovernanceMarkdown,
397
466
  };
package/src/insights.js CHANGED
@@ -87,7 +87,8 @@ function sendInsights(auditResult) {
87
87
  */
88
88
  function getLocalInsights(auditResult) {
89
89
  const { results } = auditResult;
90
- const failed = results.filter(r => !r.passed);
90
+ const applicable = results.filter(r => r.passed !== null);
91
+ const failed = applicable.filter(r => r.passed === false);
91
92
 
92
93
  // Top 3 most impactful fixes
93
94
  const impactOrder = { critical: 3, high: 2, medium: 1 };
@@ -98,7 +99,7 @@ function getLocalInsights(auditResult) {
98
99
 
99
100
  // Score breakdown by category
100
101
  const categories = {};
101
- for (const r of results) {
102
+ for (const r of applicable) {
102
103
  const cat = r.category || 'other';
103
104
  if (!categories[cat]) categories[cat] = { passed: 0, total: 0 };
104
105
  categories[cat].total++;
package/src/techniques.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * CLAUDEX Technique Database
3
- * Curated from 1,107 verified techniques, filtered to actionable setup recommendations.
3
+ * Curated from 1107 verified techniques, filtered to actionable setup recommendations.
4
4
  * Each technique includes: what to check, how to fix, impact level.
5
5
  */
6
6
 
@@ -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,