claude-launchpad 0.13.1 → 0.14.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/README.md +1 -1
- package/dist/cli.js +146 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +4 -4
- package/dist/{install-H6GW4P6K.js → install-4GQ57KCQ.js} +2 -20
- package/dist/install-4GQ57KCQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/extract-HMAN7RW4.js +0 -218
- package/dist/extract-HMAN7RW4.js.map +0 -1
- package/dist/install-H6GW4P6K.js.map +0 -1
package/README.md
CHANGED
|
@@ -201,7 +201,7 @@ claude-launchpad memory
|
|
|
201
201
|
|
|
202
202
|
If memory is not installed, it runs interactive setup. If installed, it shows stats. Requires native deps first: `npm install better-sqlite3 sqlite-vec`.
|
|
203
203
|
|
|
204
|
-
Every session, Claude loads what it needs to know and
|
|
204
|
+
Every session, Claude loads what it needs to know and stores new knowledge as it works. Stale facts fade on their own. Knowledge Claude actually uses gets reinforced. Each project has its own isolated memory, and you can sync it across machines via private GitHub Gist.
|
|
205
205
|
|
|
206
206
|
Browse everything with `--dashboard` -- a terminal UI with vim navigation, filtering, and search.
|
|
207
207
|
|
package/dist/cli.js
CHANGED
|
@@ -534,8 +534,10 @@ DerivedData/
|
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
// src/commands/init/generators/skill-enhance.ts
|
|
537
|
+
var ENHANCE_SKILL_VERSION = 4;
|
|
537
538
|
function generateEnhanceSkill() {
|
|
538
539
|
return [
|
|
540
|
+
`<!-- lp-enhance-version: ${ENHANCE_SKILL_VERSION} -->`,
|
|
539
541
|
"---",
|
|
540
542
|
"name: lp-enhance",
|
|
541
543
|
"description: |",
|
|
@@ -555,9 +557,11 @@ function generateEnhanceSkill() {
|
|
|
555
557
|
"1. Read CLAUDE.md (if it exists)",
|
|
556
558
|
"2. Read .claude/settings.json (hooks, permissions, MCP)",
|
|
557
559
|
"3. Read .claude/rules/*.md (existing rules)",
|
|
558
|
-
"4.
|
|
559
|
-
"5.
|
|
560
|
-
"6.
|
|
560
|
+
"4. Read .claudeignore (if it exists)",
|
|
561
|
+
"5. Scan src/ directory structure (top-level dirs, key files)",
|
|
562
|
+
"6. Read package.json / go.mod / pyproject.toml for stack detection",
|
|
563
|
+
"7. Check for monorepo indicators (workspaces, nx.json, lerna.json)",
|
|
564
|
+
"8. Check scenarios/ directory for existing eval scenarios",
|
|
561
565
|
"",
|
|
562
566
|
"**Done when:** you have a mental model of the stack, architecture, and existing config.",
|
|
563
567
|
"",
|
|
@@ -584,7 +588,9 @@ function generateEnhanceSkill() {
|
|
|
584
588
|
"",
|
|
585
589
|
"1. Create or update .claude/rules/ files for overflow content",
|
|
586
590
|
"2. Generate path-scoped rules if the project has distinct areas (see below)",
|
|
587
|
-
"3.
|
|
591
|
+
"3. Review .claudeignore and print suggestions (see below)",
|
|
592
|
+
"4. Generate 2-3 custom eval scenarios in scenarios/custom/ (see below)",
|
|
593
|
+
"5. Verify line count is under 200",
|
|
588
594
|
"",
|
|
589
595
|
"**Rules:**",
|
|
590
596
|
"- Don't remove existing content, only add or improve",
|
|
@@ -596,8 +602,9 @@ function generateEnhanceSkill() {
|
|
|
596
602
|
"1. Run `claude-launchpad doctor` to check the score improved",
|
|
597
603
|
"2. Print suggested hooks (exact JSON) for .claude/settings.json but don't modify it",
|
|
598
604
|
"3. Print suggested MCP servers if external services detected (Postgres, Redis, Stripe, etc.)",
|
|
605
|
+
'4. If eval scenarios were generated, print: "Run this in your terminal (not inside Claude Code): `claude-launchpad eval --scenarios scenarios/ --runs 1`"',
|
|
599
606
|
"",
|
|
600
|
-
"**Done when:** doctor score is equal or higher, suggestions printed.",
|
|
607
|
+
"**Done when:** doctor score is equal or higher, suggestions printed, eval scenarios created if applicable.",
|
|
601
608
|
"",
|
|
602
609
|
"## Path-scoped rules generation",
|
|
603
610
|
"",
|
|
@@ -657,6 +664,72 @@ function generateEnhanceSkill() {
|
|
|
657
664
|
"- If no SessionStart hook exists, suggest one that injects TASKS.md",
|
|
658
665
|
"- DO NOT modify settings.json directly. Print exact JSON to add.",
|
|
659
666
|
"",
|
|
667
|
+
"## .claudeignore review",
|
|
668
|
+
"",
|
|
669
|
+
"Read .claudeignore and check if the patterns make sense for the detected stack:",
|
|
670
|
+
"",
|
|
671
|
+
"**Always flag:**",
|
|
672
|
+
"- Missing node_modules/ (JS/TS projects)",
|
|
673
|
+
"- Missing __pycache__/ or .venv/ (Python projects)",
|
|
674
|
+
"- Missing target/ (Rust/Java projects)",
|
|
675
|
+
"- Missing .env / .env.* patterns",
|
|
676
|
+
"- Missing lock files (pnpm-lock.yaml, package-lock.json, yarn.lock, etc.)",
|
|
677
|
+
"- Missing coverage/ directory",
|
|
678
|
+
"- Large generated files that waste context (*.min.js, *.map, migrations/)",
|
|
679
|
+
"",
|
|
680
|
+
"**Never flag:**",
|
|
681
|
+
"- Patterns the user clearly added intentionally",
|
|
682
|
+
"- Test fixtures or seed data (might be needed for context)",
|
|
683
|
+
"",
|
|
684
|
+
"If .claudeignore is missing entirely, create one with sensible defaults for the detected stack.",
|
|
685
|
+
"If it exists but has gaps, print suggested additions. Do NOT modify it directly.",
|
|
686
|
+
"",
|
|
687
|
+
"## Eval scenario generation",
|
|
688
|
+
"",
|
|
689
|
+
"After improving CLAUDE.md, generate 2-3 custom eval scenarios that test whether Claude follows the project's specific rules. Write them as YAML files in scenarios/ at the project root.",
|
|
690
|
+
"",
|
|
691
|
+
"**Scenario YAML format:**",
|
|
692
|
+
"```yaml",
|
|
693
|
+
"name: custom/scenario-name",
|
|
694
|
+
"description: What this scenario tests",
|
|
695
|
+
"setup:",
|
|
696
|
+
" files:",
|
|
697
|
+
" - path: src/example.ts",
|
|
698
|
+
" content: |",
|
|
699
|
+
" // Starter file that tempts Claude to break a rule",
|
|
700
|
+
" instructions: |",
|
|
701
|
+
" The specific rule from CLAUDE.md being tested.",
|
|
702
|
+
'prompt: "A task that would tempt Claude to break the rule"',
|
|
703
|
+
"checks:",
|
|
704
|
+
" - type: grep",
|
|
705
|
+
' pattern: "expected_pattern"',
|
|
706
|
+
" target: src/example.ts",
|
|
707
|
+
" expect: present",
|
|
708
|
+
" points: 5",
|
|
709
|
+
" label: What this check verifies",
|
|
710
|
+
" - type: file-exists",
|
|
711
|
+
" target: path/to/expected/file",
|
|
712
|
+
" expect: present",
|
|
713
|
+
" points: 5",
|
|
714
|
+
" label: What this check verifies",
|
|
715
|
+
"passingScore: 7",
|
|
716
|
+
"runs: 3",
|
|
717
|
+
"```",
|
|
718
|
+
"",
|
|
719
|
+
"**How to choose scenarios:**",
|
|
720
|
+
"1. Pick the 2-3 most important rules from ## Off-Limits and ## Conventions",
|
|
721
|
+
"2. Design a task that naturally tempts Claude to break each rule",
|
|
722
|
+
"3. Write checks that verify compliance (grep for patterns, file-exists for structure)",
|
|
723
|
+
"",
|
|
724
|
+
"**Check types available:** `grep` (pattern in file), `file-exists` (present/absent), `max-lines` (file length)",
|
|
725
|
+
"",
|
|
726
|
+
"**Examples of good custom scenarios:**",
|
|
727
|
+
'- Off-limits says "never use any" \u2192 task asks to build types, check for no `any` keyword',
|
|
728
|
+
'- Convention says "max 400 lines per file" \u2192 task asks to generate a large module, check line count',
|
|
729
|
+
'- Off-limits says "no raw SQL" \u2192 task asks to add a query, check for ORM usage',
|
|
730
|
+
"",
|
|
731
|
+
"**Skip if:** scenarios/ already has 3+ YAML files, or CLAUDE.md has no project-specific rules worth testing.",
|
|
732
|
+
"",
|
|
660
733
|
"## Other advanced configuration",
|
|
661
734
|
"",
|
|
662
735
|
"- If the project uses external APIs, suggest sandbox.network.allowedDomains",
|
|
@@ -1241,6 +1314,16 @@ async function analyzeRules(config) {
|
|
|
1241
1314
|
message: "No /lp-enhance skill found \u2014 use it inside Claude Code to AI-complete your CLAUDE.md",
|
|
1242
1315
|
fix: "Run `claude-launchpad init` or `doctor --fix` to generate the skill"
|
|
1243
1316
|
});
|
|
1317
|
+
} else {
|
|
1318
|
+
const installedVersion = await getSkillVersion(projectRoot);
|
|
1319
|
+
if (installedVersion !== null && installedVersion < ENHANCE_SKILL_VERSION) {
|
|
1320
|
+
issues.push({
|
|
1321
|
+
analyzer: "Rules",
|
|
1322
|
+
severity: "low",
|
|
1323
|
+
message: `/lp-enhance skill is outdated (v${installedVersion}, latest v${ENHANCE_SKILL_VERSION})`,
|
|
1324
|
+
fix: "Run `doctor --fix` to update the skill"
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1244
1327
|
}
|
|
1245
1328
|
if (config.rules.length === 0) {
|
|
1246
1329
|
issues.push({
|
|
@@ -1280,6 +1363,23 @@ async function analyzeRules(config) {
|
|
|
1280
1363
|
const score = Math.max(0, 100 - issues.length * 10);
|
|
1281
1364
|
return { name: "Rules", issues, score };
|
|
1282
1365
|
}
|
|
1366
|
+
async function getSkillVersion(projectRoot) {
|
|
1367
|
+
const paths = [
|
|
1368
|
+
join4(projectRoot, ".claude", "skills", "lp-enhance", "SKILL.md"),
|
|
1369
|
+
join4(homedir2(), ".claude", "skills", "lp-enhance", "SKILL.md")
|
|
1370
|
+
];
|
|
1371
|
+
for (const p of paths) {
|
|
1372
|
+
try {
|
|
1373
|
+
const content = await readFile3(p, "utf-8");
|
|
1374
|
+
const match = content.match(/<!-- lp-enhance-version: (\d+) -->/);
|
|
1375
|
+
if (match) return parseInt(match[1], 10);
|
|
1376
|
+
return 0;
|
|
1377
|
+
} catch {
|
|
1378
|
+
continue;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
return null;
|
|
1382
|
+
}
|
|
1283
1383
|
|
|
1284
1384
|
// src/commands/doctor/analyzers/permissions.ts
|
|
1285
1385
|
async function analyzePermissions(config) {
|
|
@@ -1441,7 +1541,7 @@ var MEMORY_MCP_TOOLS = [
|
|
|
1441
1541
|
function hasMemoryIndicators(config) {
|
|
1442
1542
|
const hasMcpServer = config.mcpServers.some((s) => s.name === "agentic-memory");
|
|
1443
1543
|
const hasHookRef = config.hooks.some(
|
|
1444
|
-
(h) => h.command?.includes("memory context")
|
|
1544
|
+
(h) => h.command?.includes("memory context")
|
|
1445
1545
|
);
|
|
1446
1546
|
return hasMcpServer || hasHookRef;
|
|
1447
1547
|
}
|
|
@@ -1459,15 +1559,15 @@ async function analyzeMemory(config) {
|
|
|
1459
1559
|
fix: "Add a SessionStart hook that runs `memory context` to inject relevant memories"
|
|
1460
1560
|
});
|
|
1461
1561
|
}
|
|
1462
|
-
const
|
|
1562
|
+
const hasStaleStopHook = config.hooks.some(
|
|
1463
1563
|
(h) => h.event === "Stop" && h.command?.includes("memory extract")
|
|
1464
1564
|
);
|
|
1465
|
-
if (
|
|
1565
|
+
if (hasStaleStopHook) {
|
|
1466
1566
|
issues.push({
|
|
1467
1567
|
analyzer: "Memory",
|
|
1468
|
-
severity: "
|
|
1469
|
-
message: "
|
|
1470
|
-
fix: "
|
|
1568
|
+
severity: "low",
|
|
1569
|
+
message: "Deprecated Stop hook found (memory extract) \u2014 auto-extraction was removed, Claude stores memories directly via MCP tools",
|
|
1570
|
+
fix: "Run `doctor --fix` to remove the stale Stop hook"
|
|
1471
1571
|
});
|
|
1472
1572
|
}
|
|
1473
1573
|
const autoMemoryDisabled = config.settings?.autoMemoryEnabled === false;
|
|
@@ -1641,11 +1741,13 @@ var FIX_TABLE = [
|
|
|
1641
1741
|
{ analyzer: "Permissions", match: "Sandbox not enabled", fix: (root) => addSandboxSettings(root) },
|
|
1642
1742
|
{ analyzer: "Permissions", match: ".env is protected by hooks but not in .claudeignore", fix: (root) => addEnvToClaudeignore(root) },
|
|
1643
1743
|
{ analyzer: "Rules", match: "No /lp-enhance skill", fix: (root) => createEnhanceSkill(root) },
|
|
1744
|
+
{ analyzer: "Rules", match: "lp-enhance skill is outdated", fix: (root) => updateEnhanceSkill(root) },
|
|
1644
1745
|
{ analyzer: "Settings", match: "Deprecated includeCoAuthoredBy", fix: (root) => migrateAttribution(root) },
|
|
1645
1746
|
{ analyzer: "Hooks", match: "SessionStart", fix: (root) => addSessionStartHook(root) },
|
|
1747
|
+
{ analyzer: "Memory", match: "Deprecated Stop hook", fix: (root) => removeStaleStopHook(root) },
|
|
1646
1748
|
{ analyzer: "Memory", match: "autoMemoryEnabled not disabled", fix: (root) => disableAutoMemory(root) },
|
|
1647
1749
|
{ analyzer: "Memory", match: "MCP tool permission", fix: (root) => addMemoryToolPermissions(root) },
|
|
1648
|
-
{ analyzer: "Memory", match: "CLAUDE.md missing memory guidance", fix: (root) => addClaudeMdSection(root, "## Memory", "Use agentic-memory to persist knowledge across sessions:\n- Memories are automatically injected at session start
|
|
1750
|
+
{ analyzer: "Memory", match: "CLAUDE.md missing memory guidance", fix: (root) => addClaudeMdSection(root, "## Memory", "Use agentic-memory to persist knowledge across sessions:\n- Memories are automatically injected at session start\n- STORE IMMEDIATELY when: a dependency strategy changes, an architecture decision is made, a convention is established, a bug pattern is discovered, or a feature is killed/added\n- Use memory_search before memory_store to check for duplicates\n- NEVER store credentials, API keys, tokens, or secrets in memories") }
|
|
1649
1751
|
];
|
|
1650
1752
|
async function tryFix(issue, root, detected) {
|
|
1651
1753
|
const entry = FIX_TABLE.find(
|
|
@@ -1888,6 +1990,36 @@ async function createEnhanceSkill(root) {
|
|
|
1888
1990
|
log.success("Generated /lp-enhance skill (.claude/skills/lp-enhance/)");
|
|
1889
1991
|
return true;
|
|
1890
1992
|
}
|
|
1993
|
+
async function updateEnhanceSkill(root) {
|
|
1994
|
+
const projectPath = join5(root, ".claude", "skills", "lp-enhance", "SKILL.md");
|
|
1995
|
+
const globalPath = join5(homedir3(), ".claude", "skills", "lp-enhance", "SKILL.md");
|
|
1996
|
+
const targetPath = await fileExists(projectPath) ? projectPath : await fileExists(globalPath) ? globalPath : null;
|
|
1997
|
+
if (!targetPath) return false;
|
|
1998
|
+
await writeFile2(targetPath, generateEnhanceSkill());
|
|
1999
|
+
log.success("Updated /lp-enhance skill to latest version");
|
|
2000
|
+
return true;
|
|
2001
|
+
}
|
|
2002
|
+
async function removeStaleStopHook(root) {
|
|
2003
|
+
const settings = await readSettingsJson(root);
|
|
2004
|
+
const hooks = settings.hooks;
|
|
2005
|
+
if (!hooks?.Stop) return false;
|
|
2006
|
+
const stopHooks = hooks.Stop;
|
|
2007
|
+
const filtered = stopHooks.filter((h) => {
|
|
2008
|
+
const innerHooks = h.hooks;
|
|
2009
|
+
return !innerHooks?.some(
|
|
2010
|
+
(ih) => typeof ih.command === "string" && ih.command.includes("memory extract")
|
|
2011
|
+
);
|
|
2012
|
+
});
|
|
2013
|
+
if (filtered.length === stopHooks.length) return false;
|
|
2014
|
+
if (filtered.length === 0) {
|
|
2015
|
+
delete hooks.Stop;
|
|
2016
|
+
} else {
|
|
2017
|
+
hooks.Stop = filtered;
|
|
2018
|
+
}
|
|
2019
|
+
await writeSettingsJson(root, settings);
|
|
2020
|
+
log.success("Removed deprecated Stop hook (memory extract)");
|
|
2021
|
+
return true;
|
|
2022
|
+
}
|
|
1891
2023
|
|
|
1892
2024
|
// src/commands/doctor/watcher.ts
|
|
1893
2025
|
import { readdir as readdir2, stat } from "fs/promises";
|
|
@@ -2695,7 +2827,7 @@ function createMemoryCommand() {
|
|
|
2695
2827
|
log.info("Skipped.");
|
|
2696
2828
|
return;
|
|
2697
2829
|
}
|
|
2698
|
-
const { runInstall } = await import("./install-
|
|
2830
|
+
const { runInstall } = await import("./install-4GQ57KCQ.js");
|
|
2699
2831
|
await runInstall({});
|
|
2700
2832
|
} else {
|
|
2701
2833
|
const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
|
|
@@ -2711,13 +2843,6 @@ function createMemoryCommand() {
|
|
|
2711
2843
|
}).helpCommand(false),
|
|
2712
2844
|
{ hidden: true }
|
|
2713
2845
|
);
|
|
2714
|
-
memory.addCommand(
|
|
2715
|
-
new Command4("extract").description("Extract facts from transcript (hook handler)").action(async () => {
|
|
2716
|
-
const { runExtract } = await import("./extract-HMAN7RW4.js");
|
|
2717
|
-
await runExtract();
|
|
2718
|
-
}).helpCommand(false),
|
|
2719
|
-
{ hidden: true }
|
|
2720
|
-
);
|
|
2721
2846
|
memory.addCommand(
|
|
2722
2847
|
new Command4("serve").description("Start MCP server (Claude Code)").action(async () => {
|
|
2723
2848
|
const { startServer } = await import("./commands/memory/server.js");
|
|
@@ -2741,7 +2866,7 @@ function createMemoryCommand() {
|
|
|
2741
2866
|
}
|
|
2742
2867
|
|
|
2743
2868
|
// src/cli.ts
|
|
2744
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2869
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.14.1", "-v, --version").action(async () => {
|
|
2745
2870
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2746
2871
|
if (hasConfig) {
|
|
2747
2872
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|