claude-launchpad 0.7.8 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-CSLWJEGD.js +0 -0
- package/dist/chunk-EUAVDA7W.js +0 -0
- package/dist/chunk-FL3JGYDM.js +0 -0
- package/dist/chunk-NAW47BYA.js +0 -0
- package/dist/chunk-NNVJCKEP.js +0 -0
- package/dist/chunk-OYSKBXBB.js +0 -0
- package/dist/chunk-TALTTAMW.js +0 -0
- package/dist/chunk-UN2XVQ5K.js +0 -0
- package/dist/cli.js +87 -95
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +0 -0
- package/dist/context-QU2QFVS3.js +0 -0
- package/dist/extract-ADZYHMUP.js +0 -0
- package/dist/{install-56GBDZHM.js → install-3IW2PDOS.js} +2 -2
- package/dist/install-3IW2PDOS.js.map +1 -0
- package/dist/require-deps-6D6IBICL.js +0 -0
- package/dist/stats-XLVVS3JA.js +0 -0
- package/dist/tui-BXRHLYAS.js +0 -0
- package/package.json +14 -21
- package/dist/install-56GBDZHM.js.map +0 -1
package/dist/chunk-CSLWJEGD.js
CHANGED
|
File without changes
|
package/dist/chunk-EUAVDA7W.js
CHANGED
|
File without changes
|
package/dist/chunk-FL3JGYDM.js
CHANGED
|
File without changes
|
package/dist/chunk-NAW47BYA.js
CHANGED
|
File without changes
|
package/dist/chunk-NNVJCKEP.js
CHANGED
|
File without changes
|
package/dist/chunk-OYSKBXBB.js
CHANGED
|
File without changes
|
package/dist/chunk-TALTTAMW.js
CHANGED
|
File without changes
|
package/dist/chunk-UN2XVQ5K.js
CHANGED
|
File without changes
|
package/dist/cli.js
CHANGED
|
@@ -270,14 +270,6 @@ When all tasks in the current sprint are complete, do a quick quality check befo
|
|
|
270
270
|
- Never hardcode secrets \u2014 use environment variables
|
|
271
271
|
- Never write to \`.env\` files
|
|
272
272
|
- Never expose internal error details in API responses`);
|
|
273
|
-
sections.push("", `## Memory & Learnings
|
|
274
|
-
Use the built-in memory system to persist knowledge across sessions:
|
|
275
|
-
- **Save immediately** when you discover: a non-obvious fix, a gotcha, an external resource, a decision with context that would be lost, or a known issue to fix later
|
|
276
|
-
- **Categories**: \`decision\` (why X over Y), \`gotcha\` (non-obvious pitfall), \`deferred\` (known issue, not urgent), \`reference\` (where to find things)
|
|
277
|
-
- **Where**: project memory for this repo, global memory for cross-project learnings
|
|
278
|
-
- **Format**: one fact per memory, include date and why \u2014 not just what
|
|
279
|
-
- **Prune**: check if a memory on this topic exists before saving \u2014 update, don't duplicate
|
|
280
|
-
- Before starting work, check memory for relevant context from previous sessions`);
|
|
281
273
|
sections.push("", `## Key Decisions
|
|
282
274
|
<!-- Record architectural decisions as you make them -->`);
|
|
283
275
|
return sections.join("\n") + "\n";
|
|
@@ -561,7 +553,7 @@ CLAUDE.md must stay UNDER 120 lines of actionable content (not counting headings
|
|
|
561
553
|
2. **## Architecture** - 3-5 bullet points describing the codebase shape (not a full directory tree)
|
|
562
554
|
3. **## Conventions** - max 8 key patterns. Move detailed rules to .claude/rules/conventions.md
|
|
563
555
|
4. **## Off-Limits** - max 8 guardrails specific to this project
|
|
564
|
-
5. **## Memory & Learnings** -
|
|
556
|
+
5. **## Memory & Learnings** - ONLY if the project already has a ## Memory section or agentic-memory is configured in .claude/settings.json. If present, keep to max 6 bullets. If the project does NOT use memory, do NOT add this section
|
|
565
557
|
6. **## Key Decisions** - only decisions that affect how Claude should work in this codebase
|
|
566
558
|
7. **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. Print as suggestions at the end, not in CLAUDE.md.
|
|
567
559
|
|
|
@@ -1314,89 +1306,6 @@ async function analyzeMcp(config) {
|
|
|
1314
1306
|
return { name: "MCP Servers", issues, score };
|
|
1315
1307
|
}
|
|
1316
1308
|
|
|
1317
|
-
// src/commands/doctor/analyzers/quality.ts
|
|
1318
|
-
var ESSENTIAL_SECTIONS = [
|
|
1319
|
-
{ pattern: /^##\s+(Tech )?Stack/m, name: "Stack", why: "Claude performs worse without knowing the tech stack" },
|
|
1320
|
-
{ pattern: /^##\s+Commands/m, name: "Commands", why: "Claude guesses wrong without explicit dev/build/test commands" },
|
|
1321
|
-
{ pattern: /^##\s+Session Start/m, name: "Session Start", why: "Without this, Claude won't read TASKS.md or maintain continuity" },
|
|
1322
|
-
{ pattern: /^##\s+Off.?Limits/m, name: "Off-Limits", why: "Without guardrails, Claude has no boundaries beyond defaults" },
|
|
1323
|
-
{ pattern: /^##\s+(Architecture|Project Structure)/m, name: "Architecture/Structure", why: "Claude makes better decisions when it understands the codebase shape" },
|
|
1324
|
-
{ pattern: /^##\s+Memory/m, name: "Memory & Learnings", why: "Without memory instructions, Claude forgets learnings and repeats mistakes across sessions" }
|
|
1325
|
-
];
|
|
1326
|
-
var VAGUE_PATTERNS = [
|
|
1327
|
-
{ pattern: /write (good|clean|quality|nice) code/i, label: "write good code" },
|
|
1328
|
-
{ pattern: /be (careful|thorough|diligent)/i, label: "be careful" },
|
|
1329
|
-
{ pattern: /follow best practices/i, label: "follow best practices" },
|
|
1330
|
-
{ pattern: /make sure (everything|it) works/i, label: "make sure it works" }
|
|
1331
|
-
];
|
|
1332
|
-
var SECRET_PATTERNS = [
|
|
1333
|
-
{ pattern: /sk-[a-zA-Z0-9]{20,}/, label: "OpenAI API key" },
|
|
1334
|
-
{ pattern: /ghp_[a-zA-Z0-9]{36}/, label: "GitHub personal token" },
|
|
1335
|
-
{ pattern: /AKIA[0-9A-Z]{16}/, label: "AWS access key" },
|
|
1336
|
-
{ pattern: /xoxb-[0-9]+-[a-zA-Z0-9]+/, label: "Slack bot token" }
|
|
1337
|
-
];
|
|
1338
|
-
async function analyzeQuality(config) {
|
|
1339
|
-
const issues = [];
|
|
1340
|
-
const content = config.claudeMdContent;
|
|
1341
|
-
if (content === null) {
|
|
1342
|
-
issues.push({
|
|
1343
|
-
analyzer: "Quality",
|
|
1344
|
-
severity: "high",
|
|
1345
|
-
message: "No CLAUDE.md found",
|
|
1346
|
-
fix: "Run `claude-launchpad init` to generate one"
|
|
1347
|
-
});
|
|
1348
|
-
return { name: "CLAUDE.md Quality", issues, score: 0 };
|
|
1349
|
-
}
|
|
1350
|
-
let sectionsFound = 0;
|
|
1351
|
-
for (const section of ESSENTIAL_SECTIONS) {
|
|
1352
|
-
if (section.pattern.test(content)) {
|
|
1353
|
-
sectionsFound++;
|
|
1354
|
-
} else {
|
|
1355
|
-
issues.push({
|
|
1356
|
-
analyzer: "Quality",
|
|
1357
|
-
severity: "medium",
|
|
1358
|
-
message: `Missing "## ${section.name}" section \u2014 ${section.why}`,
|
|
1359
|
-
fix: `Add a ## ${section.name} section to CLAUDE.md`
|
|
1360
|
-
});
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
for (const vague of VAGUE_PATTERNS) {
|
|
1364
|
-
if (vague.pattern.test(content)) {
|
|
1365
|
-
issues.push({
|
|
1366
|
-
analyzer: "Quality",
|
|
1367
|
-
severity: "low",
|
|
1368
|
-
message: `Vague instruction detected: "${vague.label}" \u2014 zero signal, wastes budget`,
|
|
1369
|
-
fix: "Replace with specific, actionable instructions"
|
|
1370
|
-
});
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
for (const secret of SECRET_PATTERNS) {
|
|
1374
|
-
if (secret.pattern.test(content)) {
|
|
1375
|
-
issues.push({
|
|
1376
|
-
analyzer: "Quality",
|
|
1377
|
-
severity: "critical",
|
|
1378
|
-
message: `Possible ${secret.label} found in CLAUDE.md \u2014 secrets must never be in config files`,
|
|
1379
|
-
fix: "Remove the secret immediately and rotate it"
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
const todoCount = (content.match(/<!--\s*TODO/gi) ?? []).length;
|
|
1384
|
-
if (todoCount > 3) {
|
|
1385
|
-
issues.push({
|
|
1386
|
-
analyzer: "Quality",
|
|
1387
|
-
severity: "medium",
|
|
1388
|
-
message: `${todoCount} TODO placeholders \u2014 CLAUDE.md is mostly unfinished`,
|
|
1389
|
-
fix: "Fill in the TODO sections or remove them"
|
|
1390
|
-
});
|
|
1391
|
-
}
|
|
1392
|
-
const criticals = issues.filter((i) => i.severity === "critical").length;
|
|
1393
|
-
const highs = issues.filter((i) => i.severity === "high").length;
|
|
1394
|
-
const mediums = issues.filter((i) => i.severity === "medium").length;
|
|
1395
|
-
const lows = issues.filter((i) => i.severity === "low").length;
|
|
1396
|
-
const score = Math.max(0, 100 - criticals * 40 - highs * 30 - mediums * 15 - lows * 5);
|
|
1397
|
-
return { name: "CLAUDE.md Quality", issues, score };
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
1309
|
// src/commands/doctor/analyzers/memory.ts
|
|
1401
1310
|
var MEMORY_MCP_TOOLS = [
|
|
1402
1311
|
"mcp__agentic-memory__memory_store",
|
|
@@ -1484,6 +1393,90 @@ async function analyzeMemory(config) {
|
|
|
1484
1393
|
return { name: "Memory", issues, score };
|
|
1485
1394
|
}
|
|
1486
1395
|
|
|
1396
|
+
// src/commands/doctor/analyzers/quality.ts
|
|
1397
|
+
var BASE_SECTIONS = [
|
|
1398
|
+
{ pattern: /^##\s+(Tech )?Stack/m, name: "Stack", why: "Claude performs worse without knowing the tech stack" },
|
|
1399
|
+
{ pattern: /^##\s+Commands/m, name: "Commands", why: "Claude guesses wrong without explicit dev/build/test commands" },
|
|
1400
|
+
{ pattern: /^##\s+Session Start/m, name: "Session Start", why: "Without this, Claude won't read TASKS.md or maintain continuity" },
|
|
1401
|
+
{ pattern: /^##\s+Off.?Limits/m, name: "Off-Limits", why: "Without guardrails, Claude has no boundaries beyond defaults" },
|
|
1402
|
+
{ pattern: /^##\s+(Architecture|Project Structure)/m, name: "Architecture/Structure", why: "Claude makes better decisions when it understands the codebase shape" }
|
|
1403
|
+
];
|
|
1404
|
+
var MEMORY_SECTION = { pattern: /^##\s+Memory/m, name: "Memory & Learnings", why: "Without memory instructions, Claude forgets learnings and repeats mistakes across sessions" };
|
|
1405
|
+
var VAGUE_PATTERNS = [
|
|
1406
|
+
{ pattern: /write (good|clean|quality|nice) code/i, label: "write good code" },
|
|
1407
|
+
{ pattern: /be (careful|thorough|diligent)/i, label: "be careful" },
|
|
1408
|
+
{ pattern: /follow best practices/i, label: "follow best practices" },
|
|
1409
|
+
{ pattern: /make sure (everything|it) works/i, label: "make sure it works" }
|
|
1410
|
+
];
|
|
1411
|
+
var SECRET_PATTERNS = [
|
|
1412
|
+
{ pattern: /sk-[a-zA-Z0-9]{20,}/, label: "OpenAI API key" },
|
|
1413
|
+
{ pattern: /ghp_[a-zA-Z0-9]{36}/, label: "GitHub personal token" },
|
|
1414
|
+
{ pattern: /AKIA[0-9A-Z]{16}/, label: "AWS access key" },
|
|
1415
|
+
{ pattern: /xoxb-[0-9]+-[a-zA-Z0-9]+/, label: "Slack bot token" }
|
|
1416
|
+
];
|
|
1417
|
+
async function analyzeQuality(config) {
|
|
1418
|
+
const issues = [];
|
|
1419
|
+
const content = config.claudeMdContent;
|
|
1420
|
+
if (content === null) {
|
|
1421
|
+
issues.push({
|
|
1422
|
+
analyzer: "Quality",
|
|
1423
|
+
severity: "high",
|
|
1424
|
+
message: "No CLAUDE.md found",
|
|
1425
|
+
fix: "Run `claude-launchpad init` to generate one"
|
|
1426
|
+
});
|
|
1427
|
+
return { name: "CLAUDE.md Quality", issues, score: 0 };
|
|
1428
|
+
}
|
|
1429
|
+
const sections = hasMemoryIndicators(config) ? [...BASE_SECTIONS, MEMORY_SECTION] : [...BASE_SECTIONS];
|
|
1430
|
+
let sectionsFound = 0;
|
|
1431
|
+
for (const section of sections) {
|
|
1432
|
+
if (section.pattern.test(content)) {
|
|
1433
|
+
sectionsFound++;
|
|
1434
|
+
} else {
|
|
1435
|
+
issues.push({
|
|
1436
|
+
analyzer: "Quality",
|
|
1437
|
+
severity: "medium",
|
|
1438
|
+
message: `Missing "## ${section.name}" section \u2014 ${section.why}`,
|
|
1439
|
+
fix: `Add a ## ${section.name} section to CLAUDE.md`
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
for (const vague of VAGUE_PATTERNS) {
|
|
1444
|
+
if (vague.pattern.test(content)) {
|
|
1445
|
+
issues.push({
|
|
1446
|
+
analyzer: "Quality",
|
|
1447
|
+
severity: "low",
|
|
1448
|
+
message: `Vague instruction detected: "${vague.label}" \u2014 zero signal, wastes budget`,
|
|
1449
|
+
fix: "Replace with specific, actionable instructions"
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
for (const secret of SECRET_PATTERNS) {
|
|
1454
|
+
if (secret.pattern.test(content)) {
|
|
1455
|
+
issues.push({
|
|
1456
|
+
analyzer: "Quality",
|
|
1457
|
+
severity: "critical",
|
|
1458
|
+
message: `Possible ${secret.label} found in CLAUDE.md \u2014 secrets must never be in config files`,
|
|
1459
|
+
fix: "Remove the secret immediately and rotate it"
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
const todoCount = (content.match(/<!--\s*TODO/gi) ?? []).length;
|
|
1464
|
+
if (todoCount > 3) {
|
|
1465
|
+
issues.push({
|
|
1466
|
+
analyzer: "Quality",
|
|
1467
|
+
severity: "medium",
|
|
1468
|
+
message: `${todoCount} TODO placeholders \u2014 CLAUDE.md is mostly unfinished`,
|
|
1469
|
+
fix: "Fill in the TODO sections or remove them"
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
const criticals = issues.filter((i) => i.severity === "critical").length;
|
|
1473
|
+
const highs = issues.filter((i) => i.severity === "high").length;
|
|
1474
|
+
const mediums = issues.filter((i) => i.severity === "medium").length;
|
|
1475
|
+
const lows = issues.filter((i) => i.severity === "low").length;
|
|
1476
|
+
const score = Math.max(0, 100 - criticals * 40 - highs * 30 - mediums * 15 - lows * 5);
|
|
1477
|
+
return { name: "CLAUDE.md Quality", issues, score };
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1487
1480
|
// src/commands/doctor/fixer.ts
|
|
1488
1481
|
import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2, access as access4 } from "fs/promises";
|
|
1489
1482
|
import { join as join5 } from "path";
|
|
@@ -1524,7 +1517,6 @@ var FIX_TABLE = [
|
|
|
1524
1517
|
{ analyzer: "Quality", match: "Session Start", fix: (root) => addClaudeMdSection(root, "## Session Start", "- ALWAYS read @TASKS.md first - it tracks progress across sessions\n- Update TASKS.md as you complete work") },
|
|
1525
1518
|
{ analyzer: "Rules", match: "No .claudeignore", fix: (root, detected) => createClaudeignore(root, detected) },
|
|
1526
1519
|
{ analyzer: "Rules", match: "No .claude/rules/", fix: (root) => createStarterRules(root) },
|
|
1527
|
-
{ analyzer: "Quality", match: "Memory", fix: (root) => addClaudeMdSection(root, "## Memory & Learnings", "Use the built-in memory system to persist knowledge across sessions:\n- **Save immediately** when you discover: a non-obvious fix, a gotcha, an external resource, a decision with context that would be lost, or a known issue to fix later\n- **Categories**: `decision` (why X over Y), `gotcha` (non-obvious pitfall), `deferred` (known issue, not urgent), `reference` (where to find things)\n- **Where**: project memory for this repo, global memory for cross-project learnings\n- **Format**: one fact per memory, include date and why \u2014 not just what\n- **Prune**: check if a memory on this topic exists before saving \u2014 update, don't duplicate\n- Before starting work, check memory for relevant context from previous sessions") },
|
|
1528
1520
|
{ analyzer: "Hooks", match: "PostCompact", fix: (root) => addPostCompactHook(root) },
|
|
1529
1521
|
{ analyzer: "Permissions", match: "force-push", fix: (root) => addForcePushProtection(root) },
|
|
1530
1522
|
{ analyzer: "Permissions", match: "Credential files not blocked", fix: (root) => addCredentialDenyRules(root) },
|
|
@@ -2626,7 +2618,7 @@ function createMemoryCommand() {
|
|
|
2626
2618
|
log.info("Skipped.");
|
|
2627
2619
|
return;
|
|
2628
2620
|
}
|
|
2629
|
-
const { runInstall } = await import("./install-
|
|
2621
|
+
const { runInstall } = await import("./install-3IW2PDOS.js");
|
|
2630
2622
|
await runInstall({});
|
|
2631
2623
|
} else {
|
|
2632
2624
|
const { requireMemoryDeps } = await import("./require-deps-6D6IBICL.js");
|
|
@@ -2660,7 +2652,7 @@ function createMemoryCommand() {
|
|
|
2660
2652
|
}
|
|
2661
2653
|
|
|
2662
2654
|
// src/cli.ts
|
|
2663
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2655
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.8.0", "-v, --version").action(async () => {
|
|
2664
2656
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2665
2657
|
if (hasConfig) {
|
|
2666
2658
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|