claude-launchpad 0.3.1 → 0.3.2
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/dist/cli.js +85 -139
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { Command as Command5 } from "commander";
|
|
5
|
-
import { access as access8 } from "fs/promises";
|
|
6
5
|
import { join as join10 } from "path";
|
|
7
6
|
|
|
8
7
|
// src/commands/init/index.ts
|
|
@@ -70,9 +69,60 @@ function printIssue(severity, analyzer, message, fix) {
|
|
|
70
69
|
}
|
|
71
70
|
console.log();
|
|
72
71
|
}
|
|
72
|
+
function renderDoctorReport(results) {
|
|
73
|
+
const overallScore = Math.round(
|
|
74
|
+
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
75
|
+
);
|
|
76
|
+
for (const result of results) {
|
|
77
|
+
printScoreCard(result.name, result.score);
|
|
78
|
+
}
|
|
79
|
+
log.blank();
|
|
80
|
+
printScoreCard("Overall", overallScore);
|
|
81
|
+
log.blank();
|
|
82
|
+
const allIssues = results.flatMap((r) => r.issues);
|
|
83
|
+
const actionable = allIssues.filter((i) => i.severity !== "info");
|
|
84
|
+
if (actionable.length === 0) {
|
|
85
|
+
log.success("No issues found. Your configuration looks solid.");
|
|
86
|
+
return { overallScore, actionableCount: 0 };
|
|
87
|
+
}
|
|
88
|
+
const sorted = [...actionable].sort((a, b) => {
|
|
89
|
+
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
90
|
+
return (order[a.severity] ?? 4) - (order[b.severity] ?? 4);
|
|
91
|
+
});
|
|
92
|
+
for (const issue of sorted) {
|
|
93
|
+
printIssue(issue.severity, issue.analyzer, issue.message, issue.fix);
|
|
94
|
+
}
|
|
95
|
+
log.info(`${actionable.length} issue(s) found. Fix critical/high first.`);
|
|
96
|
+
return { overallScore, actionableCount: actionable.length };
|
|
97
|
+
}
|
|
73
98
|
|
|
74
|
-
// src/lib/
|
|
99
|
+
// src/lib/fs-utils.ts
|
|
75
100
|
import { readFile, access } from "fs/promises";
|
|
101
|
+
async function fileExists(path) {
|
|
102
|
+
try {
|
|
103
|
+
await access(path);
|
|
104
|
+
return true;
|
|
105
|
+
} catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function readFileOrNull(path) {
|
|
110
|
+
try {
|
|
111
|
+
return await readFile(path, "utf-8");
|
|
112
|
+
} catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function readJsonOrNull(path) {
|
|
117
|
+
try {
|
|
118
|
+
const content = await readFile(path, "utf-8");
|
|
119
|
+
return JSON.parse(content);
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/lib/detect.ts
|
|
76
126
|
import { join, basename } from "path";
|
|
77
127
|
async function detectProject(root) {
|
|
78
128
|
const name = basename(root);
|
|
@@ -300,29 +350,6 @@ function pmRun(pkg) {
|
|
|
300
350
|
if (pm?.startsWith("bun")) return "bun";
|
|
301
351
|
return "npm run";
|
|
302
352
|
}
|
|
303
|
-
async function readJsonOrNull(path) {
|
|
304
|
-
try {
|
|
305
|
-
const content = await readFile(path, "utf-8");
|
|
306
|
-
return JSON.parse(content);
|
|
307
|
-
} catch {
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
async function readFileOrNull(path) {
|
|
312
|
-
try {
|
|
313
|
-
return await readFile(path, "utf-8");
|
|
314
|
-
} catch {
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
async function fileExists(path) {
|
|
319
|
-
try {
|
|
320
|
-
await access(path);
|
|
321
|
-
return true;
|
|
322
|
-
} catch {
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
353
|
async function globExists(dir, pattern) {
|
|
327
354
|
const { readdir: readdir5 } = await import("fs/promises");
|
|
328
355
|
try {
|
|
@@ -601,7 +628,7 @@ function createInitCommand() {
|
|
|
601
628
|
message: "One-line description (optional):"
|
|
602
629
|
});
|
|
603
630
|
const options = { name: name.trim(), description: description.trim() };
|
|
604
|
-
const hasClaudeMd = await
|
|
631
|
+
const hasClaudeMd = await fileExists(join2(root, "CLAUDE.md"));
|
|
605
632
|
if (hasClaudeMd && !opts.yes) {
|
|
606
633
|
const overwrite = await confirm({
|
|
607
634
|
message: "CLAUDE.md already exists. Overwrite?",
|
|
@@ -626,7 +653,7 @@ async function scaffold(root, options, detected) {
|
|
|
626
653
|
const settingsPath = join2(root, ".claude", "settings.json");
|
|
627
654
|
const mergedSettings = await mergeSettings(settingsPath, settings);
|
|
628
655
|
const claudeignorePath = join2(root, ".claudeignore");
|
|
629
|
-
const hasClaudeignore = await
|
|
656
|
+
const hasClaudeignore = await fileExists(claudeignorePath);
|
|
630
657
|
const writes = [
|
|
631
658
|
writeFile(join2(root, "CLAUDE.md"), claudeMd),
|
|
632
659
|
writeFile(join2(root, "TASKS.md"), tasksMd),
|
|
@@ -647,14 +674,6 @@ async function scaffold(root, options, detected) {
|
|
|
647
674
|
log.info("Run `claude-launchpad doctor` to check your config quality.");
|
|
648
675
|
log.blank();
|
|
649
676
|
}
|
|
650
|
-
async function fileExists2(path) {
|
|
651
|
-
try {
|
|
652
|
-
await readFile2(path);
|
|
653
|
-
return true;
|
|
654
|
-
} catch {
|
|
655
|
-
return false;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
677
|
async function mergeSettings(existingPath, generated) {
|
|
659
678
|
try {
|
|
660
679
|
const existing = JSON.parse(await readFile2(existingPath, "utf-8"));
|
|
@@ -680,7 +699,7 @@ async function mergeSettings(existingPath, generated) {
|
|
|
680
699
|
import { Command as Command2 } from "commander";
|
|
681
700
|
|
|
682
701
|
// src/lib/parser.ts
|
|
683
|
-
import {
|
|
702
|
+
import { readdir, access as access2 } from "fs/promises";
|
|
684
703
|
import { join as join3, resolve } from "path";
|
|
685
704
|
var CLAUDE_MD = "CLAUDE.md";
|
|
686
705
|
var CLAUDE_DIR = ".claude";
|
|
@@ -711,7 +730,7 @@ async function parseClaudeConfig(projectRoot) {
|
|
|
711
730
|
};
|
|
712
731
|
}
|
|
713
732
|
async function readClaudeMd(root) {
|
|
714
|
-
return
|
|
733
|
+
return readFileOrNull(join3(root, CLAUDE_MD));
|
|
715
734
|
}
|
|
716
735
|
function countInstructions(content) {
|
|
717
736
|
const lines = content.split("\n");
|
|
@@ -727,7 +746,7 @@ function countInstructions(content) {
|
|
|
727
746
|
return count;
|
|
728
747
|
}
|
|
729
748
|
async function readSettings(claudeDir) {
|
|
730
|
-
const raw = await
|
|
749
|
+
const raw = await readFileOrNull(join3(claudeDir, SETTINGS_FILE));
|
|
731
750
|
if (raw === null) return null;
|
|
732
751
|
try {
|
|
733
752
|
return JSON.parse(raw);
|
|
@@ -736,7 +755,7 @@ async function readSettings(claudeDir) {
|
|
|
736
755
|
}
|
|
737
756
|
}
|
|
738
757
|
async function readHooks(claudeDir) {
|
|
739
|
-
const settingsRaw = await
|
|
758
|
+
const settingsRaw = await readFileOrNull(join3(claudeDir, SETTINGS_FILE));
|
|
740
759
|
if (settingsRaw === null) return [];
|
|
741
760
|
try {
|
|
742
761
|
const settings = JSON.parse(settingsRaw);
|
|
@@ -779,7 +798,7 @@ async function readRules(claudeDir) {
|
|
|
779
798
|
return listFilesRecursive(rulesDir, ".md");
|
|
780
799
|
}
|
|
781
800
|
async function readMcpServers(claudeDir) {
|
|
782
|
-
const settingsRaw = await
|
|
801
|
+
const settingsRaw = await readFileOrNull(join3(claudeDir, SETTINGS_FILE));
|
|
783
802
|
if (settingsRaw === null) return [];
|
|
784
803
|
try {
|
|
785
804
|
const settings = JSON.parse(settingsRaw);
|
|
@@ -809,13 +828,6 @@ async function readSkills(claudeDir) {
|
|
|
809
828
|
]);
|
|
810
829
|
return [...commands, ...skills];
|
|
811
830
|
}
|
|
812
|
-
async function readFileOrNull2(path) {
|
|
813
|
-
try {
|
|
814
|
-
return await readFile3(path, "utf-8");
|
|
815
|
-
} catch {
|
|
816
|
-
return null;
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
831
|
async function listFilesRecursive(dir, ext) {
|
|
820
832
|
try {
|
|
821
833
|
await access2(dir);
|
|
@@ -989,12 +1001,12 @@ async function analyzeHooks(config) {
|
|
|
989
1001
|
}
|
|
990
1002
|
|
|
991
1003
|
// src/commands/doctor/analyzers/rules.ts
|
|
992
|
-
import { readFile as
|
|
1004
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
993
1005
|
import { basename as basename2, join as join4, dirname } from "path";
|
|
994
1006
|
async function analyzeRules(config) {
|
|
995
1007
|
const issues = [];
|
|
996
1008
|
const projectRoot = config.claudeMdPath ? dirname(config.claudeMdPath) : process.cwd();
|
|
997
|
-
const hasClaudeignore = await
|
|
1009
|
+
const hasClaudeignore = await fileExists(join4(projectRoot, ".claudeignore"));
|
|
998
1010
|
if (!hasClaudeignore) {
|
|
999
1011
|
issues.push({
|
|
1000
1012
|
analyzer: "Rules",
|
|
@@ -1014,7 +1026,7 @@ async function analyzeRules(config) {
|
|
|
1014
1026
|
}
|
|
1015
1027
|
for (const rulePath of config.rules) {
|
|
1016
1028
|
try {
|
|
1017
|
-
const content = await
|
|
1029
|
+
const content = await readFile3(rulePath, "utf-8");
|
|
1018
1030
|
const trimmed = content.trim();
|
|
1019
1031
|
if (trimmed.length === 0) {
|
|
1020
1032
|
issues.push({
|
|
@@ -1041,14 +1053,6 @@ async function analyzeRules(config) {
|
|
|
1041
1053
|
const score = Math.max(0, 100 - issues.length * 10);
|
|
1042
1054
|
return { name: "Rules", issues, score };
|
|
1043
1055
|
}
|
|
1044
|
-
async function fileExists3(path) {
|
|
1045
|
-
try {
|
|
1046
|
-
await access3(path);
|
|
1047
|
-
return true;
|
|
1048
|
-
} catch {
|
|
1049
|
-
return false;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
1056
|
|
|
1053
1057
|
// src/commands/doctor/analyzers/permissions.ts
|
|
1054
1058
|
async function analyzePermissions(config) {
|
|
@@ -1095,7 +1099,7 @@ async function analyzePermissions(config) {
|
|
|
1095
1099
|
}
|
|
1096
1100
|
|
|
1097
1101
|
// src/commands/doctor/analyzers/mcp.ts
|
|
1098
|
-
import { access as
|
|
1102
|
+
import { access as access3 } from "fs/promises";
|
|
1099
1103
|
async function analyzeMcp(config) {
|
|
1100
1104
|
const issues = [];
|
|
1101
1105
|
const servers = config.mcpServers;
|
|
@@ -1128,7 +1132,7 @@ async function analyzeMcp(config) {
|
|
|
1128
1132
|
const executable = server.command.split(" ")[0];
|
|
1129
1133
|
if (executable.startsWith("/") || executable.startsWith("./")) {
|
|
1130
1134
|
try {
|
|
1131
|
-
await
|
|
1135
|
+
await access3(executable);
|
|
1132
1136
|
} catch {
|
|
1133
1137
|
issues.push({
|
|
1134
1138
|
analyzer: "MCP",
|
|
@@ -1227,7 +1231,7 @@ async function analyzeQuality(config) {
|
|
|
1227
1231
|
}
|
|
1228
1232
|
|
|
1229
1233
|
// src/commands/doctor/fixer.ts
|
|
1230
|
-
import { readFile as
|
|
1234
|
+
import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2, access as access4 } from "fs/promises";
|
|
1231
1235
|
import { join as join5 } from "path";
|
|
1232
1236
|
async function applyFixes(issues, projectRoot) {
|
|
1233
1237
|
const detected = await detectProject(projectRoot);
|
|
@@ -1368,7 +1372,7 @@ async function addClaudeMdSection(root, heading, content) {
|
|
|
1368
1372
|
const claudeMdPath = join5(root, "CLAUDE.md");
|
|
1369
1373
|
let existing;
|
|
1370
1374
|
try {
|
|
1371
|
-
existing = await
|
|
1375
|
+
existing = await readFile4(claudeMdPath, "utf-8");
|
|
1372
1376
|
} catch {
|
|
1373
1377
|
return false;
|
|
1374
1378
|
}
|
|
@@ -1388,7 +1392,7 @@ ${content}
|
|
|
1388
1392
|
async function createClaudeignore(root, detected) {
|
|
1389
1393
|
const ignorePath = join5(root, ".claudeignore");
|
|
1390
1394
|
try {
|
|
1391
|
-
await
|
|
1395
|
+
await access4(ignorePath);
|
|
1392
1396
|
return false;
|
|
1393
1397
|
} catch {
|
|
1394
1398
|
}
|
|
@@ -1400,7 +1404,7 @@ async function createClaudeignore(root, detected) {
|
|
|
1400
1404
|
async function createStarterRules(root) {
|
|
1401
1405
|
const rulesDir = join5(root, ".claude", "rules");
|
|
1402
1406
|
try {
|
|
1403
|
-
await
|
|
1407
|
+
await access4(rulesDir);
|
|
1404
1408
|
return false;
|
|
1405
1409
|
} catch {
|
|
1406
1410
|
}
|
|
@@ -1421,7 +1425,7 @@ async function createStarterRules(root) {
|
|
|
1421
1425
|
async function readSettingsJson(root) {
|
|
1422
1426
|
const path = join5(root, ".claude", "settings.json");
|
|
1423
1427
|
try {
|
|
1424
|
-
const content = await
|
|
1428
|
+
const content = await readFile4(path, "utf-8");
|
|
1425
1429
|
return JSON.parse(content);
|
|
1426
1430
|
} catch {
|
|
1427
1431
|
return {};
|
|
@@ -1501,29 +1505,7 @@ async function runAndDisplay(projectRoot) {
|
|
|
1501
1505
|
analyzePermissions(config),
|
|
1502
1506
|
analyzeMcp(config)
|
|
1503
1507
|
]);
|
|
1504
|
-
|
|
1505
|
-
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
1506
|
-
);
|
|
1507
|
-
for (const result of results) {
|
|
1508
|
-
printScoreCard(result.name, result.score);
|
|
1509
|
-
}
|
|
1510
|
-
log.blank();
|
|
1511
|
-
printScoreCard("Overall", overallScore);
|
|
1512
|
-
log.blank();
|
|
1513
|
-
const allIssues = results.flatMap((r) => r.issues);
|
|
1514
|
-
const actionable = allIssues.filter((i) => i.severity !== "info");
|
|
1515
|
-
if (actionable.length === 0) {
|
|
1516
|
-
log.success("No issues found. Your configuration looks solid.");
|
|
1517
|
-
return;
|
|
1518
|
-
}
|
|
1519
|
-
const sorted = [...actionable].sort((a, b) => {
|
|
1520
|
-
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
1521
|
-
return (order[a.severity] ?? 4) - (order[b.severity] ?? 4);
|
|
1522
|
-
});
|
|
1523
|
-
for (const issue of sorted) {
|
|
1524
|
-
printIssue(issue.severity, issue.analyzer, issue.message, issue.fix);
|
|
1525
|
-
}
|
|
1526
|
-
log.info(`${actionable.length} issue(s) found. Fix critical/high first.`);
|
|
1508
|
+
renderDoctorReport(results);
|
|
1527
1509
|
}
|
|
1528
1510
|
|
|
1529
1511
|
// src/commands/doctor/index.ts
|
|
@@ -1552,13 +1534,13 @@ function createDoctorCommand() {
|
|
|
1552
1534
|
analyzeMcp(config)
|
|
1553
1535
|
]);
|
|
1554
1536
|
if (opts.json) {
|
|
1555
|
-
const
|
|
1537
|
+
const overallScore2 = Math.round(
|
|
1556
1538
|
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
1557
1539
|
);
|
|
1558
|
-
console.log(JSON.stringify({ overallScore, analyzers: results, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
|
|
1540
|
+
console.log(JSON.stringify({ overallScore: overallScore2, analyzers: results, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
|
|
1559
1541
|
return;
|
|
1560
1542
|
}
|
|
1561
|
-
|
|
1543
|
+
const { overallScore } = renderDoctorReport(results);
|
|
1562
1544
|
if (opts.fix) {
|
|
1563
1545
|
const allIssues = results.flatMap((r) => r.issues);
|
|
1564
1546
|
const fixable = allIssues.filter((i) => i.severity !== "info");
|
|
@@ -1577,9 +1559,6 @@ function createDoctorCommand() {
|
|
|
1577
1559
|
}
|
|
1578
1560
|
}
|
|
1579
1561
|
if (opts.minScore) {
|
|
1580
|
-
const overallScore = Math.round(
|
|
1581
|
-
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
1582
|
-
);
|
|
1583
1562
|
const threshold = parseInt(opts.minScore, 10);
|
|
1584
1563
|
if (overallScore < threshold) {
|
|
1585
1564
|
process.exit(1);
|
|
@@ -1587,31 +1566,6 @@ function createDoctorCommand() {
|
|
|
1587
1566
|
}
|
|
1588
1567
|
});
|
|
1589
1568
|
}
|
|
1590
|
-
function renderReport(results) {
|
|
1591
|
-
const overallScore = Math.round(
|
|
1592
|
-
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
1593
|
-
);
|
|
1594
|
-
for (const result of results) {
|
|
1595
|
-
printScoreCard(result.name, result.score);
|
|
1596
|
-
}
|
|
1597
|
-
log.blank();
|
|
1598
|
-
printScoreCard("Overall", overallScore);
|
|
1599
|
-
log.blank();
|
|
1600
|
-
const allIssues = results.flatMap((r) => r.issues);
|
|
1601
|
-
const actionable = allIssues.filter((i) => i.severity !== "info");
|
|
1602
|
-
if (actionable.length === 0) {
|
|
1603
|
-
log.success("No issues found. Your configuration looks solid.");
|
|
1604
|
-
return;
|
|
1605
|
-
}
|
|
1606
|
-
for (const issue of sortBySeverity(actionable)) {
|
|
1607
|
-
printIssue(issue.severity, issue.analyzer, issue.message, issue.fix);
|
|
1608
|
-
}
|
|
1609
|
-
log.info(`${actionable.length} issue(s) found. Fix critical/high first.`);
|
|
1610
|
-
}
|
|
1611
|
-
function sortBySeverity(issues) {
|
|
1612
|
-
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
1613
|
-
return [...issues].sort((a, b) => (order[a.severity] ?? 4) - (order[b.severity] ?? 4));
|
|
1614
|
-
}
|
|
1615
1569
|
|
|
1616
1570
|
// src/commands/eval/index.ts
|
|
1617
1571
|
import { Command as Command3 } from "commander";
|
|
@@ -1619,7 +1573,7 @@ import ora from "ora";
|
|
|
1619
1573
|
import chalk2 from "chalk";
|
|
1620
1574
|
|
|
1621
1575
|
// src/commands/eval/loader.ts
|
|
1622
|
-
import { readFile as
|
|
1576
|
+
import { readFile as readFile5, readdir as readdir3, access as access5 } from "fs/promises";
|
|
1623
1577
|
import { join as join7, resolve as resolve2, dirname as dirname2 } from "path";
|
|
1624
1578
|
import { fileURLToPath } from "url";
|
|
1625
1579
|
import { parse as parseYaml } from "yaml";
|
|
@@ -1734,7 +1688,7 @@ async function findScenariosDir() {
|
|
|
1734
1688
|
}
|
|
1735
1689
|
async function dirExists(path) {
|
|
1736
1690
|
try {
|
|
1737
|
-
await
|
|
1691
|
+
await access5(path);
|
|
1738
1692
|
return true;
|
|
1739
1693
|
} catch {
|
|
1740
1694
|
return false;
|
|
@@ -1750,7 +1704,7 @@ async function loadScenarios(options) {
|
|
|
1750
1704
|
const files = await listYamlFiles(dir);
|
|
1751
1705
|
for (const file of files) {
|
|
1752
1706
|
try {
|
|
1753
|
-
const content = await
|
|
1707
|
+
const content = await readFile5(file, "utf-8");
|
|
1754
1708
|
const raw = parseYaml(content);
|
|
1755
1709
|
const scenario = validateScenario(raw, file);
|
|
1756
1710
|
scenarios.push(scenario);
|
|
@@ -1780,7 +1734,7 @@ async function listYamlFiles(dir) {
|
|
|
1780
1734
|
}
|
|
1781
1735
|
|
|
1782
1736
|
// src/commands/eval/runner.ts
|
|
1783
|
-
import { mkdir as mkdir3, writeFile as writeFile3, readFile as
|
|
1737
|
+
import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile6, readdir as readdir4, rm } from "fs/promises";
|
|
1784
1738
|
import { join as join8, dirname as dirname3 } from "path";
|
|
1785
1739
|
import { tmpdir } from "os";
|
|
1786
1740
|
import { randomUUID } from "crypto";
|
|
@@ -1933,7 +1887,7 @@ async function evaluateSingleCheck(check, sandboxDir) {
|
|
|
1933
1887
|
async function checkGrep(check, sandboxDir) {
|
|
1934
1888
|
if (!check.pattern) return false;
|
|
1935
1889
|
try {
|
|
1936
|
-
const content = await
|
|
1890
|
+
const content = await readFile6(join8(sandboxDir, check.target), "utf-8");
|
|
1937
1891
|
let found;
|
|
1938
1892
|
try {
|
|
1939
1893
|
found = new RegExp(check.pattern).test(content);
|
|
@@ -1947,7 +1901,7 @@ async function checkGrep(check, sandboxDir) {
|
|
|
1947
1901
|
}
|
|
1948
1902
|
async function checkFileExists(check, sandboxDir) {
|
|
1949
1903
|
try {
|
|
1950
|
-
await
|
|
1904
|
+
await readFile6(join8(sandboxDir, check.target));
|
|
1951
1905
|
return check.expect === "present";
|
|
1952
1906
|
} catch {
|
|
1953
1907
|
return check.expect === "absent";
|
|
@@ -1955,7 +1909,7 @@ async function checkFileExists(check, sandboxDir) {
|
|
|
1955
1909
|
}
|
|
1956
1910
|
async function checkFileAbsent(check, sandboxDir) {
|
|
1957
1911
|
try {
|
|
1958
|
-
await
|
|
1912
|
+
await readFile6(join8(sandboxDir, check.target));
|
|
1959
1913
|
return check.expect === "absent";
|
|
1960
1914
|
} catch {
|
|
1961
1915
|
return check.expect === "present";
|
|
@@ -1966,7 +1920,7 @@ async function checkMaxLines(check, sandboxDir) {
|
|
|
1966
1920
|
try {
|
|
1967
1921
|
const files = await listAllFiles(join8(sandboxDir, check.target));
|
|
1968
1922
|
for (const file of files) {
|
|
1969
|
-
const content = await
|
|
1923
|
+
const content = await readFile6(file, "utf-8");
|
|
1970
1924
|
if (content.split("\n").length > maxLines) {
|
|
1971
1925
|
return check.expect === "absent";
|
|
1972
1926
|
}
|
|
@@ -2106,7 +2060,7 @@ async function checkClaudeCli() {
|
|
|
2106
2060
|
import { Command as Command4 } from "commander";
|
|
2107
2061
|
import { spawn, execFile as execFile2 } from "child_process";
|
|
2108
2062
|
import { promisify as promisify2 } from "util";
|
|
2109
|
-
import { access as
|
|
2063
|
+
import { access as access6 } from "fs/promises";
|
|
2110
2064
|
import { join as join9 } from "path";
|
|
2111
2065
|
var execAsync = promisify2(execFile2);
|
|
2112
2066
|
var ENHANCE_PROMPT = `Read CLAUDE.md and the project's codebase, then update CLAUDE.md to fill in missing or incomplete sections.
|
|
@@ -2142,7 +2096,7 @@ function createEnhanceCommand() {
|
|
|
2142
2096
|
const root = opts.path;
|
|
2143
2097
|
const claudeMdPath = join9(root, "CLAUDE.md");
|
|
2144
2098
|
try {
|
|
2145
|
-
await
|
|
2099
|
+
await access6(claudeMdPath);
|
|
2146
2100
|
} catch {
|
|
2147
2101
|
log.error("No CLAUDE.md found. Run `claude-launchpad init` first.");
|
|
2148
2102
|
process.exit(1);
|
|
@@ -2169,8 +2123,8 @@ function createEnhanceCommand() {
|
|
|
2169
2123
|
}
|
|
2170
2124
|
|
|
2171
2125
|
// src/cli.ts
|
|
2172
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.3.
|
|
2173
|
-
const hasConfig = await
|
|
2126
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.3.2", "-v, --version").action(async () => {
|
|
2127
|
+
const hasConfig = await fileExists(join10(process.cwd(), "CLAUDE.md")) || await fileExists(join10(process.cwd(), ".claude", "settings.json"));
|
|
2174
2128
|
if (hasConfig) {
|
|
2175
2129
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|
|
2176
2130
|
} else {
|
|
@@ -2188,12 +2142,4 @@ program.addCommand(createDoctorCommand());
|
|
|
2188
2142
|
program.addCommand(createEnhanceCommand());
|
|
2189
2143
|
program.addCommand(createEvalCommand());
|
|
2190
2144
|
program.parse();
|
|
2191
|
-
async function fileExists4(path) {
|
|
2192
|
-
try {
|
|
2193
|
-
await access8(path);
|
|
2194
|
-
return true;
|
|
2195
|
-
} catch {
|
|
2196
|
-
return false;
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
2145
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/init/index.ts","../src/lib/output.ts","../src/lib/detect.ts","../src/commands/init/generators/claude-md.ts","../src/commands/init/generators/tasks-md.ts","../src/commands/init/generators/settings.ts","../src/commands/init/generators/claudeignore.ts","../src/commands/doctor/index.ts","../src/lib/parser.ts","../src/commands/doctor/analyzers/budget.ts","../src/commands/doctor/analyzers/settings.ts","../src/commands/doctor/analyzers/hooks.ts","../src/commands/doctor/analyzers/rules.ts","../src/commands/doctor/analyzers/permissions.ts","../src/commands/doctor/analyzers/mcp.ts","../src/commands/doctor/analyzers/quality.ts","../src/commands/doctor/fixer.ts","../src/commands/doctor/watcher.ts","../src/commands/eval/index.ts","../src/commands/eval/loader.ts","../src/commands/eval/schema.ts","../src/commands/eval/runner.ts","../src/commands/enhance/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { createInitCommand } from \"./commands/init/index.js\";\nimport { createDoctorCommand } from \"./commands/doctor/index.js\";\nimport { createEvalCommand } from \"./commands/eval/index.js\";\nimport { createEnhanceCommand } from \"./commands/enhance/index.js\";\nimport { printBanner, log } from \"./lib/output.js\";\n\nconst program = new Command()\n .name(\"claude-launchpad\")\n .description(\"CLI toolkit that makes Claude Code setups measurably good\")\n .version(\"0.3.1\", \"-v, --version\")\n .action(async () => {\n // Default behavior: detect existing config and route accordingly\n const hasConfig = await fileExists(join(process.cwd(), \"CLAUDE.md\"))\n || await fileExists(join(process.cwd(), \".claude\", \"settings.json\"));\n\n if (hasConfig) {\n // Route directly to doctor — it prints its own banner\n await program.commands.find((c) => c.name() === \"doctor\")?.parseAsync([], { from: \"user\" });\n } else {\n printBanner();\n log.info(\"No Claude Code config found in this directory.\");\n log.blank();\n log.step(\"Run `claude-launchpad init` to set up your project\");\n log.step(\"Run `claude-launchpad doctor` to diagnose an existing config\");\n log.step(\"Run `claude-launchpad eval` to test your config quality\");\n log.blank();\n }\n });\n\nprogram.addCommand(createInitCommand());\nprogram.addCommand(createDoctorCommand());\nprogram.addCommand(createEnhanceCommand());\nprogram.addCommand(createEvalCommand());\n\nprogram.parse();\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { Command } from \"commander\";\nimport { input, confirm } from \"@inquirer/prompts\";\nimport { writeFile, mkdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { printBanner, log } from \"../../lib/output.js\";\nimport { detectProject } from \"../../lib/detect.js\";\nimport type { InitOptions, DetectedProject } from \"../../types/index.js\";\nimport { generateClaudeMd } from \"./generators/claude-md.js\";\nimport { generateTasksMd } from \"./generators/tasks-md.js\";\nimport { generateSettings } from \"./generators/settings.js\";\nimport { generateClaudeignore } from \"./generators/claudeignore.js\";\n\nexport function createInitCommand(): Command {\n return new Command(\"init\")\n .description(\"Set up Claude Code configuration for any project\")\n .option(\"-n, --name <name>\", \"Project name\")\n .option(\"-y, --yes\", \"Accept all defaults\")\n .action(async (opts) => {\n printBanner();\n\n const root = process.cwd();\n\n // Detect what kind of project this is\n log.step(\"Detecting project...\");\n const detected = await detectProject(root);\n\n if (detected.language) {\n log.success(`Found ${detected.framework ?? detected.language} project`);\n if (detected.packageManager) log.info(`Package manager: ${detected.packageManager}`);\n if (detected.devCommand) log.info(`Dev command: ${detected.devCommand}`);\n if (detected.testCommand) log.info(`Test command: ${detected.testCommand}`);\n } else {\n log.warn(\"Could not detect project type — generating minimal config\");\n }\n log.blank();\n\n // Resolve options\n const name = opts.name ?? detected.name ?? await input({\n message: \"Project name:\",\n validate: (v: string) => (v.trim().length > 0 ? true : \"Name cannot be empty\"),\n });\n\n const description = opts.yes ? \"\" : await input({\n message: \"One-line description (optional):\",\n });\n\n const options: InitOptions = { name: name.trim(), description: description.trim() };\n\n // Check for existing files\n const hasClaudeMd = await fileExists(join(root, \"CLAUDE.md\"));\n if (hasClaudeMd && !opts.yes) {\n const overwrite = await confirm({\n message: \"CLAUDE.md already exists. Overwrite?\",\n default: false,\n });\n if (!overwrite) {\n log.info(\"Keeping existing CLAUDE.md\");\n log.step(\"Tip: run `claude-launchpad doctor` to check your existing config\");\n return;\n }\n }\n\n await scaffold(root, options, detected);\n });\n}\n\nasync function scaffold(root: string, options: InitOptions, detected: DetectedProject): Promise<void> {\n log.step(\"Generating configuration...\");\n\n const claudeMd = generateClaudeMd(options, detected);\n const tasksMd = generateTasksMd(options);\n const settings = generateSettings(detected);\n const claudeignore = generateClaudeignore(detected);\n\n await mkdir(join(root, \".claude\"), { recursive: true });\n\n // Merge with existing settings.json instead of overwriting\n const settingsPath = join(root, \".claude\", \"settings.json\");\n const mergedSettings = await mergeSettings(settingsPath, settings as unknown as Record<string, unknown>);\n\n // Only generate .claudeignore if it doesn't exist\n const claudeignorePath = join(root, \".claudeignore\");\n const hasClaudeignore = await fileExists(claudeignorePath);\n\n const writes: Promise<void>[] = [\n writeFile(join(root, \"CLAUDE.md\"), claudeMd),\n writeFile(join(root, \"TASKS.md\"), tasksMd),\n writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2) + \"\\n\"),\n ];\n\n if (!hasClaudeignore) {\n writes.push(writeFile(claudeignorePath, claudeignore));\n }\n\n await Promise.all(writes);\n\n log.success(\"Generated CLAUDE.md\");\n log.success(\"Generated TASKS.md\");\n log.success(\"Generated .claude/settings.json (merged with existing)\");\n if (!hasClaudeignore) {\n log.success(\"Generated .claudeignore\");\n }\n\n log.blank();\n log.success(\"Done! Run `claude` to start.\");\n log.info(\"Run `claude-launchpad doctor` to check your config quality.\");\n log.blank();\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await readFile(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function mergeSettings(\n existingPath: string,\n generated: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n try {\n const existing = JSON.parse(await readFile(existingPath, \"utf-8\")) as Record<string, unknown>;\n\n // Merge hooks: keep existing hooks, add generated ones that don't conflict\n const existingHooks = (existing.hooks ?? {}) as Record<string, unknown[]>;\n const generatedHooks = (generated.hooks ?? {}) as Record<string, unknown[]>;\n\n const mergedHooks: Record<string, unknown[]> = { ...existingHooks };\n for (const [event, hookList] of Object.entries(generatedHooks)) {\n if (!mergedHooks[event]) {\n mergedHooks[event] = hookList;\n }\n // If event already exists, keep existing (don't duplicate)\n }\n\n return {\n ...existing,\n ...generated,\n hooks: Object.keys(mergedHooks).length > 0 ? mergedHooks : undefined,\n };\n } catch {\n // No existing file — just use generated\n return generated;\n }\n}\n","import chalk from \"chalk\";\nimport type { Severity } from \"../types/index.js\";\n\n// ─── Colors ───\n\nexport const colors = {\n success: chalk.green,\n error: chalk.red,\n warn: chalk.yellow,\n info: chalk.cyan,\n dim: chalk.dim,\n bold: chalk.bold,\n score: (score: number): string => {\n if (score >= 80) return chalk.green.bold(`${score}%`);\n if (score >= 60) return chalk.yellow.bold(`${score}%`);\n return chalk.red.bold(`${score}%`);\n },\n severity: (sev: Severity): string => {\n const map: Record<Severity, (s: string) => string> = {\n critical: chalk.bgRed.white.bold,\n high: chalk.red.bold,\n medium: chalk.yellow,\n low: chalk.cyan,\n info: chalk.dim,\n };\n return map[sev](` ${sev.toUpperCase()} `);\n },\n} as const;\n\n// ─── Prefixed Output ───\n\nexport const log = {\n success: (msg: string): void => console.log(` ${chalk.green(\"✓\")} ${msg}`),\n error: (msg: string): void => console.log(` ${chalk.red(\"✗\")} ${msg}`),\n warn: (msg: string): void => console.log(` ${chalk.yellow(\"!\")} ${msg}`),\n step: (msg: string): void => console.log(` ${chalk.cyan(\"→\")} ${msg}`),\n info: (msg: string): void => console.log(` ${chalk.dim(\"·\")} ${msg}`),\n blank: (): void => console.log(),\n} as const;\n\n// ─── Banner ───\n\nexport function printBanner(): void {\n log.blank();\n console.log(chalk.cyan.bold(\" Claude Launchpad\"));\n console.log(chalk.dim(\" Scaffold · Diagnose · Evaluate\"));\n log.blank();\n}\n\n// ─── Score Display ───\n\nexport function printScoreCard(label: string, score: number, max: number = 100): void {\n const pct = Math.round((score / max) * 100);\n const bar = renderBar(pct, 20);\n console.log(` ${chalk.bold(label.padEnd(22))} ${bar} ${colors.score(pct).padStart(12)}`);\n}\n\nfunction renderBar(pct: number, width: number): string {\n const filled = Math.round((pct / 100) * width);\n const empty = width - filled;\n const color = pct >= 80 ? chalk.green : pct >= 60 ? chalk.yellow : chalk.red;\n return color(\"━\".repeat(filled)) + chalk.dim(\"─\".repeat(empty));\n}\n\n// ─── Issues List (replaces table) ───\n\nexport function printIssue(severity: Severity, analyzer: string, message: string, fix?: string): void {\n const tag = colors.severity(severity);\n console.log(` ${tag} ${chalk.bold(analyzer)}`);\n console.log(` ${message}`);\n if (fix) {\n console.log(` ${chalk.dim(\"Fix:\")} ${chalk.dim(fix)}`);\n }\n console.log();\n}\n","import { readFile, access } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\nimport type { DetectedProject } from \"../types/index.js\";\n\n/**\n * Detect project characteristics by scanning manifest files and directory structure.\n * Works with any stack — no hardcoded list of supported frameworks.\n */\nexport async function detectProject(root: string): Promise<DetectedProject> {\n const name = basename(root);\n\n const [pkgJson, goMod, pyProject, gemfile, cargo, pubspec, composerJson, pomXml, buildGradle, packageSwift, mixExs, csproj, lockfiles] = await Promise.all([\n readJsonOrNull<PackageJson>(join(root, \"package.json\")),\n fileExists(join(root, \"go.mod\")),\n readFileOrNull(join(root, \"pyproject.toml\")),\n fileExists(join(root, \"Gemfile\")),\n fileExists(join(root, \"Cargo.toml\")),\n fileExists(join(root, \"pubspec.yaml\")),\n readJsonOrNull<ComposerJson>(join(root, \"composer.json\")),\n fileExists(join(root, \"pom.xml\")),\n fileExists(join(root, \"build.gradle\")) || fileExists(join(root, \"build.gradle.kts\")),\n fileExists(join(root, \"Package.swift\")),\n fileExists(join(root, \"mix.exs\")),\n globExists(root, \"*.csproj\"),\n detectLockfiles(root),\n ]);\n\n const manifests: ManifestState = {\n pkgJson, goMod, pyProject, gemfile, cargo, pubspec,\n composerJson, pomXml, buildGradle, packageSwift, mixExs, csproj,\n };\n\n const language = detectLanguage(manifests);\n const framework = detectFramework(manifests);\n const packageManager = detectPackageManager(manifests, lockfiles);\n const scripts = detectScripts({ pkgJson, pyProject, goMod, gemfile, composerJson, language });\n\n return {\n name,\n language,\n framework,\n packageManager,\n hasTests: scripts.testCommand !== null,\n hasLinter: scripts.lintCommand !== null,\n hasFormatter: scripts.formatCommand !== null,\n ...scripts,\n };\n}\n\n// ─── Language Detection ───\n\ninterface ManifestState {\n pkgJson: PackageJson | null;\n goMod: boolean;\n pyProject: string | null;\n gemfile: boolean;\n cargo: boolean;\n pubspec: boolean;\n composerJson: ComposerJson | null;\n pomXml: boolean;\n buildGradle: boolean;\n packageSwift: boolean;\n mixExs: boolean;\n csproj: boolean;\n}\n\nfunction detectLanguage(m: ManifestState): string | null {\n if (m.pkgJson?.devDependencies?.typescript || m.pkgJson?.dependencies?.typescript) return \"TypeScript\";\n if (m.pkgJson) return \"JavaScript\";\n if (m.goMod) return \"Go\";\n if (m.pyProject) return \"Python\";\n if (m.gemfile) return \"Ruby\";\n if (m.cargo) return \"Rust\";\n if (m.pubspec) return \"Dart\";\n if (m.composerJson) return \"PHP\";\n if (m.buildGradle) return \"Kotlin\";\n if (m.pomXml) return \"Java\";\n if (m.packageSwift) return \"Swift\";\n if (m.mixExs) return \"Elixir\";\n if (m.csproj) return \"C#\";\n return null;\n}\n\n// ─── Framework Detection ───\n\nfunction detectFramework(m: ManifestState): string | null {\n const deps = { ...m.pkgJson?.dependencies, ...m.pkgJson?.devDependencies };\n\n // JS/TS frameworks\n if (deps.next) return \"Next.js\";\n if (deps.nuxt) return \"Nuxt\";\n if (deps.svelte || deps[\"@sveltejs/kit\"]) return \"SvelteKit\";\n if (deps.astro) return \"Astro\";\n if (deps[\"@angular/core\"]) return \"Angular\";\n if (deps.remix || deps[\"@remix-run/react\"]) return \"Remix\";\n if (deps.vue) return \"Vue\";\n if (deps.react && !deps.next) return \"React\";\n if (deps.express) return \"Express\";\n if (deps.fastify) return \"Fastify\";\n if (deps.hono) return \"Hono\";\n if (deps.nestjs || deps[\"@nestjs/core\"]) return \"NestJS\";\n\n // Python frameworks\n if (m.pyProject) {\n if (m.pyProject.includes(\"fastapi\")) return \"FastAPI\";\n if (m.pyProject.includes(\"django\")) return \"Django\";\n if (m.pyProject.includes(\"flask\")) return \"Flask\";\n }\n\n // PHP frameworks\n if (m.composerJson) {\n const phpDeps = { ...m.composerJson.require, ...m.composerJson[\"require-dev\"] };\n if (phpDeps[\"laravel/framework\"]) return \"Laravel\";\n if (phpDeps[\"symfony/framework-bundle\"]) return \"Symfony\";\n }\n\n // Ruby\n if (m.gemfile) return \"Rails\";\n\n // JVM\n if (m.buildGradle) return \"Gradle\"; // Could be Spring Boot, Android, etc.\n if (m.pomXml) return \"Maven\";\n\n return null;\n}\n\n// ─── Package Manager Detection ───\n\ninterface DetectedLockfiles {\n pnpmLock: boolean;\n yarnLock: boolean;\n bunLock: boolean;\n npmLock: boolean;\n}\n\nasync function detectLockfiles(root: string): Promise<DetectedLockfiles> {\n const [pnpmLock, yarnLock, bunLock, npmLock] = await Promise.all([\n fileExists(join(root, \"pnpm-lock.yaml\")),\n fileExists(join(root, \"yarn.lock\")),\n fileExists(join(root, \"bun.lockb\")),\n fileExists(join(root, \"package-lock.json\")),\n ]);\n return { pnpmLock, yarnLock, bunLock, npmLock };\n}\n\nfunction detectPackageManager(\n m: Pick<ManifestState, \"pkgJson\" | \"goMod\" | \"pyProject\" | \"gemfile\" | \"cargo\" | \"composerJson\">,\n lockfiles: DetectedLockfiles,\n): string | null {\n if (m.pkgJson) {\n // Check packageManager field first (most explicit)\n const pm = m.pkgJson.packageManager;\n if (pm?.startsWith(\"pnpm\")) return \"pnpm\";\n if (pm?.startsWith(\"yarn\")) return \"yarn\";\n if (pm?.startsWith(\"bun\")) return \"bun\";\n if (pm?.startsWith(\"npm\")) return \"npm\";\n\n // Fall back to lockfile detection\n if (lockfiles.pnpmLock) return \"pnpm\";\n if (lockfiles.yarnLock) return \"yarn\";\n if (lockfiles.bunLock) return \"bun\";\n if (lockfiles.npmLock) return \"npm\";\n\n return \"npm\";\n }\n if (m.goMod) return \"go modules\";\n if (m.pyProject) {\n if (m.pyProject.includes(\"[tool.uv]\")) return \"uv\";\n if (m.pyProject.includes(\"[tool.poetry]\")) return \"poetry\";\n return \"pip\";\n }\n if (m.gemfile) return \"bundler\";\n if (m.cargo) return \"cargo\";\n if (m.composerJson) return \"composer\";\n return null;\n}\n\n// ─── Script Detection ───\n\ninterface DetectedScripts {\n formatCommand: string | null;\n lintCommand: string | null;\n testCommand: string | null;\n devCommand: string | null;\n buildCommand: string | null;\n}\n\nfunction detectScripts(m: {\n pkgJson: PackageJson | null;\n pyProject: string | null;\n goMod: boolean;\n gemfile: boolean;\n composerJson: ComposerJson | null;\n language: string | null;\n}): DetectedScripts {\n const scripts = m.pkgJson?.scripts ?? {};\n\n if (m.pkgJson) {\n return {\n devCommand: scripts.dev ? `${pmRun(m.pkgJson)} dev` : null,\n buildCommand: scripts.build ? `${pmRun(m.pkgJson)} build` : null,\n testCommand: scripts.test ? `${pmRun(m.pkgJson)} test` : null,\n lintCommand: scripts.lint ? `${pmRun(m.pkgJson)} lint` : null,\n formatCommand: scripts.format ? `${pmRun(m.pkgJson)} format` : null,\n };\n }\n\n if (m.language === \"Go\") {\n return {\n devCommand: \"go run .\",\n buildCommand: \"go build .\",\n testCommand: \"go test ./...\",\n lintCommand: \"golangci-lint run\",\n formatCommand: \"gofmt -w .\",\n };\n }\n\n if (m.language === \"Python\") {\n const runner = m.pyProject?.includes(\"[tool.uv]\") ? \"uv run\" : \"python -m\";\n return {\n devCommand: null,\n buildCommand: null,\n testCommand: `${runner} pytest`,\n lintCommand: `${runner} ruff check .`,\n formatCommand: `${runner} ruff format .`,\n };\n }\n\n if (m.gemfile) {\n return {\n devCommand: \"bin/dev\",\n buildCommand: null,\n testCommand: \"bin/rails test\",\n lintCommand: \"bin/rubocop\",\n formatCommand: null,\n };\n }\n\n if (m.language === \"PHP\") {\n return {\n devCommand: \"php artisan serve\",\n buildCommand: null,\n testCommand: \"php artisan test\",\n lintCommand: \"vendor/bin/phpstan analyse\",\n formatCommand: \"vendor/bin/pint\",\n };\n }\n\n if (m.language === \"Rust\") {\n return {\n devCommand: \"cargo run\",\n buildCommand: \"cargo build\",\n testCommand: \"cargo test\",\n lintCommand: \"cargo clippy\",\n formatCommand: \"cargo fmt\",\n };\n }\n\n if (m.language === \"Java\" || m.language === \"Kotlin\") {\n return {\n devCommand: null,\n buildCommand: \"mvn package\",\n testCommand: \"mvn test\",\n lintCommand: null,\n formatCommand: null,\n };\n }\n\n if (m.language === \"Swift\") {\n return {\n devCommand: null,\n buildCommand: \"swift build\",\n testCommand: \"swift test\",\n lintCommand: \"swiftlint\",\n formatCommand: \"swift-format format -r .\",\n };\n }\n\n if (m.language === \"Elixir\") {\n return {\n devCommand: \"mix phx.server\",\n buildCommand: \"mix compile\",\n testCommand: \"mix test\",\n lintCommand: \"mix credo\",\n formatCommand: \"mix format\",\n };\n }\n\n if (m.language === \"C#\") {\n return {\n devCommand: \"dotnet run\",\n buildCommand: \"dotnet build\",\n testCommand: \"dotnet test\",\n lintCommand: null,\n formatCommand: \"dotnet format\",\n };\n }\n\n return { devCommand: null, buildCommand: null, testCommand: null, lintCommand: null, formatCommand: null };\n}\n\nfunction pmRun(pkg: PackageJson): string {\n const pm = pkg.packageManager;\n if (pm?.startsWith(\"pnpm\")) return \"pnpm\";\n if (pm?.startsWith(\"yarn\")) return \"yarn\";\n if (pm?.startsWith(\"bun\")) return \"bun\";\n return \"npm run\";\n}\n\n// ─── Utilities ───\n\ninterface PackageJson {\n name?: string;\n packageManager?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\ninterface ComposerJson {\n require?: Record<string, string>;\n \"require-dev\"?: Record<string, string>;\n}\n\nasync function readJsonOrNull<T>(path: string): Promise<T | null> {\n try {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nasync function readFileOrNull(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function globExists(dir: string, pattern: string): Promise<boolean> {\n const { readdir } = await import(\"node:fs/promises\");\n try {\n const entries = await readdir(dir);\n return entries.some((e) => e.endsWith(pattern.replace(\"*\", \"\")));\n } catch {\n return false;\n }\n}\n","import type { InitOptions, DetectedProject } from \"../../../types/index.js\";\n\nexport function generateClaudeMd(options: InitOptions, detected: DetectedProject): string {\n const sections: string[] = [];\n\n // Header\n sections.push(`# ${options.name}`);\n if (options.description) {\n sections.push(\"\", options.description);\n }\n\n // Stack (auto-detected)\n sections.push(\"\", \"## Stack\");\n if (detected.language) {\n const items: string[] = [];\n if (detected.framework) items.push(`- **Framework**: ${detected.framework}`);\n items.push(`- **Language**: ${detected.language}`);\n if (detected.packageManager) items.push(`- **Package Manager**: ${detected.packageManager}`);\n sections.push(items.join(\"\\n\"));\n } else {\n sections.push(\"<!-- TODO: Define your tech stack -->\");\n }\n\n // Commands (auto-detected)\n sections.push(\"\", \"## Commands\");\n const commands: string[] = [];\n if (detected.devCommand) commands.push(`- Dev: \\`${detected.devCommand}\\``);\n if (detected.buildCommand) commands.push(`- Build: \\`${detected.buildCommand}\\``);\n if (detected.testCommand) commands.push(`- Test: \\`${detected.testCommand}\\``);\n if (detected.lintCommand) commands.push(`- Lint: \\`${detected.lintCommand}\\``);\n if (detected.formatCommand) commands.push(`- Format: \\`${detected.formatCommand}\\``);\n if (commands.length > 0) {\n sections.push(commands.join(\"\\n\"));\n } else {\n sections.push(\"<!-- TODO: Add your dev/build/test commands -->\");\n }\n\n // Session Start\n sections.push(\"\", `## Session Start\n- ALWAYS read @TASKS.md first — it tracks progress across sessions\n- Check the Session Log at the bottom of TASKS.md for where we left off\n- Update TASKS.md as you complete work`);\n\n // Conventions\n sections.push(\"\", `## Conventions\n- Git: Conventional commits (\\`feat:\\`, \\`fix:\\`, \\`docs:\\`, \\`refactor:\\`, \\`test:\\`, \\`chore:\\`)`);\n\n // Off-Limits\n sections.push(\"\", `## Off-Limits\n- Never hardcode secrets — use environment variables\n- Never write to \\`.env\\` files\n- Never expose internal error details in API responses`);\n\n // Key Decisions\n sections.push(\"\", `## Key Decisions\n<!-- Record architectural decisions as you make them -->`);\n\n return sections.join(\"\\n\") + \"\\n\";\n}\n","import type { InitOptions } from \"../../../types/index.js\";\n\nexport function generateTasksMd(options: InitOptions): string {\n return `# ${options.name} — Task Tracker\n\n> Claude: Read this at session start. Keep this file SHORT — only current state matters.\n> Rules: (1) Only show current + next sprint tasks. (2) Completed sprints get one summary line. (3) Session log: max 3 lines per session, keep only last 3 sessions. (4) Target: under 80 lines total.\n\n## Completed Sprints\n\n## Current Sprint: Sprint 1 — Setup\n\n### In Progress\n\n### To Do\n- [ ] Project scaffolding and environment setup\n- [ ] Core feature implementation\n- [ ] Test infrastructure\n\n### Done\n\n## Next Sprint: Sprint 2 — Core Features\n- [ ] ...\n\n## Session Log\n<!-- Keep last 3 sessions only. Max 3 lines each. -->\n`;\n}\n","import type { DetectedProject } from \"../../../types/index.js\";\n\ninterface HookEntry {\n readonly type: \"command\";\n readonly command: string;\n}\n\ninterface HookGroup {\n readonly matcher: string;\n readonly hooks: ReadonlyArray<HookEntry>;\n}\n\ninterface ClaudeSettings {\n readonly hooks?: Record<string, ReadonlyArray<HookGroup>>;\n}\n\n/**\n * Generate .claude/settings.json based on detected project.\n * No third-party plugin dependencies — just hooks that match the project's tooling.\n *\n * Claude Code hook schema:\n * { \"PostToolUse\": [{ \"matcher\": \"Write|Edit\", \"hooks\": [{ \"type\": \"command\", \"command\": \"...\" }] }] }\n */\nexport function generateSettings(detected: DetectedProject): ClaudeSettings {\n const preToolUse: HookGroup[] = [];\n const postToolUse: HookGroup[] = [];\n\n // Universal: .env file protection (block read + write)\n preToolUse.push({\n matcher: \"Read|Write|Edit\",\n hooks: [{\n type: \"command\",\n command: \"echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -qE '\\\\.(env|env\\\\..*)$' && ! echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -q '.env.example' && echo 'BLOCKED: .env files contain secrets — use .env.example for documentation' && exit 1; exit 0\",\n }],\n });\n\n // Auto-format based on detected tooling\n const formatHook = buildFormatHook(detected);\n if (formatHook) {\n postToolUse.push(formatHook);\n }\n\n const hooks: Record<string, ReadonlyArray<HookGroup>> = {};\n if (preToolUse.length > 0) hooks.PreToolUse = preToolUse;\n if (postToolUse.length > 0) hooks.PostToolUse = postToolUse;\n\n return Object.keys(hooks).length > 0 ? { hooks } : {};\n}\n\n// Safe formatter commands — never interpolate user-controlled strings into shell commands\nconst SAFE_FORMATTERS: Record<string, { extensions: string[]; command: string }> = {\n TypeScript: { extensions: [\"ts\", \"tsx\"], command: \"npx prettier --write\" },\n JavaScript: { extensions: [\"js\", \"jsx\"], command: \"npx prettier --write\" },\n Python: { extensions: [\"py\"], command: \"ruff format\" },\n Go: { extensions: [\"go\"], command: \"gofmt -w\" },\n Rust: { extensions: [\"rs\"], command: \"rustfmt\" },\n Ruby: { extensions: [\"rb\"], command: \"rubocop -A\" },\n Dart: { extensions: [\"dart\"], command: \"dart format\" },\n PHP: { extensions: [\"php\"], command: \"vendor/bin/pint\" },\n Kotlin: { extensions: [\"kt\", \"kts\"], command: \"ktlint -F\" },\n Java: { extensions: [\"java\"], command: \"google-java-format -i\" },\n Swift: { extensions: [\"swift\"], command: \"swift-format format -i\" },\n Elixir: { extensions: [\"ex\", \"exs\"], command: \"mix format\" },\n \"C#\": { extensions: [\"cs\"], command: \"dotnet format\" },\n};\n\nfunction buildFormatHook(detected: DetectedProject): HookGroup | null {\n if (!detected.language) return null;\n\n const config = SAFE_FORMATTERS[detected.language];\n if (!config) return null;\n\n const extChecks = config.extensions\n .map((ext) => `[ \"$ext\" = \"${ext}\" ]`)\n .join(\" || \");\n\n // Only use hardcoded safe commands — never interpolate detected.formatCommand\n // to prevent command injection via malicious package.json scripts\n return {\n matcher: \"Write|Edit\",\n hooks: [{\n type: \"command\",\n command: `ext=\\${TOOL_INPUT_FILE_PATH##*.}; (${extChecks}) && ${config.command} \"$TOOL_INPUT_FILE_PATH\" 2>/dev/null; exit 0`,\n }],\n };\n}\n","import type { DetectedProject } from \"../../../types/index.js\";\n\n/**\n * Generate .claudeignore based on detected project type.\n * Prevents Claude from reading noise files that waste context.\n */\nexport function generateClaudeignore(detected: DetectedProject): string {\n const sections: string[] = [\"# Generated by claude-launchpad\"];\n\n // Universal ignores\n sections.push(`\n# Dependencies\nnode_modules/\n.pnp/\n.yarn/\n\n# Build output\ndist/\nbuild/\nout/\n.next/\n.nuxt/\n.output/\n.svelte-kit/\n.vercel/\n.turbo/\n\n# Package manager\npnpm-lock.yaml\npackage-lock.json\nyarn.lock\nbun.lockb\n\n# IDE & OS\n.vscode/\n.idea/\n*.swp\n*.swo\n.DS_Store\nThumbs.db\n\n# Test & coverage\ncoverage/\n.nyc_output/\n__snapshots__/\n\n# Environment (should never be read)\n.env\n.env.*\n!.env.example`);\n\n // Language-specific ignores\n const lang = detected.language;\n\n if (lang === \"Python\") {\n sections.push(`\n# Python\n__pycache__/\n*.pyc\n*.pyo\n.venv/\nvenv/\n.mypy_cache/\n.ruff_cache/\n.pytest_cache/\n*.egg-info/`);\n }\n\n if (lang === \"Go\") {\n sections.push(`\n# Go\nbin/\nvendor/`);\n }\n\n if (lang === \"Rust\") {\n sections.push(`\n# Rust\ntarget/\nCargo.lock`);\n }\n\n if (lang === \"Ruby\") {\n sections.push(`\n# Ruby\nvendor/bundle/\n.bundle/\ntmp/\nlog/`);\n }\n\n if (lang === \"Java\" || lang === \"Kotlin\") {\n sections.push(`\n# JVM\ntarget/\nbuild/\n.gradle/\n*.class\n*.jar`);\n }\n\n if (lang === \"Dart\") {\n sections.push(`\n# Dart/Flutter\n.dart_tool/\n.packages\nbuild/`);\n }\n\n if (lang === \"PHP\") {\n sections.push(`\n# PHP\nvendor/\ncomposer.lock`);\n }\n\n if (lang === \"C#\") {\n sections.push(`\n# .NET\nbin/\nobj/\n*.dll`);\n }\n\n if (lang === \"Elixir\") {\n sections.push(`\n# Elixir\n_build/\ndeps/\n.elixir_ls/`);\n }\n\n if (lang === \"Swift\") {\n sections.push(`\n# Swift\n.build/\nDerivedData/\n*.xcuserdata`);\n }\n\n return sections.join(\"\\n\") + \"\\n\";\n}\n","import { Command } from \"commander\";\nimport { printBanner, log, printScoreCard, printIssue } from \"../../lib/output.js\";\nimport { parseClaudeConfig } from \"../../lib/parser.js\";\nimport { analyzeBudget } from \"./analyzers/budget.js\";\nimport { analyzeSettings } from \"./analyzers/settings.js\";\nimport { analyzeHooks } from \"./analyzers/hooks.js\";\nimport { analyzeRules } from \"./analyzers/rules.js\";\nimport { analyzePermissions } from \"./analyzers/permissions.js\";\nimport { analyzeMcp } from \"./analyzers/mcp.js\";\nimport { analyzeQuality } from \"./analyzers/quality.js\";\nimport { applyFixes } from \"./fixer.js\";\nimport { watchConfig } from \"./watcher.js\";\nimport type { AnalyzerResult, DiagnosticIssue } from \"../../types/index.js\";\n\nexport function createDoctorCommand(): Command {\n return new Command(\"doctor\")\n .description(\"Diagnose your Claude Code configuration and report issues\")\n .option(\"-p, --path <path>\", \"Project root path\", process.cwd())\n .option(\"--json\", \"Output as JSON\")\n .option(\"--min-score <n>\", \"Exit non-zero if overall score is below this threshold (for CI)\")\n .option(\"--fix\", \"Auto-apply deterministic fixes for detected issues\")\n .option(\"--watch\", \"Watch for config changes and re-run automatically\")\n .action(async (opts) => {\n if (opts.watch) {\n await watchConfig(opts.path);\n return;\n }\n\n printBanner();\n log.step(\"Scanning Claude Code configuration...\");\n log.blank();\n\n const config = await parseClaudeConfig(opts.path);\n\n if (config.claudeMdContent === null && config.settings === null) {\n log.error(\"No Claude Code configuration found in this directory.\");\n log.info(\"Run `claude-launchpad init` to set up a project, or cd into a configured project.\");\n process.exit(1);\n }\n\n const results: AnalyzerResult[] = await Promise.all([\n analyzeBudget(config),\n analyzeQuality(config),\n analyzeSettings(config),\n analyzeHooks(config),\n analyzeRules(config),\n analyzePermissions(config),\n analyzeMcp(config),\n ]);\n\n if (opts.json) {\n const overallScore = Math.round(\n results.reduce((sum, r) => sum + r.score, 0) / results.length,\n );\n console.log(JSON.stringify({ overallScore, analyzers: results, timestamp: new Date().toISOString() }, null, 2));\n return;\n }\n\n renderReport(results);\n\n // Auto-fix mode\n if (opts.fix) {\n const allIssues = results.flatMap((r) => r.issues);\n const fixable = allIssues.filter((i) => i.severity !== \"info\");\n if (fixable.length > 0) {\n log.blank();\n log.step(\"Applying fixes...\");\n log.blank();\n const { fixed, skipped } = await applyFixes(fixable, opts.path);\n log.blank();\n if (fixed > 0) {\n log.success(`Applied ${fixed} fix(es). Run \\`claude-launchpad doctor\\` again to see your new score.`);\n }\n if (skipped > 0) {\n log.info(`${skipped} issue(s) require manual intervention.`);\n }\n }\n }\n\n // CI mode: exit non-zero if score is below threshold\n if (opts.minScore) {\n const overallScore = Math.round(\n results.reduce((sum, r) => sum + r.score, 0) / results.length,\n );\n const threshold = parseInt(opts.minScore, 10);\n if (overallScore < threshold) {\n process.exit(1);\n }\n }\n });\n}\n\nfunction renderReport(results: ReadonlyArray<AnalyzerResult>): void {\n const overallScore = Math.round(\n results.reduce((sum, r) => sum + r.score, 0) / results.length,\n );\n\n // Score cards\n for (const result of results) {\n printScoreCard(result.name, result.score);\n }\n log.blank();\n printScoreCard(\"Overall\", overallScore);\n log.blank();\n\n // Issues list\n const allIssues = results.flatMap((r) => r.issues);\n const actionable = allIssues.filter((i) => i.severity !== \"info\");\n\n if (actionable.length === 0) {\n log.success(\"No issues found. Your configuration looks solid.\");\n return;\n }\n\n for (const issue of sortBySeverity(actionable)) {\n printIssue(issue.severity, issue.analyzer, issue.message, issue.fix);\n }\n\n log.info(`${actionable.length} issue(s) found. Fix critical/high first.`);\n}\n\nfunction sortBySeverity(issues: ReadonlyArray<DiagnosticIssue>): ReadonlyArray<DiagnosticIssue> {\n const order: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\n return [...issues].sort((a, b) => (order[a.severity] ?? 4) - (order[b.severity] ?? 4));\n}\n","import { readFile, readdir, access } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport type { ClaudeConfig, HookConfig, McpServerConfig } from \"../types/index.js\";\n\nconst CLAUDE_MD = \"CLAUDE.md\";\nconst CLAUDE_DIR = \".claude\";\nconst SETTINGS_FILE = \"settings.json\";\nconst RULES_DIR = \"rules\";\n\nexport async function parseClaudeConfig(projectRoot: string): Promise<ClaudeConfig> {\n const root = resolve(projectRoot);\n const claudeDir = join(root, CLAUDE_DIR);\n\n const [claudeMd, settings, hooks, rules, mcpServers, skills] = await Promise.all([\n readClaudeMd(root),\n readSettings(claudeDir),\n readHooks(claudeDir),\n readRules(claudeDir),\n readMcpServers(claudeDir),\n readSkills(claudeDir),\n ]);\n\n const instructionCount = claudeMd\n ? countInstructions(claudeMd)\n : 0;\n\n return {\n claudeMdPath: claudeMd !== null ? join(root, CLAUDE_MD) : null,\n claudeMdContent: claudeMd,\n claudeMdInstructionCount: instructionCount,\n settingsPath: settings !== null ? join(claudeDir, SETTINGS_FILE) : null,\n settings,\n hooks,\n rules,\n mcpServers,\n skills,\n };\n}\n\n// ─── CLAUDE.md ───\n\nasync function readClaudeMd(root: string): Promise<string | null> {\n return readFileOrNull(join(root, CLAUDE_MD));\n}\n\n/**\n * Count actionable instructions in CLAUDE.md.\n * Heuristic: non-empty, non-comment, non-heading-only lines that contain\n * imperative/declarative content (not blank lines or markdown structure).\n */\nexport function countInstructions(content: string): number {\n const lines = content.split(\"\\n\");\n let count = 0;\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Skip empty lines\n if (trimmed === \"\") continue;\n // Skip pure comments\n if (trimmed.startsWith(\"<!--\") && trimmed.endsWith(\"-->\")) continue;\n // Skip code fence markers\n if (trimmed.startsWith(\"```\")) continue;\n // Skip headings that are just section markers (no instruction content)\n if (/^#{1,6}\\s+\\S/.test(trimmed)) continue;\n // Everything else is an instruction\n count++;\n }\n\n return count;\n}\n\n// ─── Settings ───\n\nasync function readSettings(claudeDir: string): Promise<Record<string, unknown> | null> {\n const raw = await readFileOrNull(join(claudeDir, SETTINGS_FILE));\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n// ─── Hooks ───\n\nasync function readHooks(claudeDir: string): Promise<ReadonlyArray<HookConfig>> {\n const settingsRaw = await readFileOrNull(join(claudeDir, SETTINGS_FILE));\n if (settingsRaw === null) return [];\n\n try {\n const settings = JSON.parse(settingsRaw) as Record<string, unknown>;\n const hooks = settings.hooks as Record<string, unknown[]> | undefined;\n if (!hooks || typeof hooks !== \"object\") return [];\n\n const result: HookConfig[] = [];\n for (const [event, hookList] of Object.entries(hooks)) {\n if (!Array.isArray(hookList)) continue;\n for (const group of hookList) {\n const g = group as Record<string, unknown>;\n const matcher = g.matcher as string | undefined;\n\n // New schema: { matcher, hooks: [{ type, command }] }\n const nestedHooks = g.hooks as Record<string, unknown>[] | undefined;\n if (Array.isArray(nestedHooks)) {\n for (const hook of nestedHooks) {\n const h = hook as Record<string, unknown>;\n result.push({\n event: event as HookConfig[\"event\"],\n type: (h.type as HookConfig[\"type\"]) ?? \"command\",\n matcher,\n command: h.command as string | undefined,\n });\n }\n } else {\n // Legacy flat schema: { matcher, type, command }\n result.push({\n event: event as HookConfig[\"event\"],\n type: (g.type as HookConfig[\"type\"]) ?? \"command\",\n matcher,\n command: g.command as string | undefined,\n });\n }\n }\n }\n return result;\n } catch {\n return [];\n }\n}\n\n// ─── Rules ───\n\nasync function readRules(claudeDir: string): Promise<ReadonlyArray<string>> {\n const rulesDir = join(claudeDir, RULES_DIR);\n return listFilesRecursive(rulesDir, \".md\");\n}\n\n// ─── MCP Servers ───\n\nasync function readMcpServers(claudeDir: string): Promise<ReadonlyArray<McpServerConfig>> {\n const settingsRaw = await readFileOrNull(join(claudeDir, SETTINGS_FILE));\n if (settingsRaw === null) return [];\n\n try {\n const settings = JSON.parse(settingsRaw) as Record<string, unknown>;\n const servers = settings.mcpServers as Record<string, unknown> | undefined;\n if (!servers || typeof servers !== \"object\") return [];\n\n const result: McpServerConfig[] = [];\n for (const [name, config] of Object.entries(servers)) {\n const c = config as Record<string, unknown>;\n result.push({\n name,\n transport: (c.transport as McpServerConfig[\"transport\"]) ?? \"stdio\",\n command: c.command as string | undefined,\n url: c.url as string | undefined,\n });\n }\n return result;\n } catch {\n return [];\n }\n}\n\n// ─── Skills ───\n\nasync function readSkills(claudeDir: string): Promise<ReadonlyArray<string>> {\n const commandsDir = join(claudeDir, \"commands\");\n const skillsDir = join(claudeDir, \"skills\");\n\n const [commands, skills] = await Promise.all([\n listFilesRecursive(commandsDir, \".md\"),\n listFilesRecursive(skillsDir, \".md\"),\n ]);\n\n return [...commands, ...skills];\n}\n\n// ─── Utilities ───\n\nasync function readFileOrNull(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nasync function listFilesRecursive(dir: string, ext: string): Promise<string[]> {\n try {\n await access(dir);\n } catch {\n return [];\n }\n\n const results: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n const nested = await listFilesRecursive(fullPath, ext);\n results.push(...nested);\n } else if (entry.name.endsWith(ext)) {\n results.push(fullPath);\n }\n }\n\n return results;\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nconst BUDGET_WARN = 120;\nconst BUDGET_DANGER = 150;\nconst BUDGET_CRITICAL = 200;\n\nexport async function analyzeBudget(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const count = config.claudeMdInstructionCount;\n\n if (config.claudeMdContent === null) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"high\",\n message: \"No CLAUDE.md found\",\n fix: \"Run `claude-launchpad init` or create CLAUDE.md manually\",\n });\n return { name: \"Instruction Budget\", issues, score: 0 };\n }\n\n if (count === 0) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"medium\",\n message: \"CLAUDE.md exists but has no actionable instructions\",\n fix: \"Add project-specific instructions to CLAUDE.md\",\n });\n return { name: \"Instruction Budget\", issues, score: 30 };\n }\n\n if (count > BUDGET_CRITICAL) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"critical\",\n message: `${count} instructions — way over the ~150 budget. Compliance drops significantly past 150.`,\n fix: \"Move detailed rules to .claude/rules/*.md files. Keep CLAUDE.md to essential project identity.\",\n });\n } else if (count > BUDGET_DANGER) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"high\",\n message: `${count} instructions — over the ~150 budget. Claude may start ignoring lower-priority rules.`,\n fix: \"Move verbose sections (conventions, off-limits details) to .claude/rules/ files.\",\n });\n } else if (count > BUDGET_WARN) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"medium\",\n message: `${count} instructions — approaching the ~150 budget.`,\n fix: \"Consider moving some rules to .claude/rules/ to leave headroom.\",\n });\n }\n\n // Score: 100 if under warn, scales down from there\n let score: number;\n if (count <= BUDGET_WARN) {\n score = 100;\n } else if (count <= BUDGET_DANGER) {\n score = 100 - Math.round(((count - BUDGET_WARN) / (BUDGET_DANGER - BUDGET_WARN)) * 30);\n } else if (count <= BUDGET_CRITICAL) {\n score = 70 - Math.round(((count - BUDGET_DANGER) / (BUDGET_CRITICAL - BUDGET_DANGER)) * 40);\n } else {\n score = Math.max(0, 30 - Math.round((count - BUDGET_CRITICAL) / 5));\n }\n\n return { name: \"Instruction Budget\", issues, score };\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeSettings(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n\n if (config.settings === null) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"medium\",\n message: \"No .claude/settings.json found\",\n fix: \"Run `claude-launchpad init` or create .claude/settings.json\",\n });\n return { name: \"Settings\", issues, score: 40 };\n }\n\n // Check for hooks (the most important setting)\n const hooks = config.settings.hooks as Record<string, unknown> | undefined;\n if (!hooks || Object.keys(hooks).length === 0) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"medium\",\n message: \"settings.json has no hooks configured\",\n fix: \"Run `claude-launchpad doctor --fix` to generate hooks\",\n });\n }\n\n // Plugins are optional — info only, doesn't affect score\n const plugins = config.settings.enabledPlugins as Record<string, boolean> | undefined;\n if (!plugins || Object.keys(plugins).length === 0) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"info\",\n message: \"No plugins enabled — plugins are optional but can add capabilities\",\n });\n }\n\n // Permission rules — only flag if allowedTools is set without security hooks\n const allowedTools = config.settings.allowedTools as string[] | undefined;\n if (allowedTools && allowedTools.length > 0 && config.hooks.length === 0) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"medium\",\n message: \"Tools auto-allowed without any hooks — no safety net for dangerous operations\",\n fix: \"Add PreToolUse hooks for security or remove allowedTools to use interactive prompting\",\n });\n }\n\n // Score: deduct for actionable issues only (not info)\n const actionableCount = issues.filter((i) => i.severity !== \"info\").length;\n const score = Math.max(0, 100 - actionableCount * 20);\n return { name: \"Settings\", issues, score };\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeHooks(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const hooks = config.hooks;\n\n if (hooks.length === 0) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"medium\",\n message: \"No hooks configured — CLAUDE.md rules are advisory (~80% compliance), hooks are 100%\",\n fix: \"Add PostToolUse hooks for auto-formatting and PreToolUse for security gates\",\n });\n return { name: \"Hooks\", issues, score: 30 };\n }\n\n // Check for auto-format hook (prettier, ruff, gofmt, rustfmt, etc.)\n const formatPatterns = [\"format\", \"prettier\", \"gofmt\", \"rustfmt\", \"rubocop\", \"pint\", \"ktlint\", \"swift-format\", \"dotnet format\"];\n const hasPostFormat = hooks.some(\n (h) => h.event === \"PostToolUse\" && h.matcher?.includes(\"Write\") && formatPatterns.some((p) => h.command?.includes(p)),\n );\n if (!hasPostFormat) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"low\",\n message: \"No auto-format hook found\",\n fix: \"Add a PostToolUse hook that runs your formatter on Write|Edit\",\n });\n }\n\n // Check for security gate (env file protection)\n const hasEnvProtection = hooks.some(\n (h) => h.event === \"PreToolUse\" && h.command?.includes(\".env\"),\n );\n if (!hasEnvProtection) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"medium\",\n message: \"No .env file protection hook — Claude could read or write secrets in .env files\",\n fix: \"Add a PreToolUse hook on Read|Write|Edit that blocks access to .env files\",\n });\n }\n\n // Check for PreToolUse hooks (security layer)\n const hasPreToolUse = hooks.some((h) => h.event === \"PreToolUse\");\n if (!hasPreToolUse) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"medium\",\n message: \"No PreToolUse hooks — this is your security enforcement layer\",\n fix: \"Add PreToolUse hooks for file protection and dangerous command blocking\",\n });\n }\n\n const score = Math.max(0, 100 - issues.length * 20);\n return { name: \"Hooks\", issues, score };\n}\n","import { readFile, access } from \"node:fs/promises\";\nimport { basename, join, dirname } from \"node:path\";\nimport type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeRules(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n\n // Check for .claudeignore\n const projectRoot = config.claudeMdPath ? dirname(config.claudeMdPath) : process.cwd();\n const hasClaudeignore = await fileExists(join(projectRoot, \".claudeignore\"));\n if (!hasClaudeignore) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: \"No .claudeignore found — Claude may read noise files (node_modules, dist, lockfiles)\",\n fix: \"Run `claude-launchpad init` or `doctor --fix` to generate one\",\n });\n }\n\n if (config.rules.length === 0) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: \"No .claude/rules/ files found\",\n fix: \"Move detailed conventions from CLAUDE.md to .claude/rules/*.md (auto-loaded, saves budget)\",\n });\n return { name: \"Rules\", issues, score: 60 };\n }\n\n // Check for empty or near-empty rule files\n for (const rulePath of config.rules) {\n try {\n const content = await readFile(rulePath, \"utf-8\");\n const trimmed = content.trim();\n if (trimmed.length === 0) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: `Empty rule file: ${basename(rulePath)}`,\n fix: `Add content to ${basename(rulePath)} or delete it`,\n });\n } else if (trimmed.length < 20) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"info\",\n message: `Very short rule file (${trimmed.length} chars): ${basename(rulePath)}`,\n });\n }\n } catch {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: `Could not read rule file: ${basename(rulePath)}`,\n });\n }\n }\n\n const score = Math.max(0, 100 - issues.length * 10);\n return { name: \"Rules\", issues, score };\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzePermissions(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n\n // Check if Bash is allowed without security hooks\n const hasBashSecurity = config.hooks.some(\n (h) => h.event === \"PreToolUse\" && (h.matcher?.includes(\"Bash\") || !h.matcher),\n );\n\n const bashAllowed = config.settings?.allowedTools as string[] | undefined;\n const hasBashAutoAllow = bashAllowed?.some((t) =>\n typeof t === \"string\" && t.toLowerCase().includes(\"bash\"),\n );\n\n if (hasBashAutoAllow && !hasBashSecurity) {\n issues.push({\n analyzer: \"Permissions\",\n severity: \"high\",\n message: \"Bash is auto-allowed without a security hook — dangerous commands could run unchecked\",\n fix: \"Add a PreToolUse hook for Bash that blocks destructive commands (rm -rf, git push --force)\",\n });\n }\n\n // Check for force push protection\n const hasForceProtection = config.hooks.some(\n (h) => h.event === \"PreToolUse\" && h.command?.includes(\"force\"),\n );\n if (!hasForceProtection) {\n issues.push({\n analyzer: \"Permissions\",\n severity: \"low\",\n message: \"No force-push protection hook\",\n fix: \"Add a PreToolUse hook that warns on `git push --force` commands\",\n });\n }\n\n // Check CLAUDE.md for off-limits section\n if (config.claudeMdContent) {\n const hasOffLimits = config.claudeMdContent.includes(\"## Off-Limits\") ||\n config.claudeMdContent.includes(\"## off-limits\");\n if (!hasOffLimits) {\n issues.push({\n analyzer: \"Permissions\",\n severity: \"medium\",\n message: \"No Off-Limits section in CLAUDE.md — Claude has no guardrails beyond defaults\",\n fix: \"Add an ## Off-Limits section with project-specific restrictions\",\n });\n }\n }\n\n const score = Math.max(0, 100 - issues.length * 20);\n return { name: \"Permissions\", issues, score };\n}\n","import { access } from \"node:fs/promises\";\nimport type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeMcp(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const servers = config.mcpServers;\n\n if (servers.length === 0) {\n issues.push({\n analyzer: \"MCP\",\n severity: \"info\",\n message: \"No MCP servers configured. Run `claude-launchpad enhance` to get stack-specific recommendations.\",\n });\n return { name: \"MCP Servers\", issues, score: 50 };\n }\n\n for (const server of servers) {\n if (server.transport === \"stdio\" && !server.command) {\n issues.push({\n analyzer: \"MCP\",\n severity: \"high\",\n message: `MCP server \"${server.name}\" uses stdio transport but has no command`,\n fix: `Add a \"command\" field to the \"${server.name}\" MCP server config`,\n });\n }\n\n if ((server.transport === \"sse\" || server.transport === \"http\") && !server.url) {\n issues.push({\n analyzer: \"MCP\",\n severity: \"high\",\n message: `MCP server \"${server.name}\" uses ${server.transport} transport but has no URL`,\n fix: `Add a \"url\" field to the \"${server.name}\" MCP server config`,\n });\n }\n\n if (server.transport === \"stdio\" && server.command) {\n const executable = server.command.split(\" \")[0];\n if (executable.startsWith(\"/\") || executable.startsWith(\"./\")) {\n try {\n await access(executable);\n } catch {\n issues.push({\n analyzer: \"MCP\",\n severity: \"medium\",\n message: `MCP server \"${server.name}\" command not found: ${executable}`,\n fix: \"Verify the path exists or install the required package\",\n });\n }\n }\n }\n }\n\n const score = Math.max(0, 100 - issues.filter((i) => i.severity !== \"info\").length * 25);\n return { name: \"MCP Servers\", issues, score };\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nconst ESSENTIAL_SECTIONS = [\n { pattern: /^##\\s+(Tech )?Stack/m, name: \"Stack\", why: \"Claude performs worse without knowing the tech stack\" },\n { pattern: /^##\\s+Commands/m, name: \"Commands\", why: \"Claude guesses wrong without explicit dev/build/test commands\" },\n { pattern: /^##\\s+Session Start/m, name: \"Session Start\", why: \"Without this, Claude won't read TASKS.md or maintain continuity\" },\n { pattern: /^##\\s+Off.?Limits/m, name: \"Off-Limits\", why: \"Without guardrails, Claude has no boundaries beyond defaults\" },\n { pattern: /^##\\s+(Architecture|Project Structure)/m, name: \"Architecture/Structure\", why: \"Claude makes better decisions when it understands the codebase shape\" },\n] as const;\n\nconst VAGUE_PATTERNS = [\n { pattern: /write (good|clean|quality|nice) code/i, label: \"write good code\" },\n { pattern: /be (careful|thorough|diligent)/i, label: \"be careful\" },\n { pattern: /follow best practices/i, label: \"follow best practices\" },\n { pattern: /make sure (everything|it) works/i, label: \"make sure it works\" },\n] as const;\n\nconst SECRET_PATTERNS = [\n { pattern: /sk-[a-zA-Z0-9]{20,}/, label: \"OpenAI API key\" },\n { pattern: /ghp_[a-zA-Z0-9]{36}/, label: \"GitHub personal token\" },\n { pattern: /AKIA[0-9A-Z]{16}/, label: \"AWS access key\" },\n { pattern: /xoxb-[0-9]+-[a-zA-Z0-9]+/, label: \"Slack bot token\" },\n] as const;\n\nexport async function analyzeQuality(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const content = config.claudeMdContent;\n\n if (content === null) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"high\",\n message: \"No CLAUDE.md found\",\n fix: \"Run `claude-launchpad init` to generate one\",\n });\n return { name: \"CLAUDE.md Quality\", issues, score: 0 };\n }\n\n // Check essential sections\n let sectionsFound = 0;\n for (const section of ESSENTIAL_SECTIONS) {\n if (section.pattern.test(content)) {\n sectionsFound++;\n } else {\n issues.push({\n analyzer: \"Quality\",\n severity: \"medium\",\n message: `Missing \"## ${section.name}\" section — ${section.why}`,\n fix: `Add a ## ${section.name} section to CLAUDE.md`,\n });\n }\n }\n\n // Check for vague/useless instructions\n for (const vague of VAGUE_PATTERNS) {\n if (vague.pattern.test(content)) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"low\",\n message: `Vague instruction detected: \"${vague.label}\" — zero signal, wastes budget`,\n fix: \"Replace with specific, actionable instructions\",\n });\n }\n }\n\n // Check for hardcoded secrets\n for (const secret of SECRET_PATTERNS) {\n if (secret.pattern.test(content)) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"critical\",\n message: `Possible ${secret.label} found in CLAUDE.md — secrets must never be in config files`,\n fix: \"Remove the secret immediately and rotate it\",\n });\n }\n }\n\n // Check for TODO placeholders (unfinished config)\n const todoCount = (content.match(/<!--\\s*TODO/gi) ?? []).length;\n if (todoCount > 3) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"medium\",\n message: `${todoCount} TODO placeholders — CLAUDE.md is mostly unfinished`,\n fix: \"Fill in the TODO sections or remove them\",\n });\n }\n\n // Score: base 100, deduct per issue\n const criticals = issues.filter((i) => i.severity === \"critical\").length;\n const highs = issues.filter((i) => i.severity === \"high\").length;\n const mediums = issues.filter((i) => i.severity === \"medium\").length;\n const lows = issues.filter((i) => i.severity === \"low\").length;\n\n const score = Math.max(0, 100 - criticals * 40 - highs * 30 - mediums * 15 - lows * 5);\n return { name: \"CLAUDE.md Quality\", issues, score };\n}\n","import { readFile, writeFile, mkdir, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { log } from \"../../lib/output.js\";\nimport { detectProject } from \"../../lib/detect.js\";\nimport { generateClaudeignore } from \"../init/generators/claudeignore.js\";\nimport type { DiagnosticIssue, DetectedProject } from \"../../types/index.js\";\n\ninterface FixResult {\n readonly fixed: number;\n readonly skipped: number;\n}\n\n/**\n * Auto-apply deterministic fixes for doctor issues.\n * Only applies fixes that are safe and unambiguous.\n */\nexport async function applyFixes(\n issues: ReadonlyArray<DiagnosticIssue>,\n projectRoot: string,\n): Promise<FixResult> {\n const detected = await detectProject(projectRoot);\n let fixed = 0;\n let skipped = 0;\n\n for (const issue of issues) {\n const applied = await tryFix(issue, projectRoot, detected);\n if (applied) {\n fixed++;\n } else {\n skipped++;\n }\n }\n\n return { fixed, skipped };\n}\n\nasync function tryFix(\n issue: DiagnosticIssue,\n root: string,\n detected: DetectedProject,\n): Promise<boolean> {\n // ─── Hooks: No hooks at all (create settings.json from scratch) ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\"No hooks configured\")) {\n const a = await addEnvProtectionHook(root);\n const b = await addAutoFormatHook(root, detected);\n const c = await addForcePushProtection(root);\n return a || b || c;\n }\n\n // ─── Hooks: No .env protection ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\".env file protection\")) {\n return addEnvProtectionHook(root);\n }\n\n // ─── Hooks: No auto-format ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\"auto-format\")) {\n return addAutoFormatHook(root, detected);\n }\n\n // ─── Hooks: No PreToolUse ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\"No PreToolUse\")) {\n return addEnvProtectionHook(root);\n }\n\n // ─── Quality: Missing Architecture section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Architecture\")) {\n return addClaudeMdSection(root, \"## Architecture\", \"<!-- TODO: Describe your codebase structure. Run `claude-launchpad enhance` to auto-fill this. -->\");\n }\n\n // ─── Quality: Missing Off-Limits section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Off-Limits\")) {\n return addClaudeMdSection(root, \"## Off-Limits\", \"- Never hardcode secrets — use environment variables\\n- Never write to `.env` files\\n- Never expose internal error details in API responses\");\n }\n\n // ─── Quality: Missing Commands section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Commands\")) {\n return addClaudeMdSection(root, \"## Commands\", \"<!-- TODO: Add your dev/build/test commands -->\");\n }\n\n // ─── Quality: Missing Stack section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Stack\")) {\n const stackContent = detected.language\n ? `- **Language**: ${detected.language}${detected.framework ? `\\n- **Framework**: ${detected.framework}` : \"\"}${detected.packageManager ? `\\n- **Package Manager**: ${detected.packageManager}` : \"\"}`\n : \"<!-- TODO: Define your tech stack -->\";\n return addClaudeMdSection(root, \"## Stack\", stackContent);\n }\n\n // ─── Quality: Missing Session Start ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Session Start\")) {\n return addClaudeMdSection(root, \"## Session Start\", \"- ALWAYS read @TASKS.md first — it tracks progress across sessions\\n- Update TASKS.md as you complete work\");\n }\n\n // ─── Rules: No .claudeignore ───\n if (issue.analyzer === \"Rules\" && issue.message.includes(\"No .claudeignore\")) {\n return createClaudeignore(root, detected);\n }\n\n // ─── Rules: No rules files ───\n if (issue.analyzer === \"Rules\" && issue.message.includes(\"No .claude/rules/\")) {\n return createStarterRules(root);\n }\n\n // ─── Permissions: No force-push protection ───\n if (issue.analyzer === \"Permissions\" && issue.message.includes(\"force-push\")) {\n return addForcePushProtection(root);\n }\n\n // Can't auto-fix this one\n return false;\n}\n\n// ─── Fix Implementations ───\n\nasync function addEnvProtectionHook(root: string): Promise<boolean> {\n const settings = await readSettingsJson(root);\n const hooks = (settings.hooks ?? {}) as Record<string, unknown>;\n const preToolUse = (hooks.PreToolUse as Record<string, unknown>[] | undefined) ?? [];\n\n // Check if already exists\n const alreadyHas = preToolUse.some((g: Record<string, unknown>) => {\n const nested = g.hooks as Record<string, unknown>[] | undefined;\n return nested?.some((h) => String(h.command ?? \"\").includes(\".env\"));\n });\n\n if (alreadyHas) return false;\n\n preToolUse.push({\n matcher: \"Read|Write|Edit\",\n hooks: [{\n type: \"command\",\n command: \"echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -qE '\\\\.(env|env\\\\..*)$' && ! echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -q '.env.example' && echo 'BLOCKED: .env files contain secrets' && exit 1; exit 0\",\n }],\n });\n\n (settings as Record<string, unknown>).hooks = { ...hooks, PreToolUse: preToolUse };\n await writeSettingsJson(root, settings);\n log.success(\"Added .env file protection hook (PreToolUse)\");\n return true;\n}\n\nasync function addAutoFormatHook(root: string, detected: DetectedProject): Promise<boolean> {\n if (!detected.language) return false;\n\n // Safe formatter commands only — never use detected.formatCommand to prevent injection\n const formatters: Record<string, { extensions: string[]; command: string }> = {\n TypeScript: { extensions: [\"ts\", \"tsx\"], command: \"npx prettier --write\" },\n JavaScript: { extensions: [\"js\", \"jsx\"], command: \"npx prettier --write\" },\n Python: { extensions: [\"py\"], command: \"ruff format\" },\n Go: { extensions: [\"go\"], command: \"gofmt -w\" },\n Rust: { extensions: [\"rs\"], command: \"rustfmt\" },\n Ruby: { extensions: [\"rb\"], command: \"rubocop -A\" },\n PHP: { extensions: [\"php\"], command: \"vendor/bin/pint\" },\n };\n\n const config = formatters[detected.language];\n if (!config) return false;\n\n const settings = await readSettingsJson(root);\n const hooks = (settings.hooks ?? {}) as Record<string, unknown>;\n const postToolUse = (hooks.PostToolUse as Record<string, unknown>[] | undefined) ?? [];\n\n const alreadyHas = postToolUse.some((g: Record<string, unknown>) => {\n const nested = g.hooks as Record<string, unknown>[] | undefined;\n return nested?.some((h) => String(h.command ?? \"\").includes(\"format\"));\n });\n\n if (alreadyHas) return false;\n\n const extChecks = config.extensions.map((ext) => `[ \"$ext\" = \"${ext}\" ]`).join(\" || \");\n\n postToolUse.push({\n matcher: \"Write|Edit\",\n hooks: [{\n type: \"command\",\n command: `ext=\\${TOOL_INPUT_FILE_PATH##*.}; (${extChecks}) && ${config.command} \"$TOOL_INPUT_FILE_PATH\" 2>/dev/null; exit 0`,\n }],\n });\n\n (settings as Record<string, unknown>).hooks = { ...hooks, PostToolUse: postToolUse };\n await writeSettingsJson(root, settings);\n log.success(`Added auto-format hook (PostToolUse → ${config.command})`);\n return true;\n}\n\nasync function addForcePushProtection(root: string): Promise<boolean> {\n const settings = await readSettingsJson(root);\n const hooks = (settings.hooks ?? {}) as Record<string, unknown>;\n const preToolUse = (hooks.PreToolUse as Record<string, unknown>[] | undefined) ?? [];\n\n const alreadyHas = preToolUse.some((g: Record<string, unknown>) => {\n const nested = g.hooks as Record<string, unknown>[] | undefined;\n return nested?.some((h) => String(h.command ?? \"\").includes(\"force\"));\n });\n\n if (alreadyHas) return false;\n\n preToolUse.push({\n matcher: \"Bash\",\n hooks: [{\n type: \"command\",\n command: \"echo \\\"$TOOL_INPUT_COMMAND\\\" | grep -qE 'push.*--force|push.*-f' && echo 'WARNING: Force push detected — this can destroy remote history' && exit 1; exit 0\",\n }],\n });\n\n (settings as Record<string, unknown>).hooks = { ...hooks, PreToolUse: preToolUse };\n await writeSettingsJson(root, settings);\n log.success(\"Added force-push protection hook (PreToolUse → Bash)\");\n return true;\n}\n\nasync function addClaudeMdSection(root: string, heading: string, content: string): Promise<boolean> {\n const claudeMdPath = join(root, \"CLAUDE.md\");\n let existing: string;\n try {\n existing = await readFile(claudeMdPath, \"utf-8\");\n } catch {\n return false; // No CLAUDE.md to add to\n }\n\n // Don't add if section already exists\n if (existing.includes(heading)) return false;\n\n // Append before Key Decisions if it exists, otherwise at end\n const keyDecisionsIdx = existing.indexOf(\"## Key Decisions\");\n const insertAt = keyDecisionsIdx > -1 ? keyDecisionsIdx : existing.length;\n\n const section = `\\n${heading}\\n${content}\\n\\n`;\n const updated = existing.slice(0, insertAt) + section + existing.slice(insertAt);\n\n await writeFile(claudeMdPath, updated);\n log.success(`Added \"${heading}\" section to CLAUDE.md`);\n return true;\n}\n\nasync function createClaudeignore(root: string, detected: DetectedProject): Promise<boolean> {\n const ignorePath = join(root, \".claudeignore\");\n try {\n await access(ignorePath);\n return false; // Already exists\n } catch {\n // Create it\n }\n\n const content = generateClaudeignore(detected);\n await writeFile(ignorePath, content);\n log.success(\"Generated .claudeignore with language-specific ignore patterns\");\n return true;\n}\n\nasync function createStarterRules(root: string): Promise<boolean> {\n const rulesDir = join(root, \".claude\", \"rules\");\n try {\n await access(rulesDir);\n return false; // Already exists\n } catch {\n // Create it\n }\n\n await mkdir(rulesDir, { recursive: true });\n\n await writeFile(\n join(rulesDir, \"conventions.md\"),\n `# Project Conventions\n\n- Use conventional commits (feat:, fix:, docs:, refactor:, test:, chore:)\n- Keep files under 400 lines, functions under 50 lines\n- Handle errors explicitly — no empty catch blocks\n- Validate input at system boundaries\n`,\n );\n\n log.success(\"Created .claude/rules/conventions.md with starter rules\");\n return true;\n}\n\n// ─── Settings JSON helpers ───\n\nasync function readSettingsJson(root: string): Promise<Record<string, unknown>> {\n const path = join(root, \".claude\", \"settings.json\");\n try {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nasync function writeSettingsJson(root: string, settings: Record<string, unknown>): Promise<void> {\n const dir = join(root, \".claude\");\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, \"settings.json\"), JSON.stringify(settings, null, 2) + \"\\n\");\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parseClaudeConfig } from \"../../lib/parser.js\";\nimport { log, printScoreCard, printIssue } from \"../../lib/output.js\";\nimport { analyzeBudget } from \"./analyzers/budget.js\";\nimport { analyzeSettings } from \"./analyzers/settings.js\";\nimport { analyzeHooks } from \"./analyzers/hooks.js\";\nimport { analyzeRules } from \"./analyzers/rules.js\";\nimport { analyzePermissions } from \"./analyzers/permissions.js\";\nimport { analyzeMcp } from \"./analyzers/mcp.js\";\nimport { analyzeQuality } from \"./analyzers/quality.js\";\nimport type { AnalyzerResult } from \"../../types/index.js\";\n\n/**\n * Watch config files for changes using polling (reliable on all OS).\n * Re-runs doctor on every detected change.\n */\nexport async function watchConfig(projectRoot: string): Promise<void> {\n // Initial run\n await runAndDisplay(projectRoot);\n\n log.blank();\n log.info(\"Watching for changes... (Ctrl+C to stop)\");\n log.blank();\n\n // Track file mtimes for change detection\n let lastSnapshot = await getFileSnapshot(projectRoot);\n\n setInterval(async () => {\n const currentSnapshot = await getFileSnapshot(projectRoot);\n if (currentSnapshot !== lastSnapshot) {\n lastSnapshot = currentSnapshot;\n console.clear();\n await runAndDisplay(projectRoot);\n log.blank();\n log.info(\"Watching for changes... (Ctrl+C to stop)\");\n log.blank();\n }\n }, 1000);\n\n // Keep process alive\n await new Promise(() => {});\n}\n\n/**\n * Get a snapshot of all config file mtimes as a string for comparison.\n */\nasync function getFileSnapshot(projectRoot: string): Promise<string> {\n const files = [\n join(projectRoot, \"CLAUDE.md\"),\n join(projectRoot, \".claudeignore\"),\n ];\n\n // Add all files in .claude/\n const claudeDir = join(projectRoot, \".claude\");\n try {\n const entries = await readdir(claudeDir, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n const parentPath = (entry as unknown as { parentPath?: string }).parentPath ?? claudeDir;\n files.push(join(parentPath, entry.name));\n }\n }\n } catch {\n // .claude/ doesn't exist\n }\n\n const mtimes: string[] = [];\n for (const file of files) {\n try {\n const s = await stat(file);\n mtimes.push(`${file}:${s.mtimeMs}`);\n } catch {\n mtimes.push(`${file}:missing`);\n }\n }\n\n return mtimes.join(\"|\");\n}\n\nasync function runAndDisplay(projectRoot: string): Promise<void> {\n console.log(\"\\x1b[36m\\x1b[1m Claude Launchpad\\x1b[0m\");\n console.log(\"\\x1b[2m Scaffold · Diagnose · Evaluate\\x1b[0m\");\n log.blank();\n\n const config = await parseClaudeConfig(projectRoot);\n\n if (config.claudeMdContent === null && config.settings === null) {\n log.error(\"No Claude Code configuration found.\");\n return;\n }\n\n const results: AnalyzerResult[] = await Promise.all([\n analyzeBudget(config),\n analyzeQuality(config),\n analyzeSettings(config),\n analyzeHooks(config),\n analyzeRules(config),\n analyzePermissions(config),\n analyzeMcp(config),\n ]);\n\n const overallScore = Math.round(\n results.reduce((sum, r) => sum + r.score, 0) / results.length,\n );\n\n for (const result of results) {\n printScoreCard(result.name, result.score);\n }\n log.blank();\n printScoreCard(\"Overall\", overallScore);\n log.blank();\n\n const allIssues = results.flatMap((r) => r.issues);\n const actionable = allIssues.filter((i) => i.severity !== \"info\");\n\n if (actionable.length === 0) {\n log.success(\"No issues found. Your configuration looks solid.\");\n return;\n }\n\n const sorted = [...actionable].sort((a, b) => {\n const order: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\n return (order[a.severity] ?? 4) - (order[b.severity] ?? 4);\n });\n\n for (const issue of sorted) {\n printIssue(issue.severity, issue.analyzer, issue.message, issue.fix);\n }\n\n log.info(`${actionable.length} issue(s) found. Fix critical/high first.`);\n}\n","import { Command } from \"commander\";\nimport ora from \"ora\";\nimport chalk from \"chalk\";\nimport { printBanner, log, printScoreCard } from \"../../lib/output.js\";\nimport { loadScenarios } from \"./loader.js\";\nimport { runScenarioWithRetries } from \"./runner.js\";\nimport type { EvalRunResult } from \"../../types/index.js\";\n\nexport function createEvalCommand(): Command {\n return new Command(\"eval\")\n .description(\"Test your Claude Code config against eval scenarios\")\n .option(\"-s, --suite <suite>\", \"Eval suite to run (e.g., security, conventions, workflow)\")\n .option(\"-p, --path <path>\", \"Project root path\", process.cwd())\n .option(\"--scenarios <path>\", \"Custom scenarios directory\")\n .option(\"--runs <n>\", \"Runs per scenario (default: 3)\", \"3\")\n .option(\"--timeout <ms>\", \"Timeout per run in ms (default: 120000)\", \"120000\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--debug\", \"Keep sandbox directories for inspection\")\n .action(async (opts) => {\n printBanner();\n\n // Verify Claude CLI is available\n const claudeAvailable = await checkClaudeCli();\n if (!claudeAvailable) {\n log.error(\"Claude CLI not found. Install it: https://docs.anthropic.com/en/docs/claude-code\");\n log.info(\"The eval command runs Claude headless against scenarios — it requires the CLI.\");\n process.exit(1);\n }\n\n // Load scenarios\n log.step(\"Loading eval scenarios...\");\n const scenarios = await loadScenarios({\n suite: opts.suite,\n customPath: opts.scenarios,\n });\n\n if (scenarios.length === 0) {\n log.warn(\"No matching scenarios found.\");\n if (opts.suite) {\n log.info(`Check that the suite \"${opts.suite}\" exists in the scenarios directory.`);\n }\n return;\n }\n\n log.success(`Loaded ${scenarios.length} scenario(s)`);\n log.blank();\n\n const runs = parseInt(opts.runs, 10);\n const timeout = parseInt(opts.timeout, 10);\n\n // Run scenarios\n const results: EvalRunResult[] = [];\n\n for (const scenario of scenarios) {\n const spinner = ora({\n text: `Running: ${scenario.name} (${runs} run${runs > 1 ? \"s\" : \"\"})`,\n prefixText: \" \",\n }).start();\n\n try {\n const result = await runScenarioWithRetries(\n { ...scenario, runs },\n { projectRoot: opts.path, timeout, debug: opts.debug },\n );\n results.push(result);\n\n if (result.passed) {\n spinner.succeed(`${scenario.name} ${result.score}/${result.maxScore}`);\n } else {\n spinner.fail(`${scenario.name} ${result.score}/${result.maxScore}`);\n }\n } catch (error: unknown) {\n spinner.fail(`${scenario.name} ERROR`);\n const msg = error instanceof Error ? error.message : String(error);\n log.error(` ${msg}`);\n results.push({\n scenario: scenario.name,\n score: 0,\n maxScore: scenario.checks.reduce((s, c) => s + c.points, 0),\n passed: false,\n checks: scenario.checks.map((c) => ({ label: c.label, passed: false, points: c.points })),\n });\n }\n }\n\n log.blank();\n\n if (opts.json) {\n const overallScore = results.reduce((s, r) => s + r.score, 0);\n const overallMax = results.reduce((s, r) => s + r.maxScore, 0);\n console.log(JSON.stringify({\n results,\n overallScore,\n overallMax,\n passed: overallScore >= overallMax * 0.8,\n timestamp: new Date().toISOString(),\n }, null, 2));\n return;\n }\n\n renderEvalReport(results);\n });\n}\n\nfunction renderEvalReport(results: ReadonlyArray<EvalRunResult>): void {\n for (const result of results) {\n const icon = result.passed ? chalk.green(\"✓\") : chalk.red(\"✗\");\n const status = result.passed ? chalk.green(\"PASS\") : chalk.red(\"FAIL\");\n const score = `${result.score}/${result.maxScore}`;\n\n console.log(` ${icon} ${chalk.bold(result.scenario)} ${score} ${status}`);\n\n const failedChecks = result.checks.filter((c) => !c.passed);\n for (const check of failedChecks) {\n console.log(` ${chalk.dim(\"─\")} ${chalk.dim(check.label)}`);\n }\n }\n\n log.blank();\n\n const totalScore = results.reduce((s, r) => s + r.score, 0);\n const totalMax = results.reduce((s, r) => s + r.maxScore, 0);\n const pct = totalMax > 0 ? Math.round((totalScore / totalMax) * 100) : 0;\n\n printScoreCard(\"Config Eval Score\", pct);\n log.blank();\n\n const passed = results.filter((r) => r.passed).length;\n const failed = results.length - passed;\n\n if (failed === 0) {\n log.success(`All ${passed} scenario(s) passed.`);\n } else {\n log.warn(`${passed} passed, ${failed} failed out of ${results.length} scenario(s).`);\n }\n}\n\nasync function checkClaudeCli(): Promise<boolean> {\n const { execFile } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const exec = promisify(execFile);\n\n try {\n await exec(\"claude\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n","import { readFile, readdir, access } from \"node:fs/promises\";\nimport { join, resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse as parseYaml } from \"yaml\";\nimport { validateScenario } from \"./schema.js\";\nimport type { EvalScenario } from \"../../types/index.js\";\n\n/**\n * Find the scenarios directory. Works both in dev (tsx) and bundled (tsup).\n * - Dev: __dirname is src/commands/eval/, scenarios is at ../../../scenarios/\n * - Bundled: __dirname is dist/, scenarios is at ../scenarios/\n * - npm installed: __dirname is node_modules/claude-launchpad/dist/, scenarios is at ../scenarios/\n */\nasync function findScenariosDir(): Promise<string> {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n\n // Try relative to this file (dev mode: src/commands/eval/ → ../../../scenarios/)\n const devPath = resolve(thisDir, \"../../../scenarios\");\n if (await dirExists(devPath)) return devPath;\n\n // Try relative to dist/ (bundled: dist/ → ../scenarios/)\n const bundledPath = resolve(thisDir, \"../scenarios\");\n if (await dirExists(bundledPath)) return bundledPath;\n\n // Try relative to package root (fallback)\n const rootPath = resolve(thisDir, \"../../scenarios\");\n if (await dirExists(rootPath)) return rootPath;\n\n return devPath; // Fall through — will just find 0 scenarios\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Load eval scenarios from a directory. Supports:\n * - Built-in scenarios (shipped in scenarios/)\n * - Custom scenarios from a user-specified path\n */\nexport async function loadScenarios(options: {\n suite?: string;\n customPath?: string;\n}): Promise<ReadonlyArray<EvalScenario>> {\n const { suite, customPath } = options;\n\n const scenarioDir = customPath\n ? resolve(customPath)\n : await findScenariosDir();\n\n const dirs = suite\n ? [join(scenarioDir, suite)]\n : await getSubdirectories(scenarioDir);\n\n // Also check the root dir for flat YAML files\n const allDirs = [scenarioDir, ...dirs];\n\n const scenarios: EvalScenario[] = [];\n\n for (const dir of allDirs) {\n const files = await listYamlFiles(dir);\n for (const file of files) {\n try {\n const content = await readFile(file, \"utf-8\");\n const raw = parseYaml(content);\n const scenario = validateScenario(raw, file);\n scenarios.push(scenario);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.warn(` Warning: Skipping ${file}: ${msg}`);\n }\n }\n }\n\n return scenarios;\n}\n\nasync function getSubdirectories(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => join(dir, e.name));\n } catch {\n return [];\n }\n}\n\nasync function listYamlFiles(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && (e.name.endsWith(\".yaml\") || e.name.endsWith(\".yml\")))\n .map((e) => join(dir, e.name));\n } catch {\n return [];\n }\n}\n","import type { EvalScenario, EvalCheck } from \"../../types/index.js\";\n\n/**\n * Validates a raw parsed YAML object against the EvalScenario schema.\n * Returns a validated scenario or throws with a descriptive error.\n */\nexport function validateScenario(raw: unknown, filePath: string): EvalScenario {\n if (!raw || typeof raw !== \"object\") {\n throw new ScenarioError(filePath, \"Scenario must be a YAML object\");\n }\n\n const obj = raw as Record<string, unknown>;\n\n const name = requireString(obj, \"name\", filePath);\n const description = requireString(obj, \"description\", filePath);\n const prompt = requireString(obj, \"prompt\", filePath);\n const setup = validateSetup(obj.setup, filePath);\n const checks = validateChecks(obj.checks, filePath);\n const passingScore = requireNumber(obj, \"passingScore\", filePath);\n const runs = optionalNumber(obj, \"runs\") ?? 3;\n\n return { name, description, setup, prompt, checks, passingScore, runs };\n}\n\n// ─── Field Validators ───\n\nfunction validateSetup(\n raw: unknown,\n filePath: string,\n): EvalScenario[\"setup\"] {\n if (!raw || typeof raw !== \"object\") {\n throw new ScenarioError(filePath, '\"setup\" must be an object with a \"files\" array');\n }\n\n const obj = raw as Record<string, unknown>;\n const files = obj.files;\n\n if (!Array.isArray(files)) {\n throw new ScenarioError(filePath, '\"setup.files\" must be an array');\n }\n\n const validatedFiles = files.map((f, i) => {\n if (!f || typeof f !== \"object\") {\n throw new ScenarioError(filePath, `setup.files[${i}] must be an object`);\n }\n const file = f as Record<string, unknown>;\n if (typeof file.path !== \"string\" || typeof file.content !== \"string\") {\n throw new ScenarioError(filePath, `setup.files[${i}] must have \"path\" and \"content\" strings`);\n }\n return { path: file.path, content: file.content };\n });\n\n const instructions = typeof obj.instructions === \"string\" ? obj.instructions : undefined;\n\n return { files: validatedFiles, instructions };\n}\n\nfunction validateChecks(raw: unknown, filePath: string): ReadonlyArray<EvalCheck> {\n if (!Array.isArray(raw) || raw.length === 0) {\n throw new ScenarioError(filePath, '\"checks\" must be a non-empty array');\n }\n\n return raw.map((c, i) => {\n if (!c || typeof c !== \"object\") {\n throw new ScenarioError(filePath, `checks[${i}] must be an object`);\n }\n const check = c as Record<string, unknown>;\n\n const validTypes = [\"grep\", \"file-exists\", \"file-absent\", \"max-lines\", \"custom\"];\n if (!validTypes.includes(check.type as string)) {\n throw new ScenarioError(filePath, `checks[${i}].type must be one of: ${validTypes.join(\", \")}`);\n }\n\n if (typeof check.target !== \"string\") {\n throw new ScenarioError(filePath, `checks[${i}].target must be a string`);\n }\n\n const validExpect = [\"present\", \"absent\"];\n if (!validExpect.includes(check.expect as string)) {\n throw new ScenarioError(filePath, `checks[${i}].expect must be \"present\" or \"absent\"`);\n }\n\n if (typeof check.points !== \"number\" || check.points < 0) {\n throw new ScenarioError(filePath, `checks[${i}].points must be a non-negative number`);\n }\n\n if (typeof check.label !== \"string\") {\n throw new ScenarioError(filePath, `checks[${i}].label must be a string`);\n }\n\n return {\n type: check.type as EvalCheck[\"type\"],\n pattern: typeof check.pattern === \"string\" ? check.pattern : undefined,\n target: check.target,\n expect: check.expect as EvalCheck[\"expect\"],\n points: check.points,\n label: check.label,\n };\n });\n}\n\n// ─── Helpers ───\n\nfunction requireString(obj: Record<string, unknown>, key: string, filePath: string): string {\n if (typeof obj[key] !== \"string\" || obj[key] === \"\") {\n throw new ScenarioError(filePath, `\"${key}\" must be a non-empty string`);\n }\n return obj[key] as string;\n}\n\nfunction requireNumber(obj: Record<string, unknown>, key: string, filePath: string): number {\n if (typeof obj[key] !== \"number\") {\n throw new ScenarioError(filePath, `\"${key}\" must be a number`);\n }\n return obj[key] as number;\n}\n\nfunction optionalNumber(obj: Record<string, unknown>, key: string): number | undefined {\n if (obj[key] === undefined) return undefined;\n if (typeof obj[key] !== \"number\") return undefined;\n return obj[key] as number;\n}\n\nclass ScenarioError extends Error {\n constructor(filePath: string, message: string) {\n super(`Invalid scenario ${filePath}: ${message}`);\n this.name = \"ScenarioError\";\n }\n}\n","import { mkdir, writeFile, readFile, readdir, rm } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { randomUUID } from \"node:crypto\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { EvalScenario, EvalRunResult, EvalCheck } from \"../../types/index.js\";\n\nconst exec = promisify(execFile);\n\ninterface RunOptions {\n readonly projectRoot: string;\n readonly timeout: number;\n readonly debug?: boolean;\n}\n\n/**\n * Execute a single eval scenario run using the Agent SDK.\n *\n * 1. Create a temp directory with the scenario's seed files\n * 2. Write a minimal CLAUDE.md with the scenario's instructions\n * 3. Run Claude via Agent SDK with explicit tool permissions\n * 4. Check the results against the scenario's checks\n * 5. Clean up\n */\nexport async function runScenario(\n scenario: EvalScenario,\n options: RunOptions,\n): Promise<EvalRunResult> {\n const sandboxDir = join(tmpdir(), `claude-eval-${randomUUID()}`);\n\n try {\n await setupSandbox(sandboxDir, scenario);\n await runClaudeInSandbox(sandboxDir, scenario.prompt, options.timeout);\n return await scoreResults(scenario, sandboxDir);\n } finally {\n if (options.debug) {\n console.log(` DEBUG: Sandbox preserved at ${sandboxDir}`);\n } else {\n await rm(sandboxDir, { recursive: true, force: true }).catch(() => {});\n }\n }\n}\n\n/**\n * Run a scenario multiple times and return the median result.\n */\nexport async function runScenarioWithRetries(\n scenario: EvalScenario,\n options: RunOptions,\n): Promise<EvalRunResult> {\n const results: EvalRunResult[] = [];\n\n for (let i = 0; i < scenario.runs; i++) {\n const result = await runScenario(scenario, options);\n results.push(result);\n }\n\n const sorted = [...results].sort((a, b) => a.score - b.score);\n return sorted[Math.floor(sorted.length / 2)];\n}\n\n// ─── Sandbox Setup ───\n\nasync function setupSandbox(sandboxDir: string, scenario: EvalScenario): Promise<void> {\n await mkdir(sandboxDir, { recursive: true });\n\n for (const file of scenario.setup.files) {\n const filePath = join(sandboxDir, file.path);\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, file.content);\n }\n\n if (scenario.setup.instructions) {\n await writeFile(\n join(sandboxDir, \"CLAUDE.md\"),\n `# Eval Scenario\\n\\n${scenario.setup.instructions}\\n`,\n );\n }\n\n await exec(\"git\", [\"init\", \"-q\"], { cwd: sandboxDir });\n await exec(\"git\", [\"add\", \"-A\"], { cwd: sandboxDir });\n await exec(\"git\", [\n \"-c\", \"user.name=eval\",\n \"-c\", \"user.email=eval@test\",\n \"commit\", \"-q\", \"-m\", \"eval setup\",\n ], { cwd: sandboxDir });\n}\n\n// ─── Claude Execution ───\n\nasync function runClaudeInSandbox(\n cwd: string,\n prompt: string,\n timeout: number,\n): Promise<void> {\n // Try Agent SDK first, fall back to CLI subprocess\n try {\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\");\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n for await (const _message of sdk.query({\n prompt,\n options: {\n cwd,\n allowedTools: [\"Bash\", \"Read\", \"Write\", \"Edit\", \"Glob\", \"Grep\"],\n permissionMode: \"dontAsk\",\n settingSources: [],\n maxTurns: 20,\n abortController: controller,\n },\n })) {\n // Consume the stream — we only care about side effects (file edits)\n }\n } finally {\n clearTimeout(timeoutId);\n }\n } catch {\n // SDK not available or failed — fall back to CLI\n await runClaudeCli(cwd, prompt, timeout);\n }\n}\n\nasync function runClaudeCli(\n cwd: string,\n prompt: string,\n timeout: number,\n): Promise<void> {\n try {\n await exec(\n \"claude\",\n [\n \"-p\", prompt,\n \"--output-format\", \"text\",\n \"--max-turns\", \"20\",\n \"--dangerously-skip-permissions\",\n \"--allowedTools\", \"Bash\", \"Read\", \"Write\", \"Edit\", \"Glob\", \"Grep\",\n ],\n { cwd, timeout, maxBuffer: 10 * 1024 * 1024 },\n );\n } catch (error: unknown) {\n // Claude might exit non-zero but still produce usable output\n if (error && typeof error === \"object\" && \"stdout\" in error) {\n return; // Files may have been modified despite exit code\n }\n throw error;\n }\n}\n\n// ─── Scoring ───\n\nasync function scoreResults(\n scenario: EvalScenario,\n sandboxDir: string,\n): Promise<EvalRunResult> {\n const checkResults = await evaluateChecks(scenario.checks, sandboxDir);\n\n const score = checkResults\n .filter((c) => c.passed)\n .reduce((sum, c) => sum + c.points, 0);\n\n const maxScore = scenario.checks.reduce((sum, c) => sum + c.points, 0);\n\n return {\n scenario: scenario.name,\n score,\n maxScore,\n passed: score >= scenario.passingScore,\n checks: checkResults,\n };\n}\n\nasync function evaluateChecks(\n checks: ReadonlyArray<EvalCheck>,\n sandboxDir: string,\n): Promise<ReadonlyArray<{ label: string; passed: boolean; points: number }>> {\n const results: { label: string; passed: boolean; points: number }[] = [];\n\n for (const check of checks) {\n const passed = await evaluateSingleCheck(check, sandboxDir);\n results.push({ label: check.label, passed, points: check.points });\n }\n\n return results;\n}\n\nasync function evaluateSingleCheck(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n switch (check.type) {\n case \"grep\":\n return checkGrep(check, sandboxDir);\n case \"file-exists\":\n return checkFileExists(check, sandboxDir);\n case \"file-absent\":\n return checkFileAbsent(check, sandboxDir);\n case \"max-lines\":\n return checkMaxLines(check, sandboxDir);\n case \"custom\":\n return false;\n default:\n return false;\n }\n}\n\n// ─── Individual Check Implementations ───\n\nasync function checkGrep(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n if (!check.pattern) return false;\n try {\n const content = await readFile(join(sandboxDir, check.target), \"utf-8\");\n let found: boolean;\n try {\n found = new RegExp(check.pattern).test(content);\n } catch {\n return false; // Invalid regex\n }\n return check.expect === \"present\" ? found : !found;\n } catch {\n return check.expect === \"absent\";\n }\n}\n\nasync function checkFileExists(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n try {\n await readFile(join(sandboxDir, check.target));\n return check.expect === \"present\";\n } catch {\n return check.expect === \"absent\";\n }\n}\n\nasync function checkFileAbsent(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n try {\n await readFile(join(sandboxDir, check.target));\n return check.expect === \"absent\";\n } catch {\n return check.expect === \"present\";\n }\n}\n\nasync function checkMaxLines(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n const maxLines = parseInt(check.pattern ?? \"800\", 10);\n try {\n const files = await listAllFiles(join(sandboxDir, check.target));\n for (const file of files) {\n const content = await readFile(file, \"utf-8\");\n if (content.split(\"\\n\").length > maxLines) {\n return check.expect === \"absent\";\n }\n }\n return check.expect === \"present\";\n } catch {\n return check.expect === \"absent\";\n }\n}\n\n// ─── Utilities ───\n\nasync function listAllFiles(dir: string): Promise<string[]> {\n const results: string[] = [];\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...await listAllFiles(fullPath));\n } else {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory doesn't exist\n }\n return results;\n}\n","import { Command } from \"commander\";\nimport { spawn, execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { printBanner, log } from \"../../lib/output.js\";\n\nconst execAsync = promisify(execFile);\n\nconst ENHANCE_PROMPT = `Read CLAUDE.md and the project's codebase, then update CLAUDE.md to fill in missing or incomplete sections.\n\nCRITICAL BUDGET RULE: CLAUDE.md must stay UNDER 120 lines of actionable content (not counting headings, blank lines, or comments). Claude Code starts ignoring rules past ~150 instructions. If you need more detail, create .claude/rules/ files instead:\n- Create .claude/rules/conventions.md for detailed coding patterns\n- Create .claude/rules/architecture.md for detailed structure docs\n- Keep CLAUDE.md to HIGH-LEVEL summaries only (3-5 bullets per section max)\n\nSections to fill in or preserve (DO NOT remove any existing section):\n1. **## Stack** — if missing or incomplete, detect and add language, framework, package manager\n2. **## Architecture** — 3-5 bullet points describing the codebase shape (not a full directory tree)\n3. **## Conventions** — max 8 key patterns. Move detailed rules to .claude/rules/conventions.md\n4. **## Off-Limits** — max 8 guardrails specific to this project\n5. **## Key Decisions** — only decisions that affect how Claude should work in this codebase\n6. **MCP server suggestions** — look at what external services the project uses (databases, APIs, storage). If you spot Postgres, Redis, Stripe, GitHub API, or similar, suggest relevant MCP servers the user could add. Print these as suggestions at the end, not in CLAUDE.md.\n\nAlso review .claude/settings.json hooks:\n- Read the existing hooks in .claude/settings.json\n- If you see project-specific patterns that deserve hooks (e.g., protected directories, test file patterns, migration files), suggest adding them\n- DO NOT overwrite existing hooks — only add new ones that are specific to this project\n- Print hook suggestions at the end with the exact JSON to add, don't modify settings.json directly\n\nRules:\n- Don't remove existing content — only add or improve\n- Be specific to THIS project, not generic advice\n- Use bullet points, not paragraphs\n- If a section would exceed 8 bullets, split into a .claude/rules/ file and reference it\n- After editing, count the actionable lines. If over 120, move content to rules files until under`;\n\nexport function createEnhanceCommand(): Command {\n return new Command(\"enhance\")\n .description(\"Use Claude to analyze your codebase and complete CLAUDE.md\")\n .option(\"-p, --path <path>\", \"Project root path\", process.cwd())\n .action(async (opts) => {\n printBanner();\n\n const root = opts.path;\n\n // Check CLAUDE.md exists\n const claudeMdPath = join(root, \"CLAUDE.md\");\n try {\n await access(claudeMdPath);\n } catch {\n log.error(\"No CLAUDE.md found. Run `claude-launchpad init` first.\");\n process.exit(1);\n }\n\n // Check Claude CLI is available\n try {\n await execAsync(\"claude\", [\"--version\"]);\n } catch {\n log.error(\"Claude CLI not found. Install it: https://docs.anthropic.com/en/docs/claude-code\");\n process.exit(1);\n }\n\n log.step(\"Launching Claude to enhance your CLAUDE.md...\");\n log.blank();\n\n const child = spawn(\n \"claude\",\n [ENHANCE_PROMPT],\n { cwd: root, stdio: \"inherit\" },\n );\n\n await new Promise<number>((resolve) => {\n child.on(\"close\", (code) => resolve(code ?? 0));\n });\n\n log.blank();\n log.success(\"Run `claude-launchpad doctor` to check your updated score.\");\n });\n}\n"],"mappings":"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","names":["Command","access","join","readFile","join","readdir","fileExists","join","readFile","Command","readFile","access","join","readFileOrNull","readFile","access","basename","join","fileExists","access","readFile","writeFile","mkdir","access","join","join","readFile","writeFile","access","mkdir","readdir","join","join","readdir","Command","Command","chalk","readFile","readdir","access","join","resolve","dirname","dirname","resolve","access","join","readFile","readdir","mkdir","writeFile","readFile","readdir","join","dirname","Command","chalk","execFile","promisify","exec","Command","execFile","promisify","access","join","promisify","execFile","Command","join","access","resolve","Command","fileExists","join","access"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/init/index.ts","../src/lib/output.ts","../src/lib/fs-utils.ts","../src/lib/detect.ts","../src/commands/init/generators/claude-md.ts","../src/commands/init/generators/tasks-md.ts","../src/commands/init/generators/settings.ts","../src/commands/init/generators/claudeignore.ts","../src/commands/doctor/index.ts","../src/lib/parser.ts","../src/commands/doctor/analyzers/budget.ts","../src/commands/doctor/analyzers/settings.ts","../src/commands/doctor/analyzers/hooks.ts","../src/commands/doctor/analyzers/rules.ts","../src/commands/doctor/analyzers/permissions.ts","../src/commands/doctor/analyzers/mcp.ts","../src/commands/doctor/analyzers/quality.ts","../src/commands/doctor/fixer.ts","../src/commands/doctor/watcher.ts","../src/commands/eval/index.ts","../src/commands/eval/loader.ts","../src/commands/eval/schema.ts","../src/commands/eval/runner.ts","../src/commands/enhance/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { join } from \"node:path\";\nimport { createInitCommand } from \"./commands/init/index.js\";\nimport { createDoctorCommand } from \"./commands/doctor/index.js\";\nimport { createEvalCommand } from \"./commands/eval/index.js\";\nimport { createEnhanceCommand } from \"./commands/enhance/index.js\";\nimport { printBanner, log } from \"./lib/output.js\";\nimport { fileExists } from \"./lib/fs-utils.js\";\n\nconst program = new Command()\n .name(\"claude-launchpad\")\n .description(\"CLI toolkit that makes Claude Code setups measurably good\")\n .version(\"0.3.2\", \"-v, --version\")\n .action(async () => {\n // Default behavior: detect existing config and route accordingly\n const hasConfig = await fileExists(join(process.cwd(), \"CLAUDE.md\"))\n || await fileExists(join(process.cwd(), \".claude\", \"settings.json\"));\n\n if (hasConfig) {\n // Route directly to doctor — it prints its own banner\n await program.commands.find((c) => c.name() === \"doctor\")?.parseAsync([], { from: \"user\" });\n } else {\n printBanner();\n log.info(\"No Claude Code config found in this directory.\");\n log.blank();\n log.step(\"Run `claude-launchpad init` to set up your project\");\n log.step(\"Run `claude-launchpad doctor` to diagnose an existing config\");\n log.step(\"Run `claude-launchpad eval` to test your config quality\");\n log.blank();\n }\n });\n\nprogram.addCommand(createInitCommand());\nprogram.addCommand(createDoctorCommand());\nprogram.addCommand(createEnhanceCommand());\nprogram.addCommand(createEvalCommand());\n\nprogram.parse();\n","import { Command } from \"commander\";\nimport { input, confirm } from \"@inquirer/prompts\";\nimport { writeFile, mkdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { printBanner, log } from \"../../lib/output.js\";\nimport { fileExists } from \"../../lib/fs-utils.js\";\nimport { detectProject } from \"../../lib/detect.js\";\nimport type { InitOptions, DetectedProject } from \"../../types/index.js\";\nimport { generateClaudeMd } from \"./generators/claude-md.js\";\nimport { generateTasksMd } from \"./generators/tasks-md.js\";\nimport { generateSettings } from \"./generators/settings.js\";\nimport { generateClaudeignore } from \"./generators/claudeignore.js\";\n\nexport function createInitCommand(): Command {\n return new Command(\"init\")\n .description(\"Set up Claude Code configuration for any project\")\n .option(\"-n, --name <name>\", \"Project name\")\n .option(\"-y, --yes\", \"Accept all defaults\")\n .action(async (opts) => {\n printBanner();\n\n const root = process.cwd();\n\n // Detect what kind of project this is\n log.step(\"Detecting project...\");\n const detected = await detectProject(root);\n\n if (detected.language) {\n log.success(`Found ${detected.framework ?? detected.language} project`);\n if (detected.packageManager) log.info(`Package manager: ${detected.packageManager}`);\n if (detected.devCommand) log.info(`Dev command: ${detected.devCommand}`);\n if (detected.testCommand) log.info(`Test command: ${detected.testCommand}`);\n } else {\n log.warn(\"Could not detect project type — generating minimal config\");\n }\n log.blank();\n\n // Resolve options\n const name = opts.name ?? detected.name ?? await input({\n message: \"Project name:\",\n validate: (v: string) => (v.trim().length > 0 ? true : \"Name cannot be empty\"),\n });\n\n const description = opts.yes ? \"\" : await input({\n message: \"One-line description (optional):\",\n });\n\n const options: InitOptions = { name: name.trim(), description: description.trim() };\n\n // Check for existing files\n const hasClaudeMd = await fileExists(join(root, \"CLAUDE.md\"));\n if (hasClaudeMd && !opts.yes) {\n const overwrite = await confirm({\n message: \"CLAUDE.md already exists. Overwrite?\",\n default: false,\n });\n if (!overwrite) {\n log.info(\"Keeping existing CLAUDE.md\");\n log.step(\"Tip: run `claude-launchpad doctor` to check your existing config\");\n return;\n }\n }\n\n await scaffold(root, options, detected);\n });\n}\n\nasync function scaffold(root: string, options: InitOptions, detected: DetectedProject): Promise<void> {\n log.step(\"Generating configuration...\");\n\n const claudeMd = generateClaudeMd(options, detected);\n const tasksMd = generateTasksMd(options);\n const settings = generateSettings(detected);\n const claudeignore = generateClaudeignore(detected);\n\n await mkdir(join(root, \".claude\"), { recursive: true });\n\n // Merge with existing settings.json instead of overwriting\n const settingsPath = join(root, \".claude\", \"settings.json\");\n const mergedSettings = await mergeSettings(settingsPath, settings as unknown as Record<string, unknown>);\n\n // Only generate .claudeignore if it doesn't exist\n const claudeignorePath = join(root, \".claudeignore\");\n const hasClaudeignore = await fileExists(claudeignorePath);\n\n const writes: Promise<void>[] = [\n writeFile(join(root, \"CLAUDE.md\"), claudeMd),\n writeFile(join(root, \"TASKS.md\"), tasksMd),\n writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2) + \"\\n\"),\n ];\n\n if (!hasClaudeignore) {\n writes.push(writeFile(claudeignorePath, claudeignore));\n }\n\n await Promise.all(writes);\n\n log.success(\"Generated CLAUDE.md\");\n log.success(\"Generated TASKS.md\");\n log.success(\"Generated .claude/settings.json (merged with existing)\");\n if (!hasClaudeignore) {\n log.success(\"Generated .claudeignore\");\n }\n\n log.blank();\n log.success(\"Done! Run `claude` to start.\");\n log.info(\"Run `claude-launchpad doctor` to check your config quality.\");\n log.blank();\n}\n\n\nasync function mergeSettings(\n existingPath: string,\n generated: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n try {\n const existing = JSON.parse(await readFile(existingPath, \"utf-8\")) as Record<string, unknown>;\n\n // Merge hooks: keep existing hooks, add generated ones that don't conflict\n const existingHooks = (existing.hooks ?? {}) as Record<string, unknown[]>;\n const generatedHooks = (generated.hooks ?? {}) as Record<string, unknown[]>;\n\n const mergedHooks: Record<string, unknown[]> = { ...existingHooks };\n for (const [event, hookList] of Object.entries(generatedHooks)) {\n if (!mergedHooks[event]) {\n mergedHooks[event] = hookList;\n }\n // If event already exists, keep existing (don't duplicate)\n }\n\n return {\n ...existing,\n ...generated,\n hooks: Object.keys(mergedHooks).length > 0 ? mergedHooks : undefined,\n };\n } catch {\n // No existing file — just use generated\n return generated;\n }\n}\n","import chalk from \"chalk\";\nimport type { Severity, AnalyzerResult, DiagnosticIssue } from \"../types/index.js\";\n\n// ─── Colors ───\n\nexport const colors = {\n success: chalk.green,\n error: chalk.red,\n warn: chalk.yellow,\n info: chalk.cyan,\n dim: chalk.dim,\n bold: chalk.bold,\n score: (score: number): string => {\n if (score >= 80) return chalk.green.bold(`${score}%`);\n if (score >= 60) return chalk.yellow.bold(`${score}%`);\n return chalk.red.bold(`${score}%`);\n },\n severity: (sev: Severity): string => {\n const map: Record<Severity, (s: string) => string> = {\n critical: chalk.bgRed.white.bold,\n high: chalk.red.bold,\n medium: chalk.yellow,\n low: chalk.cyan,\n info: chalk.dim,\n };\n return map[sev](` ${sev.toUpperCase()} `);\n },\n} as const;\n\n// ─── Prefixed Output ───\n\nexport const log = {\n success: (msg: string): void => console.log(` ${chalk.green(\"✓\")} ${msg}`),\n error: (msg: string): void => console.log(` ${chalk.red(\"✗\")} ${msg}`),\n warn: (msg: string): void => console.log(` ${chalk.yellow(\"!\")} ${msg}`),\n step: (msg: string): void => console.log(` ${chalk.cyan(\"→\")} ${msg}`),\n info: (msg: string): void => console.log(` ${chalk.dim(\"·\")} ${msg}`),\n blank: (): void => console.log(),\n} as const;\n\n// ─── Banner ───\n\nexport function printBanner(): void {\n log.blank();\n console.log(chalk.cyan.bold(\" Claude Launchpad\"));\n console.log(chalk.dim(\" Scaffold · Diagnose · Evaluate\"));\n log.blank();\n}\n\n// ─── Score Display ───\n\nexport function printScoreCard(label: string, score: number, max: number = 100): void {\n const pct = Math.round((score / max) * 100);\n const bar = renderBar(pct, 20);\n console.log(` ${chalk.bold(label.padEnd(22))} ${bar} ${colors.score(pct).padStart(12)}`);\n}\n\nfunction renderBar(pct: number, width: number): string {\n const filled = Math.round((pct / 100) * width);\n const empty = width - filled;\n const color = pct >= 80 ? chalk.green : pct >= 60 ? chalk.yellow : chalk.red;\n return color(\"━\".repeat(filled)) + chalk.dim(\"─\".repeat(empty));\n}\n\n// ─── Issues List (replaces table) ───\n\nexport function printIssue(severity: Severity, analyzer: string, message: string, fix?: string): void {\n const tag = colors.severity(severity);\n console.log(` ${tag} ${chalk.bold(analyzer)}`);\n console.log(` ${message}`);\n if (fix) {\n console.log(` ${chalk.dim(\"Fix:\")} ${chalk.dim(fix)}`);\n }\n console.log();\n}\n\n// ─── Report Rendering (shared by doctor + watcher) ───\n\nexport function renderDoctorReport(results: ReadonlyArray<AnalyzerResult>): {\n overallScore: number;\n actionableCount: number;\n} {\n const overallScore = Math.round(\n results.reduce((sum, r) => sum + r.score, 0) / results.length,\n );\n\n for (const result of results) {\n printScoreCard(result.name, result.score);\n }\n log.blank();\n printScoreCard(\"Overall\", overallScore);\n log.blank();\n\n const allIssues = results.flatMap((r) => r.issues);\n const actionable = allIssues.filter((i) => i.severity !== \"info\");\n\n if (actionable.length === 0) {\n log.success(\"No issues found. Your configuration looks solid.\");\n return { overallScore, actionableCount: 0 };\n }\n\n const sorted = [...actionable].sort((a, b) => {\n const order: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\n return (order[a.severity] ?? 4) - (order[b.severity] ?? 4);\n });\n\n for (const issue of sorted) {\n printIssue(issue.severity, issue.analyzer, issue.message, issue.fix);\n }\n\n log.info(`${actionable.length} issue(s) found. Fix critical/high first.`);\n return { overallScore, actionableCount: actionable.length };\n}\n","import { readFile, access } from \"node:fs/promises\";\n\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readFileOrNull(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport async function readJsonOrNull<T>(path: string): Promise<T | null> {\n try {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n","import { join, basename } from \"node:path\";\nimport { fileExists, readFileOrNull, readJsonOrNull } from \"./fs-utils.js\";\nimport type { DetectedProject } from \"../types/index.js\";\n\n/**\n * Detect project characteristics by scanning manifest files and directory structure.\n * Works with any stack — no hardcoded list of supported frameworks.\n */\nexport async function detectProject(root: string): Promise<DetectedProject> {\n const name = basename(root);\n\n const [pkgJson, goMod, pyProject, gemfile, cargo, pubspec, composerJson, pomXml, buildGradle, packageSwift, mixExs, csproj, lockfiles] = await Promise.all([\n readJsonOrNull<PackageJson>(join(root, \"package.json\")),\n fileExists(join(root, \"go.mod\")),\n readFileOrNull(join(root, \"pyproject.toml\")),\n fileExists(join(root, \"Gemfile\")),\n fileExists(join(root, \"Cargo.toml\")),\n fileExists(join(root, \"pubspec.yaml\")),\n readJsonOrNull<ComposerJson>(join(root, \"composer.json\")),\n fileExists(join(root, \"pom.xml\")),\n fileExists(join(root, \"build.gradle\")) || fileExists(join(root, \"build.gradle.kts\")),\n fileExists(join(root, \"Package.swift\")),\n fileExists(join(root, \"mix.exs\")),\n globExists(root, \"*.csproj\"),\n detectLockfiles(root),\n ]);\n\n const manifests: ManifestState = {\n pkgJson, goMod, pyProject, gemfile, cargo, pubspec,\n composerJson, pomXml, buildGradle, packageSwift, mixExs, csproj,\n };\n\n const language = detectLanguage(manifests);\n const framework = detectFramework(manifests);\n const packageManager = detectPackageManager(manifests, lockfiles);\n const scripts = detectScripts({ pkgJson, pyProject, goMod, gemfile, composerJson, language });\n\n return {\n name,\n language,\n framework,\n packageManager,\n hasTests: scripts.testCommand !== null,\n hasLinter: scripts.lintCommand !== null,\n hasFormatter: scripts.formatCommand !== null,\n ...scripts,\n };\n}\n\n// ─── Language Detection ───\n\ninterface ManifestState {\n pkgJson: PackageJson | null;\n goMod: boolean;\n pyProject: string | null;\n gemfile: boolean;\n cargo: boolean;\n pubspec: boolean;\n composerJson: ComposerJson | null;\n pomXml: boolean;\n buildGradle: boolean;\n packageSwift: boolean;\n mixExs: boolean;\n csproj: boolean;\n}\n\nfunction detectLanguage(m: ManifestState): string | null {\n if (m.pkgJson?.devDependencies?.typescript || m.pkgJson?.dependencies?.typescript) return \"TypeScript\";\n if (m.pkgJson) return \"JavaScript\";\n if (m.goMod) return \"Go\";\n if (m.pyProject) return \"Python\";\n if (m.gemfile) return \"Ruby\";\n if (m.cargo) return \"Rust\";\n if (m.pubspec) return \"Dart\";\n if (m.composerJson) return \"PHP\";\n if (m.buildGradle) return \"Kotlin\";\n if (m.pomXml) return \"Java\";\n if (m.packageSwift) return \"Swift\";\n if (m.mixExs) return \"Elixir\";\n if (m.csproj) return \"C#\";\n return null;\n}\n\n// ─── Framework Detection ───\n\nfunction detectFramework(m: ManifestState): string | null {\n const deps = { ...m.pkgJson?.dependencies, ...m.pkgJson?.devDependencies };\n\n // JS/TS frameworks\n if (deps.next) return \"Next.js\";\n if (deps.nuxt) return \"Nuxt\";\n if (deps.svelte || deps[\"@sveltejs/kit\"]) return \"SvelteKit\";\n if (deps.astro) return \"Astro\";\n if (deps[\"@angular/core\"]) return \"Angular\";\n if (deps.remix || deps[\"@remix-run/react\"]) return \"Remix\";\n if (deps.vue) return \"Vue\";\n if (deps.react && !deps.next) return \"React\";\n if (deps.express) return \"Express\";\n if (deps.fastify) return \"Fastify\";\n if (deps.hono) return \"Hono\";\n if (deps.nestjs || deps[\"@nestjs/core\"]) return \"NestJS\";\n\n // Python frameworks\n if (m.pyProject) {\n if (m.pyProject.includes(\"fastapi\")) return \"FastAPI\";\n if (m.pyProject.includes(\"django\")) return \"Django\";\n if (m.pyProject.includes(\"flask\")) return \"Flask\";\n }\n\n // PHP frameworks\n if (m.composerJson) {\n const phpDeps = { ...m.composerJson.require, ...m.composerJson[\"require-dev\"] };\n if (phpDeps[\"laravel/framework\"]) return \"Laravel\";\n if (phpDeps[\"symfony/framework-bundle\"]) return \"Symfony\";\n }\n\n // Ruby\n if (m.gemfile) return \"Rails\";\n\n // JVM\n if (m.buildGradle) return \"Gradle\"; // Could be Spring Boot, Android, etc.\n if (m.pomXml) return \"Maven\";\n\n return null;\n}\n\n// ─── Package Manager Detection ───\n\ninterface DetectedLockfiles {\n pnpmLock: boolean;\n yarnLock: boolean;\n bunLock: boolean;\n npmLock: boolean;\n}\n\nasync function detectLockfiles(root: string): Promise<DetectedLockfiles> {\n const [pnpmLock, yarnLock, bunLock, npmLock] = await Promise.all([\n fileExists(join(root, \"pnpm-lock.yaml\")),\n fileExists(join(root, \"yarn.lock\")),\n fileExists(join(root, \"bun.lockb\")),\n fileExists(join(root, \"package-lock.json\")),\n ]);\n return { pnpmLock, yarnLock, bunLock, npmLock };\n}\n\nfunction detectPackageManager(\n m: Pick<ManifestState, \"pkgJson\" | \"goMod\" | \"pyProject\" | \"gemfile\" | \"cargo\" | \"composerJson\">,\n lockfiles: DetectedLockfiles,\n): string | null {\n if (m.pkgJson) {\n // Check packageManager field first (most explicit)\n const pm = m.pkgJson.packageManager;\n if (pm?.startsWith(\"pnpm\")) return \"pnpm\";\n if (pm?.startsWith(\"yarn\")) return \"yarn\";\n if (pm?.startsWith(\"bun\")) return \"bun\";\n if (pm?.startsWith(\"npm\")) return \"npm\";\n\n // Fall back to lockfile detection\n if (lockfiles.pnpmLock) return \"pnpm\";\n if (lockfiles.yarnLock) return \"yarn\";\n if (lockfiles.bunLock) return \"bun\";\n if (lockfiles.npmLock) return \"npm\";\n\n return \"npm\";\n }\n if (m.goMod) return \"go modules\";\n if (m.pyProject) {\n if (m.pyProject.includes(\"[tool.uv]\")) return \"uv\";\n if (m.pyProject.includes(\"[tool.poetry]\")) return \"poetry\";\n return \"pip\";\n }\n if (m.gemfile) return \"bundler\";\n if (m.cargo) return \"cargo\";\n if (m.composerJson) return \"composer\";\n return null;\n}\n\n// ─── Script Detection ───\n\ninterface DetectedScripts {\n formatCommand: string | null;\n lintCommand: string | null;\n testCommand: string | null;\n devCommand: string | null;\n buildCommand: string | null;\n}\n\nfunction detectScripts(m: {\n pkgJson: PackageJson | null;\n pyProject: string | null;\n goMod: boolean;\n gemfile: boolean;\n composerJson: ComposerJson | null;\n language: string | null;\n}): DetectedScripts {\n const scripts = m.pkgJson?.scripts ?? {};\n\n if (m.pkgJson) {\n return {\n devCommand: scripts.dev ? `${pmRun(m.pkgJson)} dev` : null,\n buildCommand: scripts.build ? `${pmRun(m.pkgJson)} build` : null,\n testCommand: scripts.test ? `${pmRun(m.pkgJson)} test` : null,\n lintCommand: scripts.lint ? `${pmRun(m.pkgJson)} lint` : null,\n formatCommand: scripts.format ? `${pmRun(m.pkgJson)} format` : null,\n };\n }\n\n if (m.language === \"Go\") {\n return {\n devCommand: \"go run .\",\n buildCommand: \"go build .\",\n testCommand: \"go test ./...\",\n lintCommand: \"golangci-lint run\",\n formatCommand: \"gofmt -w .\",\n };\n }\n\n if (m.language === \"Python\") {\n const runner = m.pyProject?.includes(\"[tool.uv]\") ? \"uv run\" : \"python -m\";\n return {\n devCommand: null,\n buildCommand: null,\n testCommand: `${runner} pytest`,\n lintCommand: `${runner} ruff check .`,\n formatCommand: `${runner} ruff format .`,\n };\n }\n\n if (m.gemfile) {\n return {\n devCommand: \"bin/dev\",\n buildCommand: null,\n testCommand: \"bin/rails test\",\n lintCommand: \"bin/rubocop\",\n formatCommand: null,\n };\n }\n\n if (m.language === \"PHP\") {\n return {\n devCommand: \"php artisan serve\",\n buildCommand: null,\n testCommand: \"php artisan test\",\n lintCommand: \"vendor/bin/phpstan analyse\",\n formatCommand: \"vendor/bin/pint\",\n };\n }\n\n if (m.language === \"Rust\") {\n return {\n devCommand: \"cargo run\",\n buildCommand: \"cargo build\",\n testCommand: \"cargo test\",\n lintCommand: \"cargo clippy\",\n formatCommand: \"cargo fmt\",\n };\n }\n\n if (m.language === \"Java\" || m.language === \"Kotlin\") {\n return {\n devCommand: null,\n buildCommand: \"mvn package\",\n testCommand: \"mvn test\",\n lintCommand: null,\n formatCommand: null,\n };\n }\n\n if (m.language === \"Swift\") {\n return {\n devCommand: null,\n buildCommand: \"swift build\",\n testCommand: \"swift test\",\n lintCommand: \"swiftlint\",\n formatCommand: \"swift-format format -r .\",\n };\n }\n\n if (m.language === \"Elixir\") {\n return {\n devCommand: \"mix phx.server\",\n buildCommand: \"mix compile\",\n testCommand: \"mix test\",\n lintCommand: \"mix credo\",\n formatCommand: \"mix format\",\n };\n }\n\n if (m.language === \"C#\") {\n return {\n devCommand: \"dotnet run\",\n buildCommand: \"dotnet build\",\n testCommand: \"dotnet test\",\n lintCommand: null,\n formatCommand: \"dotnet format\",\n };\n }\n\n return { devCommand: null, buildCommand: null, testCommand: null, lintCommand: null, formatCommand: null };\n}\n\nfunction pmRun(pkg: PackageJson): string {\n const pm = pkg.packageManager;\n if (pm?.startsWith(\"pnpm\")) return \"pnpm\";\n if (pm?.startsWith(\"yarn\")) return \"yarn\";\n if (pm?.startsWith(\"bun\")) return \"bun\";\n return \"npm run\";\n}\n\n// ─── Utilities ───\n\ninterface PackageJson {\n name?: string;\n packageManager?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\ninterface ComposerJson {\n require?: Record<string, string>;\n \"require-dev\"?: Record<string, string>;\n}\n\nasync function globExists(dir: string, pattern: string): Promise<boolean> {\n const { readdir } = await import(\"node:fs/promises\");\n try {\n const entries = await readdir(dir);\n return entries.some((e) => e.endsWith(pattern.replace(\"*\", \"\")));\n } catch {\n return false;\n }\n}\n","import type { InitOptions, DetectedProject } from \"../../../types/index.js\";\n\nexport function generateClaudeMd(options: InitOptions, detected: DetectedProject): string {\n const sections: string[] = [];\n\n // Header\n sections.push(`# ${options.name}`);\n if (options.description) {\n sections.push(\"\", options.description);\n }\n\n // Stack (auto-detected)\n sections.push(\"\", \"## Stack\");\n if (detected.language) {\n const items: string[] = [];\n if (detected.framework) items.push(`- **Framework**: ${detected.framework}`);\n items.push(`- **Language**: ${detected.language}`);\n if (detected.packageManager) items.push(`- **Package Manager**: ${detected.packageManager}`);\n sections.push(items.join(\"\\n\"));\n } else {\n sections.push(\"<!-- TODO: Define your tech stack -->\");\n }\n\n // Commands (auto-detected)\n sections.push(\"\", \"## Commands\");\n const commands: string[] = [];\n if (detected.devCommand) commands.push(`- Dev: \\`${detected.devCommand}\\``);\n if (detected.buildCommand) commands.push(`- Build: \\`${detected.buildCommand}\\``);\n if (detected.testCommand) commands.push(`- Test: \\`${detected.testCommand}\\``);\n if (detected.lintCommand) commands.push(`- Lint: \\`${detected.lintCommand}\\``);\n if (detected.formatCommand) commands.push(`- Format: \\`${detected.formatCommand}\\``);\n if (commands.length > 0) {\n sections.push(commands.join(\"\\n\"));\n } else {\n sections.push(\"<!-- TODO: Add your dev/build/test commands -->\");\n }\n\n // Session Start\n sections.push(\"\", `## Session Start\n- ALWAYS read @TASKS.md first — it tracks progress across sessions\n- Check the Session Log at the bottom of TASKS.md for where we left off\n- Update TASKS.md as you complete work`);\n\n // Conventions\n sections.push(\"\", `## Conventions\n- Git: Conventional commits (\\`feat:\\`, \\`fix:\\`, \\`docs:\\`, \\`refactor:\\`, \\`test:\\`, \\`chore:\\`)`);\n\n // Off-Limits\n sections.push(\"\", `## Off-Limits\n- Never hardcode secrets — use environment variables\n- Never write to \\`.env\\` files\n- Never expose internal error details in API responses`);\n\n // Key Decisions\n sections.push(\"\", `## Key Decisions\n<!-- Record architectural decisions as you make them -->`);\n\n return sections.join(\"\\n\") + \"\\n\";\n}\n","import type { InitOptions } from \"../../../types/index.js\";\n\nexport function generateTasksMd(options: InitOptions): string {\n return `# ${options.name} — Task Tracker\n\n> Claude: Read this at session start. Keep this file SHORT — only current state matters.\n> Rules: (1) Only show current + next sprint tasks. (2) Completed sprints get one summary line. (3) Session log: max 3 lines per session, keep only last 3 sessions. (4) Target: under 80 lines total.\n\n## Completed Sprints\n\n## Current Sprint: Sprint 1 — Setup\n\n### In Progress\n\n### To Do\n- [ ] Project scaffolding and environment setup\n- [ ] Core feature implementation\n- [ ] Test infrastructure\n\n### Done\n\n## Next Sprint: Sprint 2 — Core Features\n- [ ] ...\n\n## Session Log\n<!-- Keep last 3 sessions only. Max 3 lines each. -->\n`;\n}\n","import type { DetectedProject } from \"../../../types/index.js\";\n\ninterface HookEntry {\n readonly type: \"command\";\n readonly command: string;\n}\n\ninterface HookGroup {\n readonly matcher: string;\n readonly hooks: ReadonlyArray<HookEntry>;\n}\n\ninterface ClaudeSettings {\n readonly hooks?: Record<string, ReadonlyArray<HookGroup>>;\n}\n\n/**\n * Generate .claude/settings.json based on detected project.\n * No third-party plugin dependencies — just hooks that match the project's tooling.\n *\n * Claude Code hook schema:\n * { \"PostToolUse\": [{ \"matcher\": \"Write|Edit\", \"hooks\": [{ \"type\": \"command\", \"command\": \"...\" }] }] }\n */\nexport function generateSettings(detected: DetectedProject): ClaudeSettings {\n const preToolUse: HookGroup[] = [];\n const postToolUse: HookGroup[] = [];\n\n // Universal: .env file protection (block read + write)\n preToolUse.push({\n matcher: \"Read|Write|Edit\",\n hooks: [{\n type: \"command\",\n command: \"echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -qE '\\\\.(env|env\\\\..*)$' && ! echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -q '.env.example' && echo 'BLOCKED: .env files contain secrets — use .env.example for documentation' && exit 1; exit 0\",\n }],\n });\n\n // Auto-format based on detected tooling\n const formatHook = buildFormatHook(detected);\n if (formatHook) {\n postToolUse.push(formatHook);\n }\n\n const hooks: Record<string, ReadonlyArray<HookGroup>> = {};\n if (preToolUse.length > 0) hooks.PreToolUse = preToolUse;\n if (postToolUse.length > 0) hooks.PostToolUse = postToolUse;\n\n return Object.keys(hooks).length > 0 ? { hooks } : {};\n}\n\n// Safe formatter commands — never interpolate user-controlled strings into shell commands\nconst SAFE_FORMATTERS: Record<string, { extensions: string[]; command: string }> = {\n TypeScript: { extensions: [\"ts\", \"tsx\"], command: \"npx prettier --write\" },\n JavaScript: { extensions: [\"js\", \"jsx\"], command: \"npx prettier --write\" },\n Python: { extensions: [\"py\"], command: \"ruff format\" },\n Go: { extensions: [\"go\"], command: \"gofmt -w\" },\n Rust: { extensions: [\"rs\"], command: \"rustfmt\" },\n Ruby: { extensions: [\"rb\"], command: \"rubocop -A\" },\n Dart: { extensions: [\"dart\"], command: \"dart format\" },\n PHP: { extensions: [\"php\"], command: \"vendor/bin/pint\" },\n Kotlin: { extensions: [\"kt\", \"kts\"], command: \"ktlint -F\" },\n Java: { extensions: [\"java\"], command: \"google-java-format -i\" },\n Swift: { extensions: [\"swift\"], command: \"swift-format format -i\" },\n Elixir: { extensions: [\"ex\", \"exs\"], command: \"mix format\" },\n \"C#\": { extensions: [\"cs\"], command: \"dotnet format\" },\n};\n\nfunction buildFormatHook(detected: DetectedProject): HookGroup | null {\n if (!detected.language) return null;\n\n const config = SAFE_FORMATTERS[detected.language];\n if (!config) return null;\n\n const extChecks = config.extensions\n .map((ext) => `[ \"$ext\" = \"${ext}\" ]`)\n .join(\" || \");\n\n // Only use hardcoded safe commands — never interpolate detected.formatCommand\n // to prevent command injection via malicious package.json scripts\n return {\n matcher: \"Write|Edit\",\n hooks: [{\n type: \"command\",\n command: `ext=\\${TOOL_INPUT_FILE_PATH##*.}; (${extChecks}) && ${config.command} \"$TOOL_INPUT_FILE_PATH\" 2>/dev/null; exit 0`,\n }],\n };\n}\n","import type { DetectedProject } from \"../../../types/index.js\";\n\n/**\n * Generate .claudeignore based on detected project type.\n * Prevents Claude from reading noise files that waste context.\n */\nexport function generateClaudeignore(detected: DetectedProject): string {\n const sections: string[] = [\"# Generated by claude-launchpad\"];\n\n // Universal ignores\n sections.push(`\n# Dependencies\nnode_modules/\n.pnp/\n.yarn/\n\n# Build output\ndist/\nbuild/\nout/\n.next/\n.nuxt/\n.output/\n.svelte-kit/\n.vercel/\n.turbo/\n\n# Package manager\npnpm-lock.yaml\npackage-lock.json\nyarn.lock\nbun.lockb\n\n# IDE & OS\n.vscode/\n.idea/\n*.swp\n*.swo\n.DS_Store\nThumbs.db\n\n# Test & coverage\ncoverage/\n.nyc_output/\n__snapshots__/\n\n# Environment (should never be read)\n.env\n.env.*\n!.env.example`);\n\n // Language-specific ignores\n const lang = detected.language;\n\n if (lang === \"Python\") {\n sections.push(`\n# Python\n__pycache__/\n*.pyc\n*.pyo\n.venv/\nvenv/\n.mypy_cache/\n.ruff_cache/\n.pytest_cache/\n*.egg-info/`);\n }\n\n if (lang === \"Go\") {\n sections.push(`\n# Go\nbin/\nvendor/`);\n }\n\n if (lang === \"Rust\") {\n sections.push(`\n# Rust\ntarget/\nCargo.lock`);\n }\n\n if (lang === \"Ruby\") {\n sections.push(`\n# Ruby\nvendor/bundle/\n.bundle/\ntmp/\nlog/`);\n }\n\n if (lang === \"Java\" || lang === \"Kotlin\") {\n sections.push(`\n# JVM\ntarget/\nbuild/\n.gradle/\n*.class\n*.jar`);\n }\n\n if (lang === \"Dart\") {\n sections.push(`\n# Dart/Flutter\n.dart_tool/\n.packages\nbuild/`);\n }\n\n if (lang === \"PHP\") {\n sections.push(`\n# PHP\nvendor/\ncomposer.lock`);\n }\n\n if (lang === \"C#\") {\n sections.push(`\n# .NET\nbin/\nobj/\n*.dll`);\n }\n\n if (lang === \"Elixir\") {\n sections.push(`\n# Elixir\n_build/\ndeps/\n.elixir_ls/`);\n }\n\n if (lang === \"Swift\") {\n sections.push(`\n# Swift\n.build/\nDerivedData/\n*.xcuserdata`);\n }\n\n return sections.join(\"\\n\") + \"\\n\";\n}\n","import { Command } from \"commander\";\nimport { printBanner, log, renderDoctorReport } from \"../../lib/output.js\";\nimport { parseClaudeConfig } from \"../../lib/parser.js\";\nimport { analyzeBudget } from \"./analyzers/budget.js\";\nimport { analyzeSettings } from \"./analyzers/settings.js\";\nimport { analyzeHooks } from \"./analyzers/hooks.js\";\nimport { analyzeRules } from \"./analyzers/rules.js\";\nimport { analyzePermissions } from \"./analyzers/permissions.js\";\nimport { analyzeMcp } from \"./analyzers/mcp.js\";\nimport { analyzeQuality } from \"./analyzers/quality.js\";\nimport { applyFixes } from \"./fixer.js\";\nimport { watchConfig } from \"./watcher.js\";\nimport type { AnalyzerResult } from \"../../types/index.js\";\n\nexport function createDoctorCommand(): Command {\n return new Command(\"doctor\")\n .description(\"Diagnose your Claude Code configuration and report issues\")\n .option(\"-p, --path <path>\", \"Project root path\", process.cwd())\n .option(\"--json\", \"Output as JSON\")\n .option(\"--min-score <n>\", \"Exit non-zero if overall score is below this threshold (for CI)\")\n .option(\"--fix\", \"Auto-apply deterministic fixes for detected issues\")\n .option(\"--watch\", \"Watch for config changes and re-run automatically\")\n .action(async (opts) => {\n if (opts.watch) {\n await watchConfig(opts.path);\n return;\n }\n\n printBanner();\n log.step(\"Scanning Claude Code configuration...\");\n log.blank();\n\n const config = await parseClaudeConfig(opts.path);\n\n if (config.claudeMdContent === null && config.settings === null) {\n log.error(\"No Claude Code configuration found in this directory.\");\n log.info(\"Run `claude-launchpad init` to set up a project, or cd into a configured project.\");\n process.exit(1);\n }\n\n const results: AnalyzerResult[] = await Promise.all([\n analyzeBudget(config),\n analyzeQuality(config),\n analyzeSettings(config),\n analyzeHooks(config),\n analyzeRules(config),\n analyzePermissions(config),\n analyzeMcp(config),\n ]);\n\n if (opts.json) {\n const overallScore = Math.round(\n results.reduce((sum, r) => sum + r.score, 0) / results.length,\n );\n console.log(JSON.stringify({ overallScore, analyzers: results, timestamp: new Date().toISOString() }, null, 2));\n return;\n }\n\n const { overallScore } = renderDoctorReport(results);\n\n // Auto-fix mode\n if (opts.fix) {\n const allIssues = results.flatMap((r) => r.issues);\n const fixable = allIssues.filter((i) => i.severity !== \"info\");\n if (fixable.length > 0) {\n log.blank();\n log.step(\"Applying fixes...\");\n log.blank();\n const { fixed, skipped } = await applyFixes(fixable, opts.path);\n log.blank();\n if (fixed > 0) {\n log.success(`Applied ${fixed} fix(es). Run \\`claude-launchpad doctor\\` again to see your new score.`);\n }\n if (skipped > 0) {\n log.info(`${skipped} issue(s) require manual intervention.`);\n }\n }\n }\n\n // CI mode: exit non-zero if score is below threshold\n if (opts.minScore) {\n const threshold = parseInt(opts.minScore, 10);\n if (overallScore < threshold) {\n process.exit(1);\n }\n }\n });\n}\n","import { readdir, access } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { readFileOrNull } from \"./fs-utils.js\";\nimport type { ClaudeConfig, HookConfig, McpServerConfig } from \"../types/index.js\";\n\nconst CLAUDE_MD = \"CLAUDE.md\";\nconst CLAUDE_DIR = \".claude\";\nconst SETTINGS_FILE = \"settings.json\";\nconst RULES_DIR = \"rules\";\n\nexport async function parseClaudeConfig(projectRoot: string): Promise<ClaudeConfig> {\n const root = resolve(projectRoot);\n const claudeDir = join(root, CLAUDE_DIR);\n\n const [claudeMd, settings, hooks, rules, mcpServers, skills] = await Promise.all([\n readClaudeMd(root),\n readSettings(claudeDir),\n readHooks(claudeDir),\n readRules(claudeDir),\n readMcpServers(claudeDir),\n readSkills(claudeDir),\n ]);\n\n const instructionCount = claudeMd\n ? countInstructions(claudeMd)\n : 0;\n\n return {\n claudeMdPath: claudeMd !== null ? join(root, CLAUDE_MD) : null,\n claudeMdContent: claudeMd,\n claudeMdInstructionCount: instructionCount,\n settingsPath: settings !== null ? join(claudeDir, SETTINGS_FILE) : null,\n settings,\n hooks,\n rules,\n mcpServers,\n skills,\n };\n}\n\n// ─── CLAUDE.md ───\n\nasync function readClaudeMd(root: string): Promise<string | null> {\n return readFileOrNull(join(root, CLAUDE_MD));\n}\n\n/**\n * Count actionable instructions in CLAUDE.md.\n * Heuristic: non-empty, non-comment, non-heading-only lines that contain\n * imperative/declarative content (not blank lines or markdown structure).\n */\nexport function countInstructions(content: string): number {\n const lines = content.split(\"\\n\");\n let count = 0;\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Skip empty lines\n if (trimmed === \"\") continue;\n // Skip pure comments\n if (trimmed.startsWith(\"<!--\") && trimmed.endsWith(\"-->\")) continue;\n // Skip code fence markers\n if (trimmed.startsWith(\"```\")) continue;\n // Skip headings that are just section markers (no instruction content)\n if (/^#{1,6}\\s+\\S/.test(trimmed)) continue;\n // Everything else is an instruction\n count++;\n }\n\n return count;\n}\n\n// ─── Settings ───\n\nasync function readSettings(claudeDir: string): Promise<Record<string, unknown> | null> {\n const raw = await readFileOrNull(join(claudeDir, SETTINGS_FILE));\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n// ─── Hooks ───\n\nasync function readHooks(claudeDir: string): Promise<ReadonlyArray<HookConfig>> {\n const settingsRaw = await readFileOrNull(join(claudeDir, SETTINGS_FILE));\n if (settingsRaw === null) return [];\n\n try {\n const settings = JSON.parse(settingsRaw) as Record<string, unknown>;\n const hooks = settings.hooks as Record<string, unknown[]> | undefined;\n if (!hooks || typeof hooks !== \"object\") return [];\n\n const result: HookConfig[] = [];\n for (const [event, hookList] of Object.entries(hooks)) {\n if (!Array.isArray(hookList)) continue;\n for (const group of hookList) {\n const g = group as Record<string, unknown>;\n const matcher = g.matcher as string | undefined;\n\n // New schema: { matcher, hooks: [{ type, command }] }\n const nestedHooks = g.hooks as Record<string, unknown>[] | undefined;\n if (Array.isArray(nestedHooks)) {\n for (const hook of nestedHooks) {\n const h = hook as Record<string, unknown>;\n result.push({\n event: event as HookConfig[\"event\"],\n type: (h.type as HookConfig[\"type\"]) ?? \"command\",\n matcher,\n command: h.command as string | undefined,\n });\n }\n } else {\n // Legacy flat schema: { matcher, type, command }\n result.push({\n event: event as HookConfig[\"event\"],\n type: (g.type as HookConfig[\"type\"]) ?? \"command\",\n matcher,\n command: g.command as string | undefined,\n });\n }\n }\n }\n return result;\n } catch {\n return [];\n }\n}\n\n// ─── Rules ───\n\nasync function readRules(claudeDir: string): Promise<ReadonlyArray<string>> {\n const rulesDir = join(claudeDir, RULES_DIR);\n return listFilesRecursive(rulesDir, \".md\");\n}\n\n// ─── MCP Servers ───\n\nasync function readMcpServers(claudeDir: string): Promise<ReadonlyArray<McpServerConfig>> {\n const settingsRaw = await readFileOrNull(join(claudeDir, SETTINGS_FILE));\n if (settingsRaw === null) return [];\n\n try {\n const settings = JSON.parse(settingsRaw) as Record<string, unknown>;\n const servers = settings.mcpServers as Record<string, unknown> | undefined;\n if (!servers || typeof servers !== \"object\") return [];\n\n const result: McpServerConfig[] = [];\n for (const [name, config] of Object.entries(servers)) {\n const c = config as Record<string, unknown>;\n result.push({\n name,\n transport: (c.transport as McpServerConfig[\"transport\"]) ?? \"stdio\",\n command: c.command as string | undefined,\n url: c.url as string | undefined,\n });\n }\n return result;\n } catch {\n return [];\n }\n}\n\n// ─── Skills ───\n\nasync function readSkills(claudeDir: string): Promise<ReadonlyArray<string>> {\n const commandsDir = join(claudeDir, \"commands\");\n const skillsDir = join(claudeDir, \"skills\");\n\n const [commands, skills] = await Promise.all([\n listFilesRecursive(commandsDir, \".md\"),\n listFilesRecursive(skillsDir, \".md\"),\n ]);\n\n return [...commands, ...skills];\n}\n\n\nasync function listFilesRecursive(dir: string, ext: string): Promise<string[]> {\n try {\n await access(dir);\n } catch {\n return [];\n }\n\n const results: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n const nested = await listFilesRecursive(fullPath, ext);\n results.push(...nested);\n } else if (entry.name.endsWith(ext)) {\n results.push(fullPath);\n }\n }\n\n return results;\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nconst BUDGET_WARN = 120;\nconst BUDGET_DANGER = 150;\nconst BUDGET_CRITICAL = 200;\n\nexport async function analyzeBudget(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const count = config.claudeMdInstructionCount;\n\n if (config.claudeMdContent === null) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"high\",\n message: \"No CLAUDE.md found\",\n fix: \"Run `claude-launchpad init` or create CLAUDE.md manually\",\n });\n return { name: \"Instruction Budget\", issues, score: 0 };\n }\n\n if (count === 0) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"medium\",\n message: \"CLAUDE.md exists but has no actionable instructions\",\n fix: \"Add project-specific instructions to CLAUDE.md\",\n });\n return { name: \"Instruction Budget\", issues, score: 30 };\n }\n\n if (count > BUDGET_CRITICAL) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"critical\",\n message: `${count} instructions — way over the ~150 budget. Compliance drops significantly past 150.`,\n fix: \"Move detailed rules to .claude/rules/*.md files. Keep CLAUDE.md to essential project identity.\",\n });\n } else if (count > BUDGET_DANGER) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"high\",\n message: `${count} instructions — over the ~150 budget. Claude may start ignoring lower-priority rules.`,\n fix: \"Move verbose sections (conventions, off-limits details) to .claude/rules/ files.\",\n });\n } else if (count > BUDGET_WARN) {\n issues.push({\n analyzer: \"Budget\",\n severity: \"medium\",\n message: `${count} instructions — approaching the ~150 budget.`,\n fix: \"Consider moving some rules to .claude/rules/ to leave headroom.\",\n });\n }\n\n // Score: 100 if under warn, scales down from there\n let score: number;\n if (count <= BUDGET_WARN) {\n score = 100;\n } else if (count <= BUDGET_DANGER) {\n score = 100 - Math.round(((count - BUDGET_WARN) / (BUDGET_DANGER - BUDGET_WARN)) * 30);\n } else if (count <= BUDGET_CRITICAL) {\n score = 70 - Math.round(((count - BUDGET_DANGER) / (BUDGET_CRITICAL - BUDGET_DANGER)) * 40);\n } else {\n score = Math.max(0, 30 - Math.round((count - BUDGET_CRITICAL) / 5));\n }\n\n return { name: \"Instruction Budget\", issues, score };\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeSettings(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n\n if (config.settings === null) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"medium\",\n message: \"No .claude/settings.json found\",\n fix: \"Run `claude-launchpad init` or create .claude/settings.json\",\n });\n return { name: \"Settings\", issues, score: 40 };\n }\n\n // Check for hooks (the most important setting)\n const hooks = config.settings.hooks as Record<string, unknown> | undefined;\n if (!hooks || Object.keys(hooks).length === 0) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"medium\",\n message: \"settings.json has no hooks configured\",\n fix: \"Run `claude-launchpad doctor --fix` to generate hooks\",\n });\n }\n\n // Plugins are optional — info only, doesn't affect score\n const plugins = config.settings.enabledPlugins as Record<string, boolean> | undefined;\n if (!plugins || Object.keys(plugins).length === 0) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"info\",\n message: \"No plugins enabled — plugins are optional but can add capabilities\",\n });\n }\n\n // Permission rules — only flag if allowedTools is set without security hooks\n const allowedTools = config.settings.allowedTools as string[] | undefined;\n if (allowedTools && allowedTools.length > 0 && config.hooks.length === 0) {\n issues.push({\n analyzer: \"Settings\",\n severity: \"medium\",\n message: \"Tools auto-allowed without any hooks — no safety net for dangerous operations\",\n fix: \"Add PreToolUse hooks for security or remove allowedTools to use interactive prompting\",\n });\n }\n\n // Score: deduct for actionable issues only (not info)\n const actionableCount = issues.filter((i) => i.severity !== \"info\").length;\n const score = Math.max(0, 100 - actionableCount * 20);\n return { name: \"Settings\", issues, score };\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeHooks(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const hooks = config.hooks;\n\n if (hooks.length === 0) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"medium\",\n message: \"No hooks configured — CLAUDE.md rules are advisory (~80% compliance), hooks are 100%\",\n fix: \"Add PostToolUse hooks for auto-formatting and PreToolUse for security gates\",\n });\n return { name: \"Hooks\", issues, score: 30 };\n }\n\n // Check for auto-format hook (prettier, ruff, gofmt, rustfmt, etc.)\n const formatPatterns = [\"format\", \"prettier\", \"gofmt\", \"rustfmt\", \"rubocop\", \"pint\", \"ktlint\", \"swift-format\", \"dotnet format\"];\n const hasPostFormat = hooks.some(\n (h) => h.event === \"PostToolUse\" && h.matcher?.includes(\"Write\") && formatPatterns.some((p) => h.command?.includes(p)),\n );\n if (!hasPostFormat) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"low\",\n message: \"No auto-format hook found\",\n fix: \"Add a PostToolUse hook that runs your formatter on Write|Edit\",\n });\n }\n\n // Check for security gate (env file protection)\n const hasEnvProtection = hooks.some(\n (h) => h.event === \"PreToolUse\" && h.command?.includes(\".env\"),\n );\n if (!hasEnvProtection) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"medium\",\n message: \"No .env file protection hook — Claude could read or write secrets in .env files\",\n fix: \"Add a PreToolUse hook on Read|Write|Edit that blocks access to .env files\",\n });\n }\n\n // Check for PreToolUse hooks (security layer)\n const hasPreToolUse = hooks.some((h) => h.event === \"PreToolUse\");\n if (!hasPreToolUse) {\n issues.push({\n analyzer: \"Hooks\",\n severity: \"medium\",\n message: \"No PreToolUse hooks — this is your security enforcement layer\",\n fix: \"Add PreToolUse hooks for file protection and dangerous command blocking\",\n });\n }\n\n const score = Math.max(0, 100 - issues.length * 20);\n return { name: \"Hooks\", issues, score };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { basename, join, dirname } from \"node:path\";\nimport { fileExists } from \"../../../lib/fs-utils.js\";\nimport type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeRules(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n\n // Check for .claudeignore\n const projectRoot = config.claudeMdPath ? dirname(config.claudeMdPath) : process.cwd();\n const hasClaudeignore = await fileExists(join(projectRoot, \".claudeignore\"));\n if (!hasClaudeignore) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: \"No .claudeignore found — Claude may read noise files (node_modules, dist, lockfiles)\",\n fix: \"Run `claude-launchpad init` or `doctor --fix` to generate one\",\n });\n }\n\n if (config.rules.length === 0) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: \"No .claude/rules/ files found\",\n fix: \"Move detailed conventions from CLAUDE.md to .claude/rules/*.md (auto-loaded, saves budget)\",\n });\n return { name: \"Rules\", issues, score: 60 };\n }\n\n // Check for empty or near-empty rule files\n for (const rulePath of config.rules) {\n try {\n const content = await readFile(rulePath, \"utf-8\");\n const trimmed = content.trim();\n if (trimmed.length === 0) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: `Empty rule file: ${basename(rulePath)}`,\n fix: `Add content to ${basename(rulePath)} or delete it`,\n });\n } else if (trimmed.length < 20) {\n issues.push({\n analyzer: \"Rules\",\n severity: \"info\",\n message: `Very short rule file (${trimmed.length} chars): ${basename(rulePath)}`,\n });\n }\n } catch {\n issues.push({\n analyzer: \"Rules\",\n severity: \"low\",\n message: `Could not read rule file: ${basename(rulePath)}`,\n });\n }\n }\n\n const score = Math.max(0, 100 - issues.length * 10);\n return { name: \"Rules\", issues, score };\n}\n\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzePermissions(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n\n // Check if Bash is allowed without security hooks\n const hasBashSecurity = config.hooks.some(\n (h) => h.event === \"PreToolUse\" && (h.matcher?.includes(\"Bash\") || !h.matcher),\n );\n\n const bashAllowed = config.settings?.allowedTools as string[] | undefined;\n const hasBashAutoAllow = bashAllowed?.some((t) =>\n typeof t === \"string\" && t.toLowerCase().includes(\"bash\"),\n );\n\n if (hasBashAutoAllow && !hasBashSecurity) {\n issues.push({\n analyzer: \"Permissions\",\n severity: \"high\",\n message: \"Bash is auto-allowed without a security hook — dangerous commands could run unchecked\",\n fix: \"Add a PreToolUse hook for Bash that blocks destructive commands (rm -rf, git push --force)\",\n });\n }\n\n // Check for force push protection\n const hasForceProtection = config.hooks.some(\n (h) => h.event === \"PreToolUse\" && h.command?.includes(\"force\"),\n );\n if (!hasForceProtection) {\n issues.push({\n analyzer: \"Permissions\",\n severity: \"low\",\n message: \"No force-push protection hook\",\n fix: \"Add a PreToolUse hook that warns on `git push --force` commands\",\n });\n }\n\n // Check CLAUDE.md for off-limits section\n if (config.claudeMdContent) {\n const hasOffLimits = config.claudeMdContent.includes(\"## Off-Limits\") ||\n config.claudeMdContent.includes(\"## off-limits\");\n if (!hasOffLimits) {\n issues.push({\n analyzer: \"Permissions\",\n severity: \"medium\",\n message: \"No Off-Limits section in CLAUDE.md — Claude has no guardrails beyond defaults\",\n fix: \"Add an ## Off-Limits section with project-specific restrictions\",\n });\n }\n }\n\n const score = Math.max(0, 100 - issues.length * 20);\n return { name: \"Permissions\", issues, score };\n}\n","import { access } from \"node:fs/promises\";\nimport type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nexport async function analyzeMcp(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const servers = config.mcpServers;\n\n if (servers.length === 0) {\n issues.push({\n analyzer: \"MCP\",\n severity: \"info\",\n message: \"No MCP servers configured. Run `claude-launchpad enhance` to get stack-specific recommendations.\",\n });\n return { name: \"MCP Servers\", issues, score: 50 };\n }\n\n for (const server of servers) {\n if (server.transport === \"stdio\" && !server.command) {\n issues.push({\n analyzer: \"MCP\",\n severity: \"high\",\n message: `MCP server \"${server.name}\" uses stdio transport but has no command`,\n fix: `Add a \"command\" field to the \"${server.name}\" MCP server config`,\n });\n }\n\n if ((server.transport === \"sse\" || server.transport === \"http\") && !server.url) {\n issues.push({\n analyzer: \"MCP\",\n severity: \"high\",\n message: `MCP server \"${server.name}\" uses ${server.transport} transport but has no URL`,\n fix: `Add a \"url\" field to the \"${server.name}\" MCP server config`,\n });\n }\n\n if (server.transport === \"stdio\" && server.command) {\n const executable = server.command.split(\" \")[0];\n if (executable.startsWith(\"/\") || executable.startsWith(\"./\")) {\n try {\n await access(executable);\n } catch {\n issues.push({\n analyzer: \"MCP\",\n severity: \"medium\",\n message: `MCP server \"${server.name}\" command not found: ${executable}`,\n fix: \"Verify the path exists or install the required package\",\n });\n }\n }\n }\n }\n\n const score = Math.max(0, 100 - issues.filter((i) => i.severity !== \"info\").length * 25);\n return { name: \"MCP Servers\", issues, score };\n}\n","import type { ClaudeConfig, AnalyzerResult, DiagnosticIssue } from \"../../../types/index.js\";\n\nconst ESSENTIAL_SECTIONS = [\n { pattern: /^##\\s+(Tech )?Stack/m, name: \"Stack\", why: \"Claude performs worse without knowing the tech stack\" },\n { pattern: /^##\\s+Commands/m, name: \"Commands\", why: \"Claude guesses wrong without explicit dev/build/test commands\" },\n { pattern: /^##\\s+Session Start/m, name: \"Session Start\", why: \"Without this, Claude won't read TASKS.md or maintain continuity\" },\n { pattern: /^##\\s+Off.?Limits/m, name: \"Off-Limits\", why: \"Without guardrails, Claude has no boundaries beyond defaults\" },\n { pattern: /^##\\s+(Architecture|Project Structure)/m, name: \"Architecture/Structure\", why: \"Claude makes better decisions when it understands the codebase shape\" },\n] as const;\n\nconst VAGUE_PATTERNS = [\n { pattern: /write (good|clean|quality|nice) code/i, label: \"write good code\" },\n { pattern: /be (careful|thorough|diligent)/i, label: \"be careful\" },\n { pattern: /follow best practices/i, label: \"follow best practices\" },\n { pattern: /make sure (everything|it) works/i, label: \"make sure it works\" },\n] as const;\n\nconst SECRET_PATTERNS = [\n { pattern: /sk-[a-zA-Z0-9]{20,}/, label: \"OpenAI API key\" },\n { pattern: /ghp_[a-zA-Z0-9]{36}/, label: \"GitHub personal token\" },\n { pattern: /AKIA[0-9A-Z]{16}/, label: \"AWS access key\" },\n { pattern: /xoxb-[0-9]+-[a-zA-Z0-9]+/, label: \"Slack bot token\" },\n] as const;\n\nexport async function analyzeQuality(config: ClaudeConfig): Promise<AnalyzerResult> {\n const issues: DiagnosticIssue[] = [];\n const content = config.claudeMdContent;\n\n if (content === null) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"high\",\n message: \"No CLAUDE.md found\",\n fix: \"Run `claude-launchpad init` to generate one\",\n });\n return { name: \"CLAUDE.md Quality\", issues, score: 0 };\n }\n\n // Check essential sections\n let sectionsFound = 0;\n for (const section of ESSENTIAL_SECTIONS) {\n if (section.pattern.test(content)) {\n sectionsFound++;\n } else {\n issues.push({\n analyzer: \"Quality\",\n severity: \"medium\",\n message: `Missing \"## ${section.name}\" section — ${section.why}`,\n fix: `Add a ## ${section.name} section to CLAUDE.md`,\n });\n }\n }\n\n // Check for vague/useless instructions\n for (const vague of VAGUE_PATTERNS) {\n if (vague.pattern.test(content)) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"low\",\n message: `Vague instruction detected: \"${vague.label}\" — zero signal, wastes budget`,\n fix: \"Replace with specific, actionable instructions\",\n });\n }\n }\n\n // Check for hardcoded secrets\n for (const secret of SECRET_PATTERNS) {\n if (secret.pattern.test(content)) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"critical\",\n message: `Possible ${secret.label} found in CLAUDE.md — secrets must never be in config files`,\n fix: \"Remove the secret immediately and rotate it\",\n });\n }\n }\n\n // Check for TODO placeholders (unfinished config)\n const todoCount = (content.match(/<!--\\s*TODO/gi) ?? []).length;\n if (todoCount > 3) {\n issues.push({\n analyzer: \"Quality\",\n severity: \"medium\",\n message: `${todoCount} TODO placeholders — CLAUDE.md is mostly unfinished`,\n fix: \"Fill in the TODO sections or remove them\",\n });\n }\n\n // Score: base 100, deduct per issue\n const criticals = issues.filter((i) => i.severity === \"critical\").length;\n const highs = issues.filter((i) => i.severity === \"high\").length;\n const mediums = issues.filter((i) => i.severity === \"medium\").length;\n const lows = issues.filter((i) => i.severity === \"low\").length;\n\n const score = Math.max(0, 100 - criticals * 40 - highs * 30 - mediums * 15 - lows * 5);\n return { name: \"CLAUDE.md Quality\", issues, score };\n}\n","import { readFile, writeFile, mkdir, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { log } from \"../../lib/output.js\";\nimport { detectProject } from \"../../lib/detect.js\";\nimport { generateClaudeignore } from \"../init/generators/claudeignore.js\";\nimport type { DiagnosticIssue, DetectedProject } from \"../../types/index.js\";\n\ninterface FixResult {\n readonly fixed: number;\n readonly skipped: number;\n}\n\n/**\n * Auto-apply deterministic fixes for doctor issues.\n * Only applies fixes that are safe and unambiguous.\n */\nexport async function applyFixes(\n issues: ReadonlyArray<DiagnosticIssue>,\n projectRoot: string,\n): Promise<FixResult> {\n const detected = await detectProject(projectRoot);\n let fixed = 0;\n let skipped = 0;\n\n for (const issue of issues) {\n const applied = await tryFix(issue, projectRoot, detected);\n if (applied) {\n fixed++;\n } else {\n skipped++;\n }\n }\n\n return { fixed, skipped };\n}\n\nasync function tryFix(\n issue: DiagnosticIssue,\n root: string,\n detected: DetectedProject,\n): Promise<boolean> {\n // ─── Hooks: No hooks at all (create settings.json from scratch) ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\"No hooks configured\")) {\n const a = await addEnvProtectionHook(root);\n const b = await addAutoFormatHook(root, detected);\n const c = await addForcePushProtection(root);\n return a || b || c;\n }\n\n // ─── Hooks: No .env protection ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\".env file protection\")) {\n return addEnvProtectionHook(root);\n }\n\n // ─── Hooks: No auto-format ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\"auto-format\")) {\n return addAutoFormatHook(root, detected);\n }\n\n // ─── Hooks: No PreToolUse ───\n if (issue.analyzer === \"Hooks\" && issue.message.includes(\"No PreToolUse\")) {\n return addEnvProtectionHook(root);\n }\n\n // ─── Quality: Missing Architecture section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Architecture\")) {\n return addClaudeMdSection(root, \"## Architecture\", \"<!-- TODO: Describe your codebase structure. Run `claude-launchpad enhance` to auto-fill this. -->\");\n }\n\n // ─── Quality: Missing Off-Limits section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Off-Limits\")) {\n return addClaudeMdSection(root, \"## Off-Limits\", \"- Never hardcode secrets — use environment variables\\n- Never write to `.env` files\\n- Never expose internal error details in API responses\");\n }\n\n // ─── Quality: Missing Commands section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Commands\")) {\n return addClaudeMdSection(root, \"## Commands\", \"<!-- TODO: Add your dev/build/test commands -->\");\n }\n\n // ─── Quality: Missing Stack section ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Stack\")) {\n const stackContent = detected.language\n ? `- **Language**: ${detected.language}${detected.framework ? `\\n- **Framework**: ${detected.framework}` : \"\"}${detected.packageManager ? `\\n- **Package Manager**: ${detected.packageManager}` : \"\"}`\n : \"<!-- TODO: Define your tech stack -->\";\n return addClaudeMdSection(root, \"## Stack\", stackContent);\n }\n\n // ─── Quality: Missing Session Start ───\n if (issue.analyzer === \"Quality\" && issue.message.includes(\"Session Start\")) {\n return addClaudeMdSection(root, \"## Session Start\", \"- ALWAYS read @TASKS.md first — it tracks progress across sessions\\n- Update TASKS.md as you complete work\");\n }\n\n // ─── Rules: No .claudeignore ───\n if (issue.analyzer === \"Rules\" && issue.message.includes(\"No .claudeignore\")) {\n return createClaudeignore(root, detected);\n }\n\n // ─── Rules: No rules files ───\n if (issue.analyzer === \"Rules\" && issue.message.includes(\"No .claude/rules/\")) {\n return createStarterRules(root);\n }\n\n // ─── Permissions: No force-push protection ───\n if (issue.analyzer === \"Permissions\" && issue.message.includes(\"force-push\")) {\n return addForcePushProtection(root);\n }\n\n // Can't auto-fix this one\n return false;\n}\n\n// ─── Fix Implementations ───\n\nasync function addEnvProtectionHook(root: string): Promise<boolean> {\n const settings = await readSettingsJson(root);\n const hooks = (settings.hooks ?? {}) as Record<string, unknown>;\n const preToolUse = (hooks.PreToolUse as Record<string, unknown>[] | undefined) ?? [];\n\n // Check if already exists\n const alreadyHas = preToolUse.some((g: Record<string, unknown>) => {\n const nested = g.hooks as Record<string, unknown>[] | undefined;\n return nested?.some((h) => String(h.command ?? \"\").includes(\".env\"));\n });\n\n if (alreadyHas) return false;\n\n preToolUse.push({\n matcher: \"Read|Write|Edit\",\n hooks: [{\n type: \"command\",\n command: \"echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -qE '\\\\.(env|env\\\\..*)$' && ! echo \\\"$TOOL_INPUT_FILE_PATH\\\" | grep -q '.env.example' && echo 'BLOCKED: .env files contain secrets' && exit 1; exit 0\",\n }],\n });\n\n (settings as Record<string, unknown>).hooks = { ...hooks, PreToolUse: preToolUse };\n await writeSettingsJson(root, settings);\n log.success(\"Added .env file protection hook (PreToolUse)\");\n return true;\n}\n\nasync function addAutoFormatHook(root: string, detected: DetectedProject): Promise<boolean> {\n if (!detected.language) return false;\n\n // Safe formatter commands only — never use detected.formatCommand to prevent injection\n const formatters: Record<string, { extensions: string[]; command: string }> = {\n TypeScript: { extensions: [\"ts\", \"tsx\"], command: \"npx prettier --write\" },\n JavaScript: { extensions: [\"js\", \"jsx\"], command: \"npx prettier --write\" },\n Python: { extensions: [\"py\"], command: \"ruff format\" },\n Go: { extensions: [\"go\"], command: \"gofmt -w\" },\n Rust: { extensions: [\"rs\"], command: \"rustfmt\" },\n Ruby: { extensions: [\"rb\"], command: \"rubocop -A\" },\n PHP: { extensions: [\"php\"], command: \"vendor/bin/pint\" },\n };\n\n const config = formatters[detected.language];\n if (!config) return false;\n\n const settings = await readSettingsJson(root);\n const hooks = (settings.hooks ?? {}) as Record<string, unknown>;\n const postToolUse = (hooks.PostToolUse as Record<string, unknown>[] | undefined) ?? [];\n\n const alreadyHas = postToolUse.some((g: Record<string, unknown>) => {\n const nested = g.hooks as Record<string, unknown>[] | undefined;\n return nested?.some((h) => String(h.command ?? \"\").includes(\"format\"));\n });\n\n if (alreadyHas) return false;\n\n const extChecks = config.extensions.map((ext) => `[ \"$ext\" = \"${ext}\" ]`).join(\" || \");\n\n postToolUse.push({\n matcher: \"Write|Edit\",\n hooks: [{\n type: \"command\",\n command: `ext=\\${TOOL_INPUT_FILE_PATH##*.}; (${extChecks}) && ${config.command} \"$TOOL_INPUT_FILE_PATH\" 2>/dev/null; exit 0`,\n }],\n });\n\n (settings as Record<string, unknown>).hooks = { ...hooks, PostToolUse: postToolUse };\n await writeSettingsJson(root, settings);\n log.success(`Added auto-format hook (PostToolUse → ${config.command})`);\n return true;\n}\n\nasync function addForcePushProtection(root: string): Promise<boolean> {\n const settings = await readSettingsJson(root);\n const hooks = (settings.hooks ?? {}) as Record<string, unknown>;\n const preToolUse = (hooks.PreToolUse as Record<string, unknown>[] | undefined) ?? [];\n\n const alreadyHas = preToolUse.some((g: Record<string, unknown>) => {\n const nested = g.hooks as Record<string, unknown>[] | undefined;\n return nested?.some((h) => String(h.command ?? \"\").includes(\"force\"));\n });\n\n if (alreadyHas) return false;\n\n preToolUse.push({\n matcher: \"Bash\",\n hooks: [{\n type: \"command\",\n command: \"echo \\\"$TOOL_INPUT_COMMAND\\\" | grep -qE 'push.*--force|push.*-f' && echo 'WARNING: Force push detected — this can destroy remote history' && exit 1; exit 0\",\n }],\n });\n\n (settings as Record<string, unknown>).hooks = { ...hooks, PreToolUse: preToolUse };\n await writeSettingsJson(root, settings);\n log.success(\"Added force-push protection hook (PreToolUse → Bash)\");\n return true;\n}\n\nasync function addClaudeMdSection(root: string, heading: string, content: string): Promise<boolean> {\n const claudeMdPath = join(root, \"CLAUDE.md\");\n let existing: string;\n try {\n existing = await readFile(claudeMdPath, \"utf-8\");\n } catch {\n return false; // No CLAUDE.md to add to\n }\n\n // Don't add if section already exists\n if (existing.includes(heading)) return false;\n\n // Append before Key Decisions if it exists, otherwise at end\n const keyDecisionsIdx = existing.indexOf(\"## Key Decisions\");\n const insertAt = keyDecisionsIdx > -1 ? keyDecisionsIdx : existing.length;\n\n const section = `\\n${heading}\\n${content}\\n\\n`;\n const updated = existing.slice(0, insertAt) + section + existing.slice(insertAt);\n\n await writeFile(claudeMdPath, updated);\n log.success(`Added \"${heading}\" section to CLAUDE.md`);\n return true;\n}\n\nasync function createClaudeignore(root: string, detected: DetectedProject): Promise<boolean> {\n const ignorePath = join(root, \".claudeignore\");\n try {\n await access(ignorePath);\n return false; // Already exists\n } catch {\n // Create it\n }\n\n const content = generateClaudeignore(detected);\n await writeFile(ignorePath, content);\n log.success(\"Generated .claudeignore with language-specific ignore patterns\");\n return true;\n}\n\nasync function createStarterRules(root: string): Promise<boolean> {\n const rulesDir = join(root, \".claude\", \"rules\");\n try {\n await access(rulesDir);\n return false; // Already exists\n } catch {\n // Create it\n }\n\n await mkdir(rulesDir, { recursive: true });\n\n await writeFile(\n join(rulesDir, \"conventions.md\"),\n `# Project Conventions\n\n- Use conventional commits (feat:, fix:, docs:, refactor:, test:, chore:)\n- Keep files under 400 lines, functions under 50 lines\n- Handle errors explicitly — no empty catch blocks\n- Validate input at system boundaries\n`,\n );\n\n log.success(\"Created .claude/rules/conventions.md with starter rules\");\n return true;\n}\n\n// ─── Settings JSON helpers ───\n\nasync function readSettingsJson(root: string): Promise<Record<string, unknown>> {\n const path = join(root, \".claude\", \"settings.json\");\n try {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nasync function writeSettingsJson(root: string, settings: Record<string, unknown>): Promise<void> {\n const dir = join(root, \".claude\");\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, \"settings.json\"), JSON.stringify(settings, null, 2) + \"\\n\");\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parseClaudeConfig } from \"../../lib/parser.js\";\nimport { log, renderDoctorReport } from \"../../lib/output.js\";\nimport { analyzeBudget } from \"./analyzers/budget.js\";\nimport { analyzeSettings } from \"./analyzers/settings.js\";\nimport { analyzeHooks } from \"./analyzers/hooks.js\";\nimport { analyzeRules } from \"./analyzers/rules.js\";\nimport { analyzePermissions } from \"./analyzers/permissions.js\";\nimport { analyzeMcp } from \"./analyzers/mcp.js\";\nimport { analyzeQuality } from \"./analyzers/quality.js\";\nimport type { AnalyzerResult } from \"../../types/index.js\";\n\n/**\n * Watch config files for changes using polling (reliable on all OS).\n * Re-runs doctor on every detected change.\n */\nexport async function watchConfig(projectRoot: string): Promise<void> {\n await runAndDisplay(projectRoot);\n\n log.blank();\n log.info(\"Watching for changes... (Ctrl+C to stop)\");\n log.blank();\n\n let lastSnapshot = await getFileSnapshot(projectRoot);\n\n setInterval(async () => {\n const currentSnapshot = await getFileSnapshot(projectRoot);\n if (currentSnapshot !== lastSnapshot) {\n lastSnapshot = currentSnapshot;\n console.clear();\n await runAndDisplay(projectRoot);\n log.blank();\n log.info(\"Watching for changes... (Ctrl+C to stop)\");\n log.blank();\n }\n }, 1000);\n\n await new Promise(() => {});\n}\n\nasync function getFileSnapshot(projectRoot: string): Promise<string> {\n const files = [\n join(projectRoot, \"CLAUDE.md\"),\n join(projectRoot, \".claudeignore\"),\n ];\n\n const claudeDir = join(projectRoot, \".claude\");\n try {\n const entries = await readdir(claudeDir, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n const parentPath = (entry as unknown as { parentPath?: string }).parentPath ?? claudeDir;\n files.push(join(parentPath, entry.name));\n }\n }\n } catch {\n // .claude/ doesn't exist\n }\n\n const mtimes: string[] = [];\n for (const file of files) {\n try {\n const s = await stat(file);\n mtimes.push(`${file}:${s.mtimeMs}`);\n } catch {\n mtimes.push(`${file}:missing`);\n }\n }\n\n return mtimes.join(\"|\");\n}\n\nasync function runAndDisplay(projectRoot: string): Promise<void> {\n console.log(\"\\x1b[36m\\x1b[1m Claude Launchpad\\x1b[0m\");\n console.log(\"\\x1b[2m Scaffold · Diagnose · Evaluate\\x1b[0m\");\n log.blank();\n\n const config = await parseClaudeConfig(projectRoot);\n\n if (config.claudeMdContent === null && config.settings === null) {\n log.error(\"No Claude Code configuration found.\");\n return;\n }\n\n const results: AnalyzerResult[] = await Promise.all([\n analyzeBudget(config),\n analyzeQuality(config),\n analyzeSettings(config),\n analyzeHooks(config),\n analyzeRules(config),\n analyzePermissions(config),\n analyzeMcp(config),\n ]);\n\n renderDoctorReport(results);\n}\n","import { Command } from \"commander\";\nimport ora from \"ora\";\nimport chalk from \"chalk\";\nimport { printBanner, log, printScoreCard } from \"../../lib/output.js\";\nimport { loadScenarios } from \"./loader.js\";\nimport { runScenarioWithRetries } from \"./runner.js\";\nimport type { EvalRunResult } from \"../../types/index.js\";\n\nexport function createEvalCommand(): Command {\n return new Command(\"eval\")\n .description(\"Test your Claude Code config against eval scenarios\")\n .option(\"-s, --suite <suite>\", \"Eval suite to run (e.g., security, conventions, workflow)\")\n .option(\"-p, --path <path>\", \"Project root path\", process.cwd())\n .option(\"--scenarios <path>\", \"Custom scenarios directory\")\n .option(\"--runs <n>\", \"Runs per scenario (default: 3)\", \"3\")\n .option(\"--timeout <ms>\", \"Timeout per run in ms (default: 120000)\", \"120000\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--debug\", \"Keep sandbox directories for inspection\")\n .action(async (opts) => {\n printBanner();\n\n // Verify Claude CLI is available\n const claudeAvailable = await checkClaudeCli();\n if (!claudeAvailable) {\n log.error(\"Claude CLI not found. Install it: https://docs.anthropic.com/en/docs/claude-code\");\n log.info(\"The eval command runs Claude headless against scenarios — it requires the CLI.\");\n process.exit(1);\n }\n\n // Load scenarios\n log.step(\"Loading eval scenarios...\");\n const scenarios = await loadScenarios({\n suite: opts.suite,\n customPath: opts.scenarios,\n });\n\n if (scenarios.length === 0) {\n log.warn(\"No matching scenarios found.\");\n if (opts.suite) {\n log.info(`Check that the suite \"${opts.suite}\" exists in the scenarios directory.`);\n }\n return;\n }\n\n log.success(`Loaded ${scenarios.length} scenario(s)`);\n log.blank();\n\n const runs = parseInt(opts.runs, 10);\n const timeout = parseInt(opts.timeout, 10);\n\n // Run scenarios\n const results: EvalRunResult[] = [];\n\n for (const scenario of scenarios) {\n const spinner = ora({\n text: `Running: ${scenario.name} (${runs} run${runs > 1 ? \"s\" : \"\"})`,\n prefixText: \" \",\n }).start();\n\n try {\n const result = await runScenarioWithRetries(\n { ...scenario, runs },\n { projectRoot: opts.path, timeout, debug: opts.debug },\n );\n results.push(result);\n\n if (result.passed) {\n spinner.succeed(`${scenario.name} ${result.score}/${result.maxScore}`);\n } else {\n spinner.fail(`${scenario.name} ${result.score}/${result.maxScore}`);\n }\n } catch (error: unknown) {\n spinner.fail(`${scenario.name} ERROR`);\n const msg = error instanceof Error ? error.message : String(error);\n log.error(` ${msg}`);\n results.push({\n scenario: scenario.name,\n score: 0,\n maxScore: scenario.checks.reduce((s, c) => s + c.points, 0),\n passed: false,\n checks: scenario.checks.map((c) => ({ label: c.label, passed: false, points: c.points })),\n });\n }\n }\n\n log.blank();\n\n if (opts.json) {\n const overallScore = results.reduce((s, r) => s + r.score, 0);\n const overallMax = results.reduce((s, r) => s + r.maxScore, 0);\n console.log(JSON.stringify({\n results,\n overallScore,\n overallMax,\n passed: overallScore >= overallMax * 0.8,\n timestamp: new Date().toISOString(),\n }, null, 2));\n return;\n }\n\n renderEvalReport(results);\n });\n}\n\nfunction renderEvalReport(results: ReadonlyArray<EvalRunResult>): void {\n for (const result of results) {\n const icon = result.passed ? chalk.green(\"✓\") : chalk.red(\"✗\");\n const status = result.passed ? chalk.green(\"PASS\") : chalk.red(\"FAIL\");\n const score = `${result.score}/${result.maxScore}`;\n\n console.log(` ${icon} ${chalk.bold(result.scenario)} ${score} ${status}`);\n\n const failedChecks = result.checks.filter((c) => !c.passed);\n for (const check of failedChecks) {\n console.log(` ${chalk.dim(\"─\")} ${chalk.dim(check.label)}`);\n }\n }\n\n log.blank();\n\n const totalScore = results.reduce((s, r) => s + r.score, 0);\n const totalMax = results.reduce((s, r) => s + r.maxScore, 0);\n const pct = totalMax > 0 ? Math.round((totalScore / totalMax) * 100) : 0;\n\n printScoreCard(\"Config Eval Score\", pct);\n log.blank();\n\n const passed = results.filter((r) => r.passed).length;\n const failed = results.length - passed;\n\n if (failed === 0) {\n log.success(`All ${passed} scenario(s) passed.`);\n } else {\n log.warn(`${passed} passed, ${failed} failed out of ${results.length} scenario(s).`);\n }\n}\n\nasync function checkClaudeCli(): Promise<boolean> {\n const { execFile } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const exec = promisify(execFile);\n\n try {\n await exec(\"claude\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n","import { readFile, readdir, access } from \"node:fs/promises\";\nimport { join, resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse as parseYaml } from \"yaml\";\nimport { validateScenario } from \"./schema.js\";\nimport type { EvalScenario } from \"../../types/index.js\";\n\n/**\n * Find the scenarios directory. Works both in dev (tsx) and bundled (tsup).\n * - Dev: __dirname is src/commands/eval/, scenarios is at ../../../scenarios/\n * - Bundled: __dirname is dist/, scenarios is at ../scenarios/\n * - npm installed: __dirname is node_modules/claude-launchpad/dist/, scenarios is at ../scenarios/\n */\nasync function findScenariosDir(): Promise<string> {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n\n // Try relative to this file (dev mode: src/commands/eval/ → ../../../scenarios/)\n const devPath = resolve(thisDir, \"../../../scenarios\");\n if (await dirExists(devPath)) return devPath;\n\n // Try relative to dist/ (bundled: dist/ → ../scenarios/)\n const bundledPath = resolve(thisDir, \"../scenarios\");\n if (await dirExists(bundledPath)) return bundledPath;\n\n // Try relative to package root (fallback)\n const rootPath = resolve(thisDir, \"../../scenarios\");\n if (await dirExists(rootPath)) return rootPath;\n\n return devPath; // Fall through — will just find 0 scenarios\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Load eval scenarios from a directory. Supports:\n * - Built-in scenarios (shipped in scenarios/)\n * - Custom scenarios from a user-specified path\n */\nexport async function loadScenarios(options: {\n suite?: string;\n customPath?: string;\n}): Promise<ReadonlyArray<EvalScenario>> {\n const { suite, customPath } = options;\n\n const scenarioDir = customPath\n ? resolve(customPath)\n : await findScenariosDir();\n\n const dirs = suite\n ? [join(scenarioDir, suite)]\n : await getSubdirectories(scenarioDir);\n\n // Also check the root dir for flat YAML files\n const allDirs = [scenarioDir, ...dirs];\n\n const scenarios: EvalScenario[] = [];\n\n for (const dir of allDirs) {\n const files = await listYamlFiles(dir);\n for (const file of files) {\n try {\n const content = await readFile(file, \"utf-8\");\n const raw = parseYaml(content);\n const scenario = validateScenario(raw, file);\n scenarios.push(scenario);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.warn(` Warning: Skipping ${file}: ${msg}`);\n }\n }\n }\n\n return scenarios;\n}\n\nasync function getSubdirectories(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => join(dir, e.name));\n } catch {\n return [];\n }\n}\n\nasync function listYamlFiles(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isFile() && (e.name.endsWith(\".yaml\") || e.name.endsWith(\".yml\")))\n .map((e) => join(dir, e.name));\n } catch {\n return [];\n }\n}\n","import type { EvalScenario, EvalCheck } from \"../../types/index.js\";\n\n/**\n * Validates a raw parsed YAML object against the EvalScenario schema.\n * Returns a validated scenario or throws with a descriptive error.\n */\nexport function validateScenario(raw: unknown, filePath: string): EvalScenario {\n if (!raw || typeof raw !== \"object\") {\n throw new ScenarioError(filePath, \"Scenario must be a YAML object\");\n }\n\n const obj = raw as Record<string, unknown>;\n\n const name = requireString(obj, \"name\", filePath);\n const description = requireString(obj, \"description\", filePath);\n const prompt = requireString(obj, \"prompt\", filePath);\n const setup = validateSetup(obj.setup, filePath);\n const checks = validateChecks(obj.checks, filePath);\n const passingScore = requireNumber(obj, \"passingScore\", filePath);\n const runs = optionalNumber(obj, \"runs\") ?? 3;\n\n return { name, description, setup, prompt, checks, passingScore, runs };\n}\n\n// ─── Field Validators ───\n\nfunction validateSetup(\n raw: unknown,\n filePath: string,\n): EvalScenario[\"setup\"] {\n if (!raw || typeof raw !== \"object\") {\n throw new ScenarioError(filePath, '\"setup\" must be an object with a \"files\" array');\n }\n\n const obj = raw as Record<string, unknown>;\n const files = obj.files;\n\n if (!Array.isArray(files)) {\n throw new ScenarioError(filePath, '\"setup.files\" must be an array');\n }\n\n const validatedFiles = files.map((f, i) => {\n if (!f || typeof f !== \"object\") {\n throw new ScenarioError(filePath, `setup.files[${i}] must be an object`);\n }\n const file = f as Record<string, unknown>;\n if (typeof file.path !== \"string\" || typeof file.content !== \"string\") {\n throw new ScenarioError(filePath, `setup.files[${i}] must have \"path\" and \"content\" strings`);\n }\n return { path: file.path, content: file.content };\n });\n\n const instructions = typeof obj.instructions === \"string\" ? obj.instructions : undefined;\n\n return { files: validatedFiles, instructions };\n}\n\nfunction validateChecks(raw: unknown, filePath: string): ReadonlyArray<EvalCheck> {\n if (!Array.isArray(raw) || raw.length === 0) {\n throw new ScenarioError(filePath, '\"checks\" must be a non-empty array');\n }\n\n return raw.map((c, i) => {\n if (!c || typeof c !== \"object\") {\n throw new ScenarioError(filePath, `checks[${i}] must be an object`);\n }\n const check = c as Record<string, unknown>;\n\n const validTypes = [\"grep\", \"file-exists\", \"file-absent\", \"max-lines\", \"custom\"];\n if (!validTypes.includes(check.type as string)) {\n throw new ScenarioError(filePath, `checks[${i}].type must be one of: ${validTypes.join(\", \")}`);\n }\n\n if (typeof check.target !== \"string\") {\n throw new ScenarioError(filePath, `checks[${i}].target must be a string`);\n }\n\n const validExpect = [\"present\", \"absent\"];\n if (!validExpect.includes(check.expect as string)) {\n throw new ScenarioError(filePath, `checks[${i}].expect must be \"present\" or \"absent\"`);\n }\n\n if (typeof check.points !== \"number\" || check.points < 0) {\n throw new ScenarioError(filePath, `checks[${i}].points must be a non-negative number`);\n }\n\n if (typeof check.label !== \"string\") {\n throw new ScenarioError(filePath, `checks[${i}].label must be a string`);\n }\n\n return {\n type: check.type as EvalCheck[\"type\"],\n pattern: typeof check.pattern === \"string\" ? check.pattern : undefined,\n target: check.target,\n expect: check.expect as EvalCheck[\"expect\"],\n points: check.points,\n label: check.label,\n };\n });\n}\n\n// ─── Helpers ───\n\nfunction requireString(obj: Record<string, unknown>, key: string, filePath: string): string {\n if (typeof obj[key] !== \"string\" || obj[key] === \"\") {\n throw new ScenarioError(filePath, `\"${key}\" must be a non-empty string`);\n }\n return obj[key] as string;\n}\n\nfunction requireNumber(obj: Record<string, unknown>, key: string, filePath: string): number {\n if (typeof obj[key] !== \"number\") {\n throw new ScenarioError(filePath, `\"${key}\" must be a number`);\n }\n return obj[key] as number;\n}\n\nfunction optionalNumber(obj: Record<string, unknown>, key: string): number | undefined {\n if (obj[key] === undefined) return undefined;\n if (typeof obj[key] !== \"number\") return undefined;\n return obj[key] as number;\n}\n\nclass ScenarioError extends Error {\n constructor(filePath: string, message: string) {\n super(`Invalid scenario ${filePath}: ${message}`);\n this.name = \"ScenarioError\";\n }\n}\n","import { mkdir, writeFile, readFile, readdir, rm } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { randomUUID } from \"node:crypto\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { EvalScenario, EvalRunResult, EvalCheck } from \"../../types/index.js\";\n\nconst exec = promisify(execFile);\n\ninterface RunOptions {\n readonly projectRoot: string;\n readonly timeout: number;\n readonly debug?: boolean;\n}\n\n/**\n * Execute a single eval scenario run using the Agent SDK.\n *\n * 1. Create a temp directory with the scenario's seed files\n * 2. Write a minimal CLAUDE.md with the scenario's instructions\n * 3. Run Claude via Agent SDK with explicit tool permissions\n * 4. Check the results against the scenario's checks\n * 5. Clean up\n */\nexport async function runScenario(\n scenario: EvalScenario,\n options: RunOptions,\n): Promise<EvalRunResult> {\n const sandboxDir = join(tmpdir(), `claude-eval-${randomUUID()}`);\n\n try {\n await setupSandbox(sandboxDir, scenario);\n await runClaudeInSandbox(sandboxDir, scenario.prompt, options.timeout);\n return await scoreResults(scenario, sandboxDir);\n } finally {\n if (options.debug) {\n console.log(` DEBUG: Sandbox preserved at ${sandboxDir}`);\n } else {\n await rm(sandboxDir, { recursive: true, force: true }).catch(() => {});\n }\n }\n}\n\n/**\n * Run a scenario multiple times and return the median result.\n */\nexport async function runScenarioWithRetries(\n scenario: EvalScenario,\n options: RunOptions,\n): Promise<EvalRunResult> {\n const results: EvalRunResult[] = [];\n\n for (let i = 0; i < scenario.runs; i++) {\n const result = await runScenario(scenario, options);\n results.push(result);\n }\n\n const sorted = [...results].sort((a, b) => a.score - b.score);\n return sorted[Math.floor(sorted.length / 2)];\n}\n\n// ─── Sandbox Setup ───\n\nasync function setupSandbox(sandboxDir: string, scenario: EvalScenario): Promise<void> {\n await mkdir(sandboxDir, { recursive: true });\n\n for (const file of scenario.setup.files) {\n const filePath = join(sandboxDir, file.path);\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, file.content);\n }\n\n if (scenario.setup.instructions) {\n await writeFile(\n join(sandboxDir, \"CLAUDE.md\"),\n `# Eval Scenario\\n\\n${scenario.setup.instructions}\\n`,\n );\n }\n\n await exec(\"git\", [\"init\", \"-q\"], { cwd: sandboxDir });\n await exec(\"git\", [\"add\", \"-A\"], { cwd: sandboxDir });\n await exec(\"git\", [\n \"-c\", \"user.name=eval\",\n \"-c\", \"user.email=eval@test\",\n \"commit\", \"-q\", \"-m\", \"eval setup\",\n ], { cwd: sandboxDir });\n}\n\n// ─── Claude Execution ───\n\nasync function runClaudeInSandbox(\n cwd: string,\n prompt: string,\n timeout: number,\n): Promise<void> {\n // Try Agent SDK first, fall back to CLI subprocess\n try {\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\");\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n for await (const _message of sdk.query({\n prompt,\n options: {\n cwd,\n allowedTools: [\"Bash\", \"Read\", \"Write\", \"Edit\", \"Glob\", \"Grep\"],\n permissionMode: \"dontAsk\",\n settingSources: [],\n maxTurns: 20,\n abortController: controller,\n },\n })) {\n // Consume the stream — we only care about side effects (file edits)\n }\n } finally {\n clearTimeout(timeoutId);\n }\n } catch {\n // SDK not available or failed — fall back to CLI\n await runClaudeCli(cwd, prompt, timeout);\n }\n}\n\nasync function runClaudeCli(\n cwd: string,\n prompt: string,\n timeout: number,\n): Promise<void> {\n try {\n await exec(\n \"claude\",\n [\n \"-p\", prompt,\n \"--output-format\", \"text\",\n \"--max-turns\", \"20\",\n \"--dangerously-skip-permissions\",\n \"--allowedTools\", \"Bash\", \"Read\", \"Write\", \"Edit\", \"Glob\", \"Grep\",\n ],\n { cwd, timeout, maxBuffer: 10 * 1024 * 1024 },\n );\n } catch (error: unknown) {\n // Claude might exit non-zero but still produce usable output\n if (error && typeof error === \"object\" && \"stdout\" in error) {\n return; // Files may have been modified despite exit code\n }\n throw error;\n }\n}\n\n// ─── Scoring ───\n\nasync function scoreResults(\n scenario: EvalScenario,\n sandboxDir: string,\n): Promise<EvalRunResult> {\n const checkResults = await evaluateChecks(scenario.checks, sandboxDir);\n\n const score = checkResults\n .filter((c) => c.passed)\n .reduce((sum, c) => sum + c.points, 0);\n\n const maxScore = scenario.checks.reduce((sum, c) => sum + c.points, 0);\n\n return {\n scenario: scenario.name,\n score,\n maxScore,\n passed: score >= scenario.passingScore,\n checks: checkResults,\n };\n}\n\nasync function evaluateChecks(\n checks: ReadonlyArray<EvalCheck>,\n sandboxDir: string,\n): Promise<ReadonlyArray<{ label: string; passed: boolean; points: number }>> {\n const results: { label: string; passed: boolean; points: number }[] = [];\n\n for (const check of checks) {\n const passed = await evaluateSingleCheck(check, sandboxDir);\n results.push({ label: check.label, passed, points: check.points });\n }\n\n return results;\n}\n\nasync function evaluateSingleCheck(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n switch (check.type) {\n case \"grep\":\n return checkGrep(check, sandboxDir);\n case \"file-exists\":\n return checkFileExists(check, sandboxDir);\n case \"file-absent\":\n return checkFileAbsent(check, sandboxDir);\n case \"max-lines\":\n return checkMaxLines(check, sandboxDir);\n case \"custom\":\n return false;\n default:\n return false;\n }\n}\n\n// ─── Individual Check Implementations ───\n\nasync function checkGrep(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n if (!check.pattern) return false;\n try {\n const content = await readFile(join(sandboxDir, check.target), \"utf-8\");\n let found: boolean;\n try {\n found = new RegExp(check.pattern).test(content);\n } catch {\n return false; // Invalid regex\n }\n return check.expect === \"present\" ? found : !found;\n } catch {\n return check.expect === \"absent\";\n }\n}\n\nasync function checkFileExists(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n try {\n await readFile(join(sandboxDir, check.target));\n return check.expect === \"present\";\n } catch {\n return check.expect === \"absent\";\n }\n}\n\nasync function checkFileAbsent(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n try {\n await readFile(join(sandboxDir, check.target));\n return check.expect === \"absent\";\n } catch {\n return check.expect === \"present\";\n }\n}\n\nasync function checkMaxLines(check: EvalCheck, sandboxDir: string): Promise<boolean> {\n const maxLines = parseInt(check.pattern ?? \"800\", 10);\n try {\n const files = await listAllFiles(join(sandboxDir, check.target));\n for (const file of files) {\n const content = await readFile(file, \"utf-8\");\n if (content.split(\"\\n\").length > maxLines) {\n return check.expect === \"absent\";\n }\n }\n return check.expect === \"present\";\n } catch {\n return check.expect === \"absent\";\n }\n}\n\n// ─── Utilities ───\n\nasync function listAllFiles(dir: string): Promise<string[]> {\n const results: string[] = [];\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...await listAllFiles(fullPath));\n } else {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory doesn't exist\n }\n return results;\n}\n","import { Command } from \"commander\";\nimport { spawn, execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { printBanner, log } from \"../../lib/output.js\";\n\nconst execAsync = promisify(execFile);\n\nconst ENHANCE_PROMPT = `Read CLAUDE.md and the project's codebase, then update CLAUDE.md to fill in missing or incomplete sections.\n\nCRITICAL BUDGET RULE: CLAUDE.md must stay UNDER 120 lines of actionable content (not counting headings, blank lines, or comments). Claude Code starts ignoring rules past ~150 instructions. If you need more detail, create .claude/rules/ files instead:\n- Create .claude/rules/conventions.md for detailed coding patterns\n- Create .claude/rules/architecture.md for detailed structure docs\n- Keep CLAUDE.md to HIGH-LEVEL summaries only (3-5 bullets per section max)\n\nSections to fill in or preserve (DO NOT remove any existing section):\n1. **## Stack** — if missing or incomplete, detect and add language, framework, package manager\n2. **## Architecture** — 3-5 bullet points describing the codebase shape (not a full directory tree)\n3. **## Conventions** — max 8 key patterns. Move detailed rules to .claude/rules/conventions.md\n4. **## Off-Limits** — max 8 guardrails specific to this project\n5. **## Key Decisions** — only decisions that affect how Claude should work in this codebase\n6. **MCP server suggestions** — look at what external services the project uses (databases, APIs, storage). If you spot Postgres, Redis, Stripe, GitHub API, or similar, suggest relevant MCP servers the user could add. Print these as suggestions at the end, not in CLAUDE.md.\n\nAlso review .claude/settings.json hooks:\n- Read the existing hooks in .claude/settings.json\n- If you see project-specific patterns that deserve hooks (e.g., protected directories, test file patterns, migration files), suggest adding them\n- DO NOT overwrite existing hooks — only add new ones that are specific to this project\n- Print hook suggestions at the end with the exact JSON to add, don't modify settings.json directly\n\nRules:\n- Don't remove existing content — only add or improve\n- Be specific to THIS project, not generic advice\n- Use bullet points, not paragraphs\n- If a section would exceed 8 bullets, split into a .claude/rules/ file and reference it\n- After editing, count the actionable lines. If over 120, move content to rules files until under`;\n\nexport function createEnhanceCommand(): Command {\n return new Command(\"enhance\")\n .description(\"Use Claude to analyze your codebase and complete CLAUDE.md\")\n .option(\"-p, --path <path>\", \"Project root path\", process.cwd())\n .action(async (opts) => {\n printBanner();\n\n const root = opts.path;\n\n // Check CLAUDE.md exists\n const claudeMdPath = join(root, \"CLAUDE.md\");\n try {\n await access(claudeMdPath);\n } catch {\n log.error(\"No CLAUDE.md found. Run `claude-launchpad init` first.\");\n process.exit(1);\n }\n\n // Check Claude CLI is available\n try {\n await execAsync(\"claude\", [\"--version\"]);\n } catch {\n log.error(\"Claude CLI not found. Install it: https://docs.anthropic.com/en/docs/claude-code\");\n process.exit(1);\n }\n\n log.step(\"Launching Claude to enhance your CLAUDE.md...\");\n log.blank();\n\n const child = spawn(\n \"claude\",\n [ENHANCE_PROMPT],\n { cwd: root, stdio: \"inherit\" },\n );\n\n await new Promise<number>((resolve) => {\n child.on(\"close\", (code) => resolve(code ?? 0));\n });\n\n log.blank();\n log.success(\"Run `claude-launchpad doctor` to check your updated score.\");\n });\n}\n"],"mappings":"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","names":["Command","join","readFile","join","readdir","join","readFile","Command","access","join","join","access","readFile","basename","join","join","readFile","basename","access","readFile","writeFile","mkdir","access","join","join","readFile","writeFile","access","mkdir","readdir","join","join","readdir","Command","overallScore","Command","chalk","readFile","readdir","access","join","resolve","dirname","dirname","resolve","access","join","readFile","readdir","mkdir","writeFile","readFile","readdir","join","dirname","Command","chalk","execFile","promisify","exec","Command","execFile","promisify","access","join","promisify","execFile","Command","join","access","resolve","Command","join"]}
|