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.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
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** - max 6 bullets. If missing, add instructions for using the built-in memory system: what to save (gotchas, decisions, deferred issues, references), where (project vs global memory), and the rule to check existing memories before creating duplicates
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-56GBDZHM.js");
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.7.8", "-v, --version").action(async () => {
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" });