claude-launchpad 0.7.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +101 -118
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
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,15 +1306,93 @@ async function analyzeMcp(config) {
|
|
|
1314
1306
|
return { name: "MCP Servers", issues, score };
|
|
1315
1307
|
}
|
|
1316
1308
|
|
|
1309
|
+
// src/commands/doctor/analyzers/memory.ts
|
|
1310
|
+
var MEMORY_MCP_TOOLS = [
|
|
1311
|
+
"mcp__agentic-memory__memory_store",
|
|
1312
|
+
"mcp__agentic-memory__memory_search",
|
|
1313
|
+
"mcp__agentic-memory__memory_recent",
|
|
1314
|
+
"mcp__agentic-memory__memory_forget",
|
|
1315
|
+
"mcp__agentic-memory__memory_relate",
|
|
1316
|
+
"mcp__agentic-memory__memory_stats",
|
|
1317
|
+
"mcp__agentic-memory__memory_update"
|
|
1318
|
+
];
|
|
1319
|
+
function hasMemoryIndicators(config) {
|
|
1320
|
+
const hasMcpServer = config.mcpServers.some((s) => s.name === "agentic-memory");
|
|
1321
|
+
const hasHookRef = config.hooks.some(
|
|
1322
|
+
(h) => h.command?.includes("memory context") || h.command?.includes("memory extract")
|
|
1323
|
+
);
|
|
1324
|
+
return hasMcpServer || hasHookRef;
|
|
1325
|
+
}
|
|
1326
|
+
async function analyzeMemory(config) {
|
|
1327
|
+
if (!hasMemoryIndicators(config)) return null;
|
|
1328
|
+
const issues = [];
|
|
1329
|
+
const hasSessionStart = config.hooks.some(
|
|
1330
|
+
(h) => h.event === "SessionStart" && h.command?.includes("memory context")
|
|
1331
|
+
);
|
|
1332
|
+
if (!hasSessionStart) {
|
|
1333
|
+
issues.push({
|
|
1334
|
+
analyzer: "Memory",
|
|
1335
|
+
severity: "high",
|
|
1336
|
+
message: "No SessionStart hook with memory context injection",
|
|
1337
|
+
fix: "Add a SessionStart hook that runs `memory context` to inject relevant memories"
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
const hasStopHook = config.hooks.some(
|
|
1341
|
+
(h) => h.event === "Stop" && h.command?.includes("memory extract")
|
|
1342
|
+
);
|
|
1343
|
+
if (!hasStopHook) {
|
|
1344
|
+
issues.push({
|
|
1345
|
+
analyzer: "Memory",
|
|
1346
|
+
severity: "medium",
|
|
1347
|
+
message: "No Stop hook with memory extract for session learnings",
|
|
1348
|
+
fix: "Add a Stop hook that runs `memory extract` to capture session insights"
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
const autoMemoryDisabled = config.settings?.autoMemoryEnabled === false;
|
|
1352
|
+
if (!autoMemoryDisabled) {
|
|
1353
|
+
issues.push({
|
|
1354
|
+
analyzer: "Memory",
|
|
1355
|
+
severity: "medium",
|
|
1356
|
+
message: "autoMemoryEnabled not disabled \u2014 built-in memory may conflict with agentic-memory",
|
|
1357
|
+
fix: "Set autoMemoryEnabled: false in .claude/settings.json"
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
const hasMemoryGuidance = config.claudeMdContent?.includes("agentic-memory") || config.claudeMdContent?.includes("## Memory");
|
|
1361
|
+
if (!hasMemoryGuidance) {
|
|
1362
|
+
issues.push({
|
|
1363
|
+
analyzer: "Memory",
|
|
1364
|
+
severity: "low",
|
|
1365
|
+
message: "CLAUDE.md missing memory guidance section",
|
|
1366
|
+
fix: "Add a ## Memory section to CLAUDE.md describing when and how to use agentic-memory"
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
const allowList = config.settings?.allowedTools ?? [];
|
|
1370
|
+
const missingTools = MEMORY_MCP_TOOLS.filter((t) => !allowList.includes(t));
|
|
1371
|
+
if (missingTools.length > 0) {
|
|
1372
|
+
issues.push({
|
|
1373
|
+
analyzer: "Memory",
|
|
1374
|
+
severity: "low",
|
|
1375
|
+
message: `${missingTools.length} agentic-memory MCP tool permission(s) missing from allowedTools`,
|
|
1376
|
+
fix: "Add all agentic-memory tool names to allowedTools in .claude/settings.json"
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
const critical = issues.filter((i) => i.severity === "critical").length;
|
|
1380
|
+
const high = issues.filter((i) => i.severity === "high").length;
|
|
1381
|
+
const medium = issues.filter((i) => i.severity === "medium").length;
|
|
1382
|
+
const low = issues.filter((i) => i.severity === "low").length;
|
|
1383
|
+
const score = Math.max(0, 100 - (critical * 40 + high * 20 + medium * 10 + low * 5));
|
|
1384
|
+
return { name: "Memory", issues, score };
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1317
1387
|
// src/commands/doctor/analyzers/quality.ts
|
|
1318
|
-
var
|
|
1388
|
+
var BASE_SECTIONS = [
|
|
1319
1389
|
{ pattern: /^##\s+(Tech )?Stack/m, name: "Stack", why: "Claude performs worse without knowing the tech stack" },
|
|
1320
1390
|
{ pattern: /^##\s+Commands/m, name: "Commands", why: "Claude guesses wrong without explicit dev/build/test commands" },
|
|
1321
1391
|
{ pattern: /^##\s+Session Start/m, name: "Session Start", why: "Without this, Claude won't read TASKS.md or maintain continuity" },
|
|
1322
1392
|
{ 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" }
|
|
1393
|
+
{ pattern: /^##\s+(Architecture|Project Structure)/m, name: "Architecture/Structure", why: "Claude makes better decisions when it understands the codebase shape" }
|
|
1325
1394
|
];
|
|
1395
|
+
var MEMORY_SECTION = { pattern: /^##\s+Memory/m, name: "Memory & Learnings", why: "Without memory instructions, Claude forgets learnings and repeats mistakes across sessions" };
|
|
1326
1396
|
var VAGUE_PATTERNS = [
|
|
1327
1397
|
{ pattern: /write (good|clean|quality|nice) code/i, label: "write good code" },
|
|
1328
1398
|
{ pattern: /be (careful|thorough|diligent)/i, label: "be careful" },
|
|
@@ -1347,8 +1417,9 @@ async function analyzeQuality(config) {
|
|
|
1347
1417
|
});
|
|
1348
1418
|
return { name: "CLAUDE.md Quality", issues, score: 0 };
|
|
1349
1419
|
}
|
|
1420
|
+
const sections = hasMemoryIndicators(config) ? [...BASE_SECTIONS, MEMORY_SECTION] : [...BASE_SECTIONS];
|
|
1350
1421
|
let sectionsFound = 0;
|
|
1351
|
-
for (const section of
|
|
1422
|
+
for (const section of sections) {
|
|
1352
1423
|
if (section.pattern.test(content)) {
|
|
1353
1424
|
sectionsFound++;
|
|
1354
1425
|
} else {
|
|
@@ -1397,93 +1468,6 @@ async function analyzeQuality(config) {
|
|
|
1397
1468
|
return { name: "CLAUDE.md Quality", issues, score };
|
|
1398
1469
|
}
|
|
1399
1470
|
|
|
1400
|
-
// src/commands/doctor/analyzers/memory.ts
|
|
1401
|
-
var MEMORY_MCP_TOOLS = [
|
|
1402
|
-
"mcp__agentic-memory__memory_store",
|
|
1403
|
-
"mcp__agentic-memory__memory_search",
|
|
1404
|
-
"mcp__agentic-memory__memory_recent",
|
|
1405
|
-
"mcp__agentic-memory__memory_forget",
|
|
1406
|
-
"mcp__agentic-memory__memory_relate",
|
|
1407
|
-
"mcp__agentic-memory__memory_stats",
|
|
1408
|
-
"mcp__agentic-memory__memory_update"
|
|
1409
|
-
];
|
|
1410
|
-
function hasMemoryIndicators(config) {
|
|
1411
|
-
const hasMcpServer = config.mcpServers.some((s) => s.name === "agentic-memory");
|
|
1412
|
-
const hasHookRef = config.hooks.some(
|
|
1413
|
-
(h) => h.command?.includes("memory context") || h.command?.includes("memory extract")
|
|
1414
|
-
);
|
|
1415
|
-
return hasMcpServer || hasHookRef;
|
|
1416
|
-
}
|
|
1417
|
-
async function analyzeMemory(config) {
|
|
1418
|
-
if (!hasMemoryIndicators(config)) return null;
|
|
1419
|
-
const issues = [];
|
|
1420
|
-
const hasMcpServer = config.mcpServers.some((s) => s.name === "agentic-memory");
|
|
1421
|
-
if (!hasMcpServer) {
|
|
1422
|
-
issues.push({
|
|
1423
|
-
analyzer: "Memory",
|
|
1424
|
-
severity: "high",
|
|
1425
|
-
message: "agentic-memory MCP server not found in mcpServers",
|
|
1426
|
-
fix: "Add agentic-memory to mcpServers in .claude/settings.json"
|
|
1427
|
-
});
|
|
1428
|
-
}
|
|
1429
|
-
const hasSessionStart = config.hooks.some(
|
|
1430
|
-
(h) => h.event === "SessionStart" && h.command?.includes("memory context")
|
|
1431
|
-
);
|
|
1432
|
-
if (!hasSessionStart) {
|
|
1433
|
-
issues.push({
|
|
1434
|
-
analyzer: "Memory",
|
|
1435
|
-
severity: "high",
|
|
1436
|
-
message: "No SessionStart hook with memory context injection",
|
|
1437
|
-
fix: "Add a SessionStart hook that runs `memory context` to inject relevant memories"
|
|
1438
|
-
});
|
|
1439
|
-
}
|
|
1440
|
-
const hasStopHook = config.hooks.some(
|
|
1441
|
-
(h) => h.event === "Stop" && h.command?.includes("memory extract")
|
|
1442
|
-
);
|
|
1443
|
-
if (!hasStopHook) {
|
|
1444
|
-
issues.push({
|
|
1445
|
-
analyzer: "Memory",
|
|
1446
|
-
severity: "medium",
|
|
1447
|
-
message: "No Stop hook with memory extract for session learnings",
|
|
1448
|
-
fix: "Add a Stop hook that runs `memory extract` to capture session insights"
|
|
1449
|
-
});
|
|
1450
|
-
}
|
|
1451
|
-
const autoMemoryDisabled = config.settings?.autoMemoryEnabled === false;
|
|
1452
|
-
if (!autoMemoryDisabled) {
|
|
1453
|
-
issues.push({
|
|
1454
|
-
analyzer: "Memory",
|
|
1455
|
-
severity: "medium",
|
|
1456
|
-
message: "autoMemoryEnabled not disabled \u2014 built-in memory may conflict with agentic-memory",
|
|
1457
|
-
fix: "Set autoMemoryEnabled: false in .claude/settings.json"
|
|
1458
|
-
});
|
|
1459
|
-
}
|
|
1460
|
-
const hasMemoryGuidance = config.claudeMdContent?.includes("agentic-memory") || config.claudeMdContent?.includes("## Memory");
|
|
1461
|
-
if (!hasMemoryGuidance) {
|
|
1462
|
-
issues.push({
|
|
1463
|
-
analyzer: "Memory",
|
|
1464
|
-
severity: "low",
|
|
1465
|
-
message: "CLAUDE.md missing memory guidance section",
|
|
1466
|
-
fix: "Add a ## Memory section to CLAUDE.md describing when and how to use agentic-memory"
|
|
1467
|
-
});
|
|
1468
|
-
}
|
|
1469
|
-
const allowList = config.settings?.allowedTools ?? [];
|
|
1470
|
-
const missingTools = MEMORY_MCP_TOOLS.filter((t) => !allowList.includes(t));
|
|
1471
|
-
if (missingTools.length > 0) {
|
|
1472
|
-
issues.push({
|
|
1473
|
-
analyzer: "Memory",
|
|
1474
|
-
severity: "low",
|
|
1475
|
-
message: `${missingTools.length} agentic-memory MCP tool permission(s) missing from allowedTools`,
|
|
1476
|
-
fix: "Add all agentic-memory tool names to allowedTools in .claude/settings.json"
|
|
1477
|
-
});
|
|
1478
|
-
}
|
|
1479
|
-
const critical = issues.filter((i) => i.severity === "critical").length;
|
|
1480
|
-
const high = issues.filter((i) => i.severity === "high").length;
|
|
1481
|
-
const medium = issues.filter((i) => i.severity === "medium").length;
|
|
1482
|
-
const low = issues.filter((i) => i.severity === "low").length;
|
|
1483
|
-
const score = Math.max(0, 100 - (critical * 40 + high * 20 + medium * 10 + low * 5));
|
|
1484
|
-
return { name: "Memory", issues, score };
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
1471
|
// src/commands/doctor/fixer.ts
|
|
1488
1472
|
import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2, access as access4 } from "fs/promises";
|
|
1489
1473
|
import { join as join5 } from "path";
|
|
@@ -1524,7 +1508,6 @@ var FIX_TABLE = [
|
|
|
1524
1508
|
{ 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
1509
|
{ analyzer: "Rules", match: "No .claudeignore", fix: (root, detected) => createClaudeignore(root, detected) },
|
|
1526
1510
|
{ 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
1511
|
{ analyzer: "Hooks", match: "PostCompact", fix: (root) => addPostCompactHook(root) },
|
|
1529
1512
|
{ analyzer: "Permissions", match: "force-push", fix: (root) => addForcePushProtection(root) },
|
|
1530
1513
|
{ analyzer: "Permissions", match: "Credential files not blocked", fix: (root) => addCredentialDenyRules(root) },
|
|
@@ -1947,23 +1930,23 @@ function createDoctorCommand() {
|
|
|
1947
1930
|
if (fixed > 0) {
|
|
1948
1931
|
log.success(`Applied ${fixed} fix(es). Re-scanning...`);
|
|
1949
1932
|
log.blank();
|
|
1950
|
-
const updatedConfig = await parseClaudeConfig(opts.path);
|
|
1951
|
-
const updatedResults = await Promise.all([
|
|
1952
|
-
analyzeBudget(updatedConfig),
|
|
1953
|
-
analyzeQuality(updatedConfig),
|
|
1954
|
-
analyzeSettings(updatedConfig),
|
|
1955
|
-
analyzeHooks(updatedConfig),
|
|
1956
|
-
analyzeRules(updatedConfig),
|
|
1957
|
-
analyzePermissions(updatedConfig),
|
|
1958
|
-
analyzeMcp(updatedConfig)
|
|
1959
|
-
]);
|
|
1960
|
-
const updatedMemoryResult = await analyzeMemory(updatedConfig);
|
|
1961
|
-
if (updatedMemoryResult) {
|
|
1962
|
-
updatedResults.push(updatedMemoryResult);
|
|
1963
|
-
}
|
|
1964
|
-
renderDoctorReport(updatedResults, { afterFix: true });
|
|
1965
|
-
log.info(`Then use ${chalk.bold("/lp-enhance")} inside Claude Code to have Claude restructure and complete your CLAUDE.md.`);
|
|
1966
1933
|
}
|
|
1934
|
+
const updatedConfig = await parseClaudeConfig(opts.path);
|
|
1935
|
+
const updatedResults = await Promise.all([
|
|
1936
|
+
analyzeBudget(updatedConfig),
|
|
1937
|
+
analyzeQuality(updatedConfig),
|
|
1938
|
+
analyzeSettings(updatedConfig),
|
|
1939
|
+
analyzeHooks(updatedConfig),
|
|
1940
|
+
analyzeRules(updatedConfig),
|
|
1941
|
+
analyzePermissions(updatedConfig),
|
|
1942
|
+
analyzeMcp(updatedConfig)
|
|
1943
|
+
]);
|
|
1944
|
+
const updatedMemoryResult = await analyzeMemory(updatedConfig);
|
|
1945
|
+
if (updatedMemoryResult) {
|
|
1946
|
+
updatedResults.push(updatedMemoryResult);
|
|
1947
|
+
}
|
|
1948
|
+
renderDoctorReport(updatedResults, { afterFix: true });
|
|
1949
|
+
log.info(`Then use ${chalk.bold("/lp-enhance")} inside Claude Code to have Claude restructure and complete your CLAUDE.md.`);
|
|
1967
1950
|
}
|
|
1968
1951
|
}
|
|
1969
1952
|
if (opts.minScore) {
|
|
@@ -2660,7 +2643,7 @@ function createMemoryCommand() {
|
|
|
2660
2643
|
}
|
|
2661
2644
|
|
|
2662
2645
|
// src/cli.ts
|
|
2663
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2646
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.8.1", "-v, --version").action(async () => {
|
|
2664
2647
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2665
2648
|
if (hasConfig) {
|
|
2666
2649
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|