claude-launchpad 0.6.1 → 0.7.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 +54 -20
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-6ZVXZ4EF.js +101 -0
- package/dist/chunk-6ZVXZ4EF.js.map +1 -0
- package/dist/chunk-CSLWJEGD.js +25 -0
- package/dist/chunk-CSLWJEGD.js.map +1 -0
- package/dist/chunk-EBM7RBPB.js +35 -0
- package/dist/chunk-EBM7RBPB.js.map +1 -0
- package/dist/chunk-IILH26C7.js +258 -0
- package/dist/chunk-IILH26C7.js.map +1 -0
- package/dist/chunk-JE3BZ5S4.js +311 -0
- package/dist/chunk-JE3BZ5S4.js.map +1 -0
- package/dist/chunk-NAW47BYA.js +25 -0
- package/dist/chunk-NAW47BYA.js.map +1 -0
- package/dist/chunk-TALTTAMW.js +390 -0
- package/dist/chunk-TALTTAMW.js.map +1 -0
- package/dist/cli.js +348 -212
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +685 -0
- package/dist/commands/memory/server.js.map +1 -0
- package/dist/context-LNUZ4GCF.js +316 -0
- package/dist/context-LNUZ4GCF.js.map +1 -0
- package/dist/extract-NVAXO5CK.js +217 -0
- package/dist/extract-NVAXO5CK.js.map +1 -0
- package/dist/install-65P6LMUN.js +230 -0
- package/dist/install-65P6LMUN.js.map +1 -0
- package/dist/stats-FYAK7KZW.js +73 -0
- package/dist/stats-FYAK7KZW.js.map +1 -0
- package/dist/tui-R25NTQ4K.js +1100 -0
- package/dist/tui-R25NTQ4K.js.map +1 -0
- package/package.json +19 -4
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
readSettingsJson,
|
|
4
|
+
writeSettingsJson
|
|
5
|
+
} from "./chunk-CSLWJEGD.js";
|
|
6
|
+
import {
|
|
7
|
+
log,
|
|
8
|
+
printBanner,
|
|
9
|
+
printScoreCard,
|
|
10
|
+
renderDoctorReport
|
|
11
|
+
} from "./chunk-6ZVXZ4EF.js";
|
|
12
|
+
import "./chunk-2H7UOFLK.js";
|
|
2
13
|
|
|
3
14
|
// src/cli.ts
|
|
4
15
|
import { Command as Command5 } from "commander";
|
|
@@ -6,102 +17,11 @@ import { join as join11 } from "path";
|
|
|
6
17
|
|
|
7
18
|
// src/commands/init/index.ts
|
|
8
19
|
import { Command } from "commander";
|
|
9
|
-
import { input, confirm } from "@inquirer/prompts";
|
|
20
|
+
import { input, confirm, select } from "@inquirer/prompts";
|
|
10
21
|
import { writeFile, mkdir, readFile as readFile2 } from "fs/promises";
|
|
22
|
+
import { homedir } from "os";
|
|
11
23
|
import { join as join2 } from "path";
|
|
12
24
|
|
|
13
|
-
// src/lib/output.ts
|
|
14
|
-
import chalk from "chalk";
|
|
15
|
-
var colors = {
|
|
16
|
-
success: chalk.green,
|
|
17
|
-
error: chalk.red,
|
|
18
|
-
warn: chalk.yellow,
|
|
19
|
-
info: chalk.cyan,
|
|
20
|
-
dim: chalk.dim,
|
|
21
|
-
bold: chalk.bold,
|
|
22
|
-
score: (score) => {
|
|
23
|
-
if (score >= 80) return chalk.green.bold(`${score}%`);
|
|
24
|
-
if (score >= 60) return chalk.yellow.bold(`${score}%`);
|
|
25
|
-
return chalk.red.bold(`${score}%`);
|
|
26
|
-
},
|
|
27
|
-
severity: (sev) => {
|
|
28
|
-
const map = {
|
|
29
|
-
critical: chalk.bgRed.white.bold,
|
|
30
|
-
high: chalk.red.bold,
|
|
31
|
-
medium: chalk.yellow,
|
|
32
|
-
low: chalk.cyan,
|
|
33
|
-
info: chalk.dim
|
|
34
|
-
};
|
|
35
|
-
return map[sev](` ${sev.toUpperCase()} `);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
var log = {
|
|
39
|
-
success: (msg) => console.log(` ${chalk.green("\u2713")} ${msg}`),
|
|
40
|
-
error: (msg) => console.log(` ${chalk.red("\u2717")} ${msg}`),
|
|
41
|
-
warn: (msg) => console.log(` ${chalk.yellow("!")} ${msg}`),
|
|
42
|
-
step: (msg) => console.log(` ${chalk.cyan("\u2192")} ${msg}`),
|
|
43
|
-
info: (msg) => console.log(` ${chalk.dim("\xB7")} ${msg}`),
|
|
44
|
-
blank: () => console.log()
|
|
45
|
-
};
|
|
46
|
-
function printBanner() {
|
|
47
|
-
log.blank();
|
|
48
|
-
console.log(chalk.cyan.bold(" Claude Launchpad"));
|
|
49
|
-
console.log(chalk.dim(" Scaffold \xB7 Diagnose \xB7 Evaluate"));
|
|
50
|
-
log.blank();
|
|
51
|
-
}
|
|
52
|
-
function printScoreCard(label, score, max = 100) {
|
|
53
|
-
const pct = Math.round(score / max * 100);
|
|
54
|
-
const bar = renderBar(pct, 20);
|
|
55
|
-
console.log(` ${chalk.bold(label.padEnd(22))} ${bar} ${colors.score(pct).padStart(12)}`);
|
|
56
|
-
}
|
|
57
|
-
function renderBar(pct, width) {
|
|
58
|
-
const filled = Math.round(pct / 100 * width);
|
|
59
|
-
const empty = width - filled;
|
|
60
|
-
const color = pct >= 80 ? chalk.green : pct >= 60 ? chalk.yellow : chalk.red;
|
|
61
|
-
return color("\u2501".repeat(filled)) + chalk.dim("\u2500".repeat(empty));
|
|
62
|
-
}
|
|
63
|
-
function printIssue(severity, _analyzer, message) {
|
|
64
|
-
const sevLabel = {
|
|
65
|
-
critical: chalk.bgRed.white.bold(" CRIT "),
|
|
66
|
-
high: chalk.red.bold("HIGH"),
|
|
67
|
-
medium: chalk.yellow("MED "),
|
|
68
|
-
low: chalk.dim("LOW "),
|
|
69
|
-
info: chalk.dim("INFO")
|
|
70
|
-
};
|
|
71
|
-
console.log(` ${sevLabel[severity]} ${message}`);
|
|
72
|
-
}
|
|
73
|
-
function renderDoctorReport(results, options) {
|
|
74
|
-
const overallScore = Math.round(
|
|
75
|
-
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
76
|
-
);
|
|
77
|
-
for (const result of results) {
|
|
78
|
-
printScoreCard(result.name, result.score);
|
|
79
|
-
}
|
|
80
|
-
log.blank();
|
|
81
|
-
printScoreCard("Overall", overallScore);
|
|
82
|
-
log.blank();
|
|
83
|
-
const allIssues = results.flatMap((r) => r.issues);
|
|
84
|
-
const actionable = allIssues.filter((i) => i.severity !== "info");
|
|
85
|
-
if (actionable.length === 0) {
|
|
86
|
-
log.success("No issues found. Your configuration looks solid.");
|
|
87
|
-
return { overallScore, actionableCount: 0 };
|
|
88
|
-
}
|
|
89
|
-
const sorted = [...actionable].sort((a, b) => {
|
|
90
|
-
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
91
|
-
return (order[a.severity] ?? 4) - (order[b.severity] ?? 4);
|
|
92
|
-
});
|
|
93
|
-
for (const issue of sorted) {
|
|
94
|
-
printIssue(issue.severity, issue.analyzer, issue.message);
|
|
95
|
-
}
|
|
96
|
-
log.blank();
|
|
97
|
-
if (options?.afterFix) {
|
|
98
|
-
log.info(`${actionable.length} remaining issue(s) require manual intervention.`);
|
|
99
|
-
} else {
|
|
100
|
-
log.info(`${actionable.length} issue(s). Run ${chalk.bold("--fix")} to auto-repair or ${chalk.bold("--fix --dry-run")} to preview.`);
|
|
101
|
-
}
|
|
102
|
-
return { overallScore, actionableCount: actionable.length };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
25
|
// src/lib/fs-utils.ts
|
|
106
26
|
import { readFile, access } from "fs/promises";
|
|
107
27
|
async function fileExists(path) {
|
|
@@ -617,6 +537,62 @@ DerivedData/
|
|
|
617
537
|
return sections.join("\n") + "\n";
|
|
618
538
|
}
|
|
619
539
|
|
|
540
|
+
// src/commands/init/generators/skill-enhance.ts
|
|
541
|
+
function generateEnhanceSkill() {
|
|
542
|
+
return `---
|
|
543
|
+
name: lp-enhance
|
|
544
|
+
description: AI-improve your CLAUDE.md based on codebase analysis. Fills in architecture, conventions, guardrails, and suggests hooks and MCP servers.
|
|
545
|
+
disable-model-invocation: true
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
# lp-enhance - AI-powered CLAUDE.md improver
|
|
549
|
+
|
|
550
|
+
Read CLAUDE.md and the project's codebase, then update CLAUDE.md to fill in missing or incomplete sections.
|
|
551
|
+
|
|
552
|
+
## Budget Rule
|
|
553
|
+
|
|
554
|
+
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:
|
|
555
|
+
- Create .claude/rules/conventions.md for detailed coding patterns
|
|
556
|
+
- Create .claude/rules/architecture.md for detailed structure docs
|
|
557
|
+
- Keep CLAUDE.md to HIGH-LEVEL summaries only (3-5 bullets per section max)
|
|
558
|
+
|
|
559
|
+
## Sections to fill or preserve (DO NOT remove existing sections)
|
|
560
|
+
|
|
561
|
+
1. **## Stack** - if missing or incomplete, detect and add language, framework, package manager
|
|
562
|
+
2. **## Architecture** - 3-5 bullet points describing the codebase shape (not a full directory tree)
|
|
563
|
+
3. **## Conventions** - max 8 key patterns. Move detailed rules to .claude/rules/conventions.md
|
|
564
|
+
4. **## Off-Limits** - max 8 guardrails specific to this project
|
|
565
|
+
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
|
|
566
|
+
6. **## Key Decisions** - only decisions that affect how Claude should work in this codebase
|
|
567
|
+
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.
|
|
568
|
+
|
|
569
|
+
## Hook review
|
|
570
|
+
|
|
571
|
+
Also review .claude/settings.json hooks:
|
|
572
|
+
- Read the existing hooks in .claude/settings.json
|
|
573
|
+
- If you see project-specific patterns that deserve hooks (e.g., protected directories, test file patterns, migration files), suggest adding them
|
|
574
|
+
- If no PostCompact hook exists, suggest adding one that re-injects TASKS.md after context compaction
|
|
575
|
+
- If no SessionStart hook exists, suggest adding one that injects TASKS.md at session startup
|
|
576
|
+
- DO NOT overwrite existing hooks - only add new ones specific to this project
|
|
577
|
+
- Print hook suggestions at the end with the exact JSON to add, don't modify settings.json directly
|
|
578
|
+
|
|
579
|
+
## Advanced configuration opportunities
|
|
580
|
+
|
|
581
|
+
- If the project has both app code and tests, suggest creating path-scoped .claude/rules/ files with paths: frontmatter
|
|
582
|
+
- If the project uses external APIs, suggest sandbox.network.allowedDomains to restrict outbound traffic
|
|
583
|
+
- If you detect a monorepo, suggest claudeMdExcludes in settings.json
|
|
584
|
+
|
|
585
|
+
## Rules
|
|
586
|
+
|
|
587
|
+
- Don't remove existing content - only add or improve
|
|
588
|
+
- Be specific to THIS project, not generic advice
|
|
589
|
+
- Use bullet points, not paragraphs
|
|
590
|
+
- If a section would exceed 8 bullets, split into a .claude/rules/ file and reference it
|
|
591
|
+
- After editing, count the actionable lines. If over 120, move content to rules files until under
|
|
592
|
+
- Run \`claude-launchpad doctor\` after to verify score improved
|
|
593
|
+
`;
|
|
594
|
+
}
|
|
595
|
+
|
|
620
596
|
// src/commands/init/index.ts
|
|
621
597
|
function createInitCommand() {
|
|
622
598
|
return new Command("init").description("Set up Claude Code configuration for any project").option("-n, --name <name>", "Project name").option("-y, --yes", "Accept all defaults").action(async (opts) => {
|
|
@@ -649,14 +625,15 @@ function createInitCommand() {
|
|
|
649
625
|
});
|
|
650
626
|
if (!overwrite) {
|
|
651
627
|
log.info("Keeping existing CLAUDE.md");
|
|
628
|
+
await createEnhanceSkillPrompt(root, false);
|
|
652
629
|
log.step("Tip: run `claude-launchpad doctor` to check your existing config");
|
|
653
630
|
return;
|
|
654
631
|
}
|
|
655
632
|
}
|
|
656
|
-
await scaffold(root, options, detected);
|
|
633
|
+
await scaffold(root, options, detected, opts.yes);
|
|
657
634
|
});
|
|
658
635
|
}
|
|
659
|
-
async function scaffold(root, options, detected) {
|
|
636
|
+
async function scaffold(root, options, detected, skipPrompts) {
|
|
660
637
|
log.step("Generating configuration...");
|
|
661
638
|
const claudeMd = generateClaudeMd(options, detected);
|
|
662
639
|
const tasksMd = generateTasksMd(options);
|
|
@@ -701,8 +678,10 @@ async function scaffold(root, options, detected) {
|
|
|
701
678
|
if (!hasClaudeGitignore) log.success("Generated .claude/.gitignore");
|
|
702
679
|
if (!hasClaudeignore) log.success("Generated .claudeignore");
|
|
703
680
|
if (!hasRules) log.success("Generated .claude/rules/conventions.md");
|
|
681
|
+
await createEnhanceSkillPrompt(root, skipPrompts);
|
|
704
682
|
log.blank();
|
|
705
683
|
log.success("Done! Run `claude` to start.");
|
|
684
|
+
log.info("Use `/lp-enhance` inside Claude Code to have AI complete your CLAUDE.md.");
|
|
706
685
|
log.info("Run `claude-launchpad doctor` to check your config quality.");
|
|
707
686
|
log.blank();
|
|
708
687
|
}
|
|
@@ -734,6 +713,26 @@ function generateStarterRules(detected) {
|
|
|
734
713
|
lines.push("");
|
|
735
714
|
return lines.join("\n");
|
|
736
715
|
}
|
|
716
|
+
async function createEnhanceSkillPrompt(root, skipPrompts) {
|
|
717
|
+
const projectPath = join2(root, ".claude", "skills", "lp-enhance", "SKILL.md");
|
|
718
|
+
const globalPath = join2(homedir(), ".claude", "skills", "lp-enhance", "SKILL.md");
|
|
719
|
+
const legacyProject = join2(root, ".claude", "commands", "lp-enhance.md");
|
|
720
|
+
const legacyGlobal = join2(homedir(), ".claude", "commands", "lp-enhance.md");
|
|
721
|
+
if (await fileExists(projectPath) || await fileExists(globalPath) || await fileExists(legacyProject) || await fileExists(legacyGlobal)) return;
|
|
722
|
+
const scope = skipPrompts ? "project" : await select({
|
|
723
|
+
message: "Install /lp-enhance skill (AI-powered CLAUDE.md improver):",
|
|
724
|
+
choices: [
|
|
725
|
+
{ value: "project", name: "Project scope (.claude/skills/)" },
|
|
726
|
+
{ value: "global", name: "Global scope (~/.claude/skills/)" },
|
|
727
|
+
{ value: "skip", name: "Skip" }
|
|
728
|
+
]
|
|
729
|
+
});
|
|
730
|
+
if (scope === "skip") return;
|
|
731
|
+
const targetDir = scope === "global" ? join2(homedir(), ".claude", "skills", "lp-enhance") : join2(root, ".claude", "skills", "lp-enhance");
|
|
732
|
+
await mkdir(targetDir, { recursive: true });
|
|
733
|
+
await writeFile(join2(targetDir, "SKILL.md"), generateEnhanceSkill());
|
|
734
|
+
log.success(`Generated /lp-enhance skill (${scope} scope)`);
|
|
735
|
+
}
|
|
737
736
|
async function mergeSettings(existingPath, generated) {
|
|
738
737
|
try {
|
|
739
738
|
const existing = JSON.parse(await readFile2(existingPath, "utf-8"));
|
|
@@ -757,7 +756,7 @@ async function mergeSettings(existingPath, generated) {
|
|
|
757
756
|
|
|
758
757
|
// src/commands/doctor/index.ts
|
|
759
758
|
import { Command as Command2 } from "commander";
|
|
760
|
-
import
|
|
759
|
+
import chalk from "chalk";
|
|
761
760
|
|
|
762
761
|
// src/lib/parser.ts
|
|
763
762
|
import { readdir, access as access2 } from "fs/promises";
|
|
@@ -1027,18 +1026,6 @@ async function analyzeSettings(config) {
|
|
|
1027
1026
|
message: "No claudeMdExcludes configured \u2014 consider adding this if you have a monorepo"
|
|
1028
1027
|
});
|
|
1029
1028
|
}
|
|
1030
|
-
const broadMatchers = ["Bash", "Write", "Edit", "Read"];
|
|
1031
|
-
const hooksWithoutTimeout = config.hooks.filter(
|
|
1032
|
-
(h) => !h.timeout && broadMatchers.some((m) => h.matcher?.includes(m))
|
|
1033
|
-
);
|
|
1034
|
-
if (hooksWithoutTimeout.length > 0) {
|
|
1035
|
-
issues.push({
|
|
1036
|
-
analyzer: "Settings",
|
|
1037
|
-
severity: "low",
|
|
1038
|
-
message: `${hooksWithoutTimeout.length} hook(s) on broad matchers without timeout \u2014 defaults to 60s per invocation`,
|
|
1039
|
-
fix: "Add timeout (in seconds) to hooks on Bash, Write, Edit, or Read matchers"
|
|
1040
|
-
});
|
|
1041
|
-
}
|
|
1042
1029
|
if (config.settings.autoMemoryEnabled === false) {
|
|
1043
1030
|
const hasMemorySection = config.claudeMdContent?.includes("## Memory") ?? false;
|
|
1044
1031
|
if (!hasMemorySection) {
|
|
@@ -1125,6 +1112,7 @@ async function analyzeHooks(config) {
|
|
|
1125
1112
|
// src/commands/doctor/analyzers/rules.ts
|
|
1126
1113
|
import { readFile as readFile3 } from "fs/promises";
|
|
1127
1114
|
import { basename as basename2, join as join4, dirname } from "path";
|
|
1115
|
+
import { homedir as homedir2 } from "os";
|
|
1128
1116
|
async function analyzeRules(config) {
|
|
1129
1117
|
const issues = [];
|
|
1130
1118
|
const projectRoot = config.claudeMdPath ? dirname(config.claudeMdPath) : process.cwd();
|
|
@@ -1137,6 +1125,18 @@ async function analyzeRules(config) {
|
|
|
1137
1125
|
fix: "Run `claude-launchpad init` or `doctor --fix` to generate one"
|
|
1138
1126
|
});
|
|
1139
1127
|
}
|
|
1128
|
+
const hasSkillInProject = config.skills.some(
|
|
1129
|
+
(s) => basename2(s) === "SKILL.md" && s.includes("lp-enhance") || basename2(s) === "lp-enhance.md"
|
|
1130
|
+
);
|
|
1131
|
+
const hasSkillGlobal = await fileExists(join4(homedir2(), ".claude", "skills", "lp-enhance", "SKILL.md")) || await fileExists(join4(homedir2(), ".claude", "commands", "lp-enhance.md"));
|
|
1132
|
+
if (!hasSkillInProject && !hasSkillGlobal) {
|
|
1133
|
+
issues.push({
|
|
1134
|
+
analyzer: "Rules",
|
|
1135
|
+
severity: "low",
|
|
1136
|
+
message: "No /lp-enhance skill found \u2014 use it inside Claude Code to AI-complete your CLAUDE.md",
|
|
1137
|
+
fix: "Run `claude-launchpad init` or `doctor --fix` to generate the skill"
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
1140
|
if (config.rules.length === 0) {
|
|
1141
1141
|
issues.push({
|
|
1142
1142
|
analyzer: "Rules",
|
|
@@ -1282,7 +1282,7 @@ async function analyzeMcp(config) {
|
|
|
1282
1282
|
issues.push({
|
|
1283
1283
|
analyzer: "MCP",
|
|
1284
1284
|
severity: "info",
|
|
1285
|
-
message: "No MCP servers configured.
|
|
1285
|
+
message: "No MCP servers configured. Use `/lp-enhance` in Claude Code to get stack-specific recommendations."
|
|
1286
1286
|
});
|
|
1287
1287
|
return { name: "MCP Servers", issues, score: 50 };
|
|
1288
1288
|
}
|
|
@@ -1406,9 +1406,97 @@ async function analyzeQuality(config) {
|
|
|
1406
1406
|
return { name: "CLAUDE.md Quality", issues, score };
|
|
1407
1407
|
}
|
|
1408
1408
|
|
|
1409
|
+
// src/commands/doctor/analyzers/memory.ts
|
|
1410
|
+
var MEMORY_MCP_TOOLS = [
|
|
1411
|
+
"mcp__agentic-memory__memory_store",
|
|
1412
|
+
"mcp__agentic-memory__memory_search",
|
|
1413
|
+
"mcp__agentic-memory__memory_recent",
|
|
1414
|
+
"mcp__agentic-memory__memory_forget",
|
|
1415
|
+
"mcp__agentic-memory__memory_relate",
|
|
1416
|
+
"mcp__agentic-memory__memory_stats",
|
|
1417
|
+
"mcp__agentic-memory__memory_update"
|
|
1418
|
+
];
|
|
1419
|
+
function hasMemoryIndicators(config) {
|
|
1420
|
+
const hasMcpServer = config.mcpServers.some((s) => s.name === "agentic-memory");
|
|
1421
|
+
const hasHookRef = config.hooks.some(
|
|
1422
|
+
(h) => h.command?.includes("memory context") || h.command?.includes("memory extract")
|
|
1423
|
+
);
|
|
1424
|
+
return hasMcpServer || hasHookRef;
|
|
1425
|
+
}
|
|
1426
|
+
async function analyzeMemory(config) {
|
|
1427
|
+
if (!hasMemoryIndicators(config)) return null;
|
|
1428
|
+
const issues = [];
|
|
1429
|
+
const hasMcpServer = config.mcpServers.some((s) => s.name === "agentic-memory");
|
|
1430
|
+
if (!hasMcpServer) {
|
|
1431
|
+
issues.push({
|
|
1432
|
+
analyzer: "Memory",
|
|
1433
|
+
severity: "high",
|
|
1434
|
+
message: "agentic-memory MCP server not found in mcpServers",
|
|
1435
|
+
fix: "Add agentic-memory to mcpServers in .claude/settings.json"
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
const hasSessionStart = config.hooks.some(
|
|
1439
|
+
(h) => h.event === "SessionStart" && h.command?.includes("memory context")
|
|
1440
|
+
);
|
|
1441
|
+
if (!hasSessionStart) {
|
|
1442
|
+
issues.push({
|
|
1443
|
+
analyzer: "Memory",
|
|
1444
|
+
severity: "high",
|
|
1445
|
+
message: "No SessionStart hook with memory context injection",
|
|
1446
|
+
fix: "Add a SessionStart hook that runs `memory context` to inject relevant memories"
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
const hasStopHook = config.hooks.some(
|
|
1450
|
+
(h) => h.event === "Stop" && h.command?.includes("memory extract")
|
|
1451
|
+
);
|
|
1452
|
+
if (!hasStopHook) {
|
|
1453
|
+
issues.push({
|
|
1454
|
+
analyzer: "Memory",
|
|
1455
|
+
severity: "medium",
|
|
1456
|
+
message: "No Stop hook with memory extract for session learnings",
|
|
1457
|
+
fix: "Add a Stop hook that runs `memory extract` to capture session insights"
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
const autoMemoryDisabled = config.settings?.autoMemoryEnabled === false;
|
|
1461
|
+
if (!autoMemoryDisabled) {
|
|
1462
|
+
issues.push({
|
|
1463
|
+
analyzer: "Memory",
|
|
1464
|
+
severity: "medium",
|
|
1465
|
+
message: "autoMemoryEnabled not disabled \u2014 built-in memory may conflict with agentic-memory",
|
|
1466
|
+
fix: "Set autoMemoryEnabled: false in .claude/settings.json"
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
const hasMemoryGuidance = config.claudeMdContent?.includes("agentic-memory") || config.claudeMdContent?.includes("## Memory");
|
|
1470
|
+
if (!hasMemoryGuidance) {
|
|
1471
|
+
issues.push({
|
|
1472
|
+
analyzer: "Memory",
|
|
1473
|
+
severity: "low",
|
|
1474
|
+
message: "CLAUDE.md missing memory guidance section",
|
|
1475
|
+
fix: "Add a ## Memory section to CLAUDE.md describing when and how to use agentic-memory"
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
const allowList = config.settings?.allowedTools ?? [];
|
|
1479
|
+
const missingTools = MEMORY_MCP_TOOLS.filter((t) => !allowList.includes(t));
|
|
1480
|
+
if (missingTools.length > 0) {
|
|
1481
|
+
issues.push({
|
|
1482
|
+
analyzer: "Memory",
|
|
1483
|
+
severity: "low",
|
|
1484
|
+
message: `${missingTools.length} agentic-memory MCP tool permission(s) missing from allowedTools`,
|
|
1485
|
+
fix: "Add all agentic-memory tool names to allowedTools in .claude/settings.json"
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
const critical = issues.filter((i) => i.severity === "critical").length;
|
|
1489
|
+
const high = issues.filter((i) => i.severity === "high").length;
|
|
1490
|
+
const medium = issues.filter((i) => i.severity === "medium").length;
|
|
1491
|
+
const low = issues.filter((i) => i.severity === "low").length;
|
|
1492
|
+
const score = Math.max(0, 100 - (critical * 40 + high * 20 + medium * 10 + low * 5));
|
|
1493
|
+
return { name: "Memory", issues, score };
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1409
1496
|
// src/commands/doctor/fixer.ts
|
|
1410
1497
|
import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2, access as access4 } from "fs/promises";
|
|
1411
1498
|
import { join as join5 } from "path";
|
|
1499
|
+
import { homedir as homedir3 } from "os";
|
|
1412
1500
|
async function applyFixes(issues, projectRoot) {
|
|
1413
1501
|
const detected = await detectProject(projectRoot);
|
|
1414
1502
|
let fixed = 0;
|
|
@@ -1433,7 +1521,7 @@ var FIX_TABLE = [
|
|
|
1433
1521
|
{ analyzer: "Hooks", match: ".env file protection", fix: (root) => addEnvProtectionHook(root) },
|
|
1434
1522
|
{ analyzer: "Hooks", match: "auto-format", fix: (root, detected) => addAutoFormatHook(root, detected) },
|
|
1435
1523
|
{ analyzer: "Hooks", match: "No PreToolUse", fix: (root) => addEnvProtectionHook(root) },
|
|
1436
|
-
{ analyzer: "Quality", match: "Architecture", fix: (root) => addClaudeMdSection(root, "## Architecture", "<!-- TODO: Describe your codebase structure. Run
|
|
1524
|
+
{ analyzer: "Quality", match: "Architecture", fix: (root) => addClaudeMdSection(root, "## Architecture", "<!-- TODO: Describe your codebase structure. Run `/lp-enhance` to auto-fill this. -->") },
|
|
1437
1525
|
{ analyzer: "Quality", match: "Off-Limits", fix: (root) => 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") },
|
|
1438
1526
|
{ analyzer: "Quality", match: "Commands", fix: (root) => addClaudeMdSection(root, "## Commands", "<!-- TODO: Add your dev/build/test commands -->") },
|
|
1439
1527
|
{ analyzer: "Quality", match: "Stack", fix: (root, detected) => {
|
|
@@ -1452,8 +1540,12 @@ var FIX_TABLE = [
|
|
|
1452
1540
|
{ analyzer: "Permissions", match: "Bypass permissions mode", fix: (root) => addBypassDisable(root) },
|
|
1453
1541
|
{ analyzer: "Permissions", match: "Sandbox not enabled", fix: (root) => addSandboxSettings(root) },
|
|
1454
1542
|
{ analyzer: "Permissions", match: ".env is protected by hooks but not in .claudeignore", fix: (root) => addEnvToClaudeignore(root) },
|
|
1543
|
+
{ analyzer: "Rules", match: "No /lp-enhance skill", fix: (root) => createEnhanceSkill(root) },
|
|
1455
1544
|
{ analyzer: "Settings", match: "Deprecated includeCoAuthoredBy", fix: (root) => migrateAttribution(root) },
|
|
1456
|
-
{ analyzer: "Hooks", match: "SessionStart", fix: (root) => addSessionStartHook(root) }
|
|
1545
|
+
{ analyzer: "Hooks", match: "SessionStart", fix: (root) => addSessionStartHook(root) },
|
|
1546
|
+
{ analyzer: "Memory", match: "autoMemoryEnabled not disabled", fix: (root) => disableAutoMemory(root) },
|
|
1547
|
+
{ analyzer: "Memory", match: "MCP tool permission", fix: (root) => addMemoryToolPermissions(root) },
|
|
1548
|
+
{ 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 and extracted at session end\n- Save non-obvious decisions, gotchas, and deferred issues\n- Check memory for relevant context before starting work") }
|
|
1457
1549
|
];
|
|
1458
1550
|
async function tryFix(issue, root, detected) {
|
|
1459
1551
|
const entry = FIX_TABLE.find(
|
|
@@ -1678,19 +1770,45 @@ async function createStarterRules(root) {
|
|
|
1678
1770
|
log.success("Created .claude/rules/conventions.md with starter rules");
|
|
1679
1771
|
return true;
|
|
1680
1772
|
}
|
|
1681
|
-
async function
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1773
|
+
async function disableAutoMemory(root) {
|
|
1774
|
+
const settings = await readSettingsJson(root);
|
|
1775
|
+
if (settings.autoMemoryEnabled === false) return false;
|
|
1776
|
+
settings.autoMemoryEnabled = false;
|
|
1777
|
+
await writeSettingsJson(root, settings);
|
|
1778
|
+
log.success("Set autoMemoryEnabled: false (prevents conflict with agentic-memory)");
|
|
1779
|
+
return true;
|
|
1780
|
+
}
|
|
1781
|
+
async function addMemoryToolPermissions(root) {
|
|
1782
|
+
const settings = await readSettingsJson(root);
|
|
1783
|
+
const permissions = settings.permissions ?? {};
|
|
1784
|
+
const allow = permissions.allow ?? [];
|
|
1785
|
+
const tools = [
|
|
1786
|
+
"mcp__agentic-memory__memory_store",
|
|
1787
|
+
"mcp__agentic-memory__memory_search",
|
|
1788
|
+
"mcp__agentic-memory__memory_recent",
|
|
1789
|
+
"mcp__agentic-memory__memory_forget",
|
|
1790
|
+
"mcp__agentic-memory__memory_relate",
|
|
1791
|
+
"mcp__agentic-memory__memory_stats",
|
|
1792
|
+
"mcp__agentic-memory__memory_update"
|
|
1793
|
+
];
|
|
1794
|
+
const missing = tools.filter((t) => !allow.includes(t));
|
|
1795
|
+
if (missing.length === 0) return false;
|
|
1796
|
+
settings.permissions = { ...permissions, allow: [...allow, ...missing] };
|
|
1797
|
+
await writeSettingsJson(root, settings);
|
|
1798
|
+
log.success("Added agentic-memory MCP tool permissions to allowedTools");
|
|
1799
|
+
return true;
|
|
1689
1800
|
}
|
|
1690
|
-
async function
|
|
1691
|
-
const
|
|
1692
|
-
|
|
1693
|
-
|
|
1801
|
+
async function createEnhanceSkill(root) {
|
|
1802
|
+
const skillDir = join5(root, ".claude", "skills", "lp-enhance");
|
|
1803
|
+
const skillPath = join5(skillDir, "SKILL.md");
|
|
1804
|
+
const globalPath = join5(homedir3(), ".claude", "skills", "lp-enhance", "SKILL.md");
|
|
1805
|
+
const legacyProject = join5(root, ".claude", "commands", "lp-enhance.md");
|
|
1806
|
+
const legacyGlobal = join5(homedir3(), ".claude", "commands", "lp-enhance.md");
|
|
1807
|
+
if (await fileExists(skillPath) || await fileExists(globalPath) || await fileExists(legacyProject) || await fileExists(legacyGlobal)) return false;
|
|
1808
|
+
await mkdir2(skillDir, { recursive: true });
|
|
1809
|
+
await writeFile2(skillPath, generateEnhanceSkill());
|
|
1810
|
+
log.success("Generated /lp-enhance skill (.claude/skills/lp-enhance/)");
|
|
1811
|
+
return true;
|
|
1694
1812
|
}
|
|
1695
1813
|
|
|
1696
1814
|
// src/commands/doctor/watcher.ts
|
|
@@ -1745,7 +1863,7 @@ async function getFileSnapshot(projectRoot) {
|
|
|
1745
1863
|
}
|
|
1746
1864
|
async function runAndDisplay(projectRoot) {
|
|
1747
1865
|
console.log("\x1B[36m\x1B[1m Claude Launchpad\x1B[0m");
|
|
1748
|
-
console.log("\x1B[2m Scaffold \xB7 Diagnose \xB7 Evaluate\x1B[0m");
|
|
1866
|
+
console.log("\x1B[2m Scaffold \xB7 Diagnose \xB7 Evaluate \xB7 Remember\x1B[0m");
|
|
1749
1867
|
log.blank();
|
|
1750
1868
|
const config = await parseClaudeConfig(projectRoot);
|
|
1751
1869
|
if (config.claudeMdContent === null && config.settings === null) {
|
|
@@ -1791,6 +1909,10 @@ function createDoctorCommand() {
|
|
|
1791
1909
|
analyzePermissions(config),
|
|
1792
1910
|
analyzeMcp(config)
|
|
1793
1911
|
]);
|
|
1912
|
+
const memoryResult = await analyzeMemory(config);
|
|
1913
|
+
if (memoryResult) {
|
|
1914
|
+
results.push(memoryResult);
|
|
1915
|
+
}
|
|
1794
1916
|
if (opts.json) {
|
|
1795
1917
|
const overallScore2 = Math.round(
|
|
1796
1918
|
results.reduce((sum, r) => sum + r.score, 0) / results.length
|
|
@@ -1805,7 +1927,10 @@ function createDoctorCommand() {
|
|
|
1805
1927
|
if (opts.fix) {
|
|
1806
1928
|
const allIssues = results.flatMap((r) => r.issues);
|
|
1807
1929
|
const fixable = allIssues.filter((i) => i.severity !== "info");
|
|
1808
|
-
if (fixable.length
|
|
1930
|
+
if (fixable.length === 0) {
|
|
1931
|
+
renderDoctorReport(results);
|
|
1932
|
+
log.success("Nothing to fix.");
|
|
1933
|
+
} else if (fixable.length > 0) {
|
|
1809
1934
|
if (opts.dryRun) {
|
|
1810
1935
|
const withFix = fixable.filter((i) => i.fix);
|
|
1811
1936
|
log.blank();
|
|
@@ -1820,7 +1945,7 @@ function createDoctorCommand() {
|
|
|
1820
1945
|
if (skipped > 0) {
|
|
1821
1946
|
log.info(`${skipped} issue(s) require manual intervention.`);
|
|
1822
1947
|
}
|
|
1823
|
-
log.info(`Then
|
|
1948
|
+
log.info(`Then use ${chalk.bold("/lp-enhance")} inside Claude Code to have Claude restructure and complete your CLAUDE.md.`);
|
|
1824
1949
|
return;
|
|
1825
1950
|
}
|
|
1826
1951
|
log.blank();
|
|
@@ -1841,8 +1966,12 @@ function createDoctorCommand() {
|
|
|
1841
1966
|
analyzePermissions(updatedConfig),
|
|
1842
1967
|
analyzeMcp(updatedConfig)
|
|
1843
1968
|
]);
|
|
1969
|
+
const updatedMemoryResult = await analyzeMemory(updatedConfig);
|
|
1970
|
+
if (updatedMemoryResult) {
|
|
1971
|
+
updatedResults.push(updatedMemoryResult);
|
|
1972
|
+
}
|
|
1844
1973
|
renderDoctorReport(updatedResults, { afterFix: true });
|
|
1845
|
-
log.info(`Then
|
|
1974
|
+
log.info(`Then use ${chalk.bold("/lp-enhance")} inside Claude Code to have Claude restructure and complete your CLAUDE.md.`);
|
|
1846
1975
|
}
|
|
1847
1976
|
}
|
|
1848
1977
|
}
|
|
@@ -1857,9 +1986,9 @@ function createDoctorCommand() {
|
|
|
1857
1986
|
|
|
1858
1987
|
// src/commands/eval/index.ts
|
|
1859
1988
|
import { Command as Command3 } from "commander";
|
|
1860
|
-
import { select } from "@inquirer/prompts";
|
|
1989
|
+
import { select as select2 } from "@inquirer/prompts";
|
|
1861
1990
|
import ora from "ora";
|
|
1862
|
-
import
|
|
1991
|
+
import chalk2 from "chalk";
|
|
1863
1992
|
import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
|
|
1864
1993
|
import { join as join9 } from "path";
|
|
1865
1994
|
|
|
@@ -2267,18 +2396,18 @@ async function listAllFiles(dir) {
|
|
|
2267
2396
|
function createEvalCommand() {
|
|
2268
2397
|
return new Command3("eval").description("Test your Claude Code config against eval scenarios").option("-s, --suite <suite>", "Eval suite to run (e.g., security, conventions, workflow)").option("-p, --path <path>", "Project root path", process.cwd()).option("--scenarios <path>", "Custom scenarios directory").option("--runs <n>", "Runs per scenario (default: 3)", "3").option("--timeout <ms>", "Timeout per run in ms (default: 120000)", "120000").option("--json", "Output as JSON").option("--debug", "Keep sandbox directories for inspection").option("--model <model>", "Model to use for eval (e.g., sonnet, haiku, opus)").action(async (opts) => {
|
|
2269
2398
|
printBanner();
|
|
2270
|
-
const hasFlags = opts.suite || opts.model || opts.runs !== "3" || opts.json || opts.debug;
|
|
2399
|
+
const hasFlags = opts.suite || opts.model || opts.runs !== "3" || opts.timeout !== "120000" || opts.path !== process.cwd() || Boolean(opts.scenarios) || opts.json || opts.debug;
|
|
2271
2400
|
if (!hasFlags) {
|
|
2272
|
-
opts.suite = await
|
|
2401
|
+
opts.suite = await select2({
|
|
2273
2402
|
message: "Suite",
|
|
2274
2403
|
choices: [
|
|
2275
2404
|
{ name: "security (6 scenarios)", value: "security" },
|
|
2276
2405
|
{ name: "conventions (5 scenarios)", value: "conventions" },
|
|
2277
|
-
{ name: "workflow (
|
|
2278
|
-
{ name: "all (
|
|
2406
|
+
{ name: "workflow (4 scenarios)", value: "workflow" },
|
|
2407
|
+
{ name: "all (15 scenarios)", value: void 0 }
|
|
2279
2408
|
]
|
|
2280
2409
|
});
|
|
2281
|
-
opts.runs = await
|
|
2410
|
+
opts.runs = await select2({
|
|
2282
2411
|
message: "Runs per scenario",
|
|
2283
2412
|
choices: [
|
|
2284
2413
|
{ name: "1 \u2014 fast", value: "1" },
|
|
@@ -2286,7 +2415,7 @@ function createEvalCommand() {
|
|
|
2286
2415
|
{ name: "5 \u2014 thorough", value: "5" }
|
|
2287
2416
|
]
|
|
2288
2417
|
});
|
|
2289
|
-
opts.model = await
|
|
2418
|
+
opts.model = await select2({
|
|
2290
2419
|
message: "Model",
|
|
2291
2420
|
choices: [
|
|
2292
2421
|
{ name: "haiku \u2014 cheapest", value: "haiku" },
|
|
@@ -2370,13 +2499,13 @@ function createEvalCommand() {
|
|
|
2370
2499
|
}
|
|
2371
2500
|
function renderEvalReport(results) {
|
|
2372
2501
|
for (const result of results) {
|
|
2373
|
-
const icon = result.passed ?
|
|
2374
|
-
const status = result.passed ?
|
|
2502
|
+
const icon = result.passed ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
2503
|
+
const status = result.passed ? chalk2.green("PASS") : chalk2.red("FAIL");
|
|
2375
2504
|
const score = `${result.score}/${result.maxScore}`;
|
|
2376
|
-
console.log(` ${icon} ${
|
|
2505
|
+
console.log(` ${icon} ${chalk2.bold(result.scenario)} ${score} ${status}`);
|
|
2377
2506
|
const failedChecks = result.checks.filter((c) => !c.passed);
|
|
2378
2507
|
for (const check of failedChecks) {
|
|
2379
|
-
console.log(` ${
|
|
2508
|
+
console.log(` ${chalk2.red("\u2717")} ${chalk2.dim(check.label)}`);
|
|
2380
2509
|
}
|
|
2381
2510
|
}
|
|
2382
2511
|
log.blank();
|
|
@@ -2444,9 +2573,9 @@ async function saveEvalReport(results, projectRoot, suite, model) {
|
|
|
2444
2573
|
log.success(`Report saved to .claude/eval/${filename}`);
|
|
2445
2574
|
}
|
|
2446
2575
|
async function checkClaudeCli() {
|
|
2447
|
-
const { execFile:
|
|
2448
|
-
const { promisify:
|
|
2449
|
-
const exec2 =
|
|
2576
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
2577
|
+
const { promisify: promisify2 } = await import("util");
|
|
2578
|
+
const exec2 = promisify2(execFile2);
|
|
2450
2579
|
try {
|
|
2451
2580
|
await exec2("claude", ["--version"]);
|
|
2452
2581
|
return true;
|
|
@@ -2455,82 +2584,88 @@ async function checkClaudeCli() {
|
|
|
2455
2584
|
}
|
|
2456
2585
|
}
|
|
2457
2586
|
|
|
2458
|
-
// src/commands/
|
|
2459
|
-
import {
|
|
2460
|
-
import { spawn, execFile as execFile2 } from "child_process";
|
|
2461
|
-
import { promisify as promisify2 } from "util";
|
|
2462
|
-
import { access as access7 } from "fs/promises";
|
|
2587
|
+
// src/commands/memory/index.ts
|
|
2588
|
+
import { readFileSync } from "fs";
|
|
2463
2589
|
import { join as join10 } from "path";
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
- If the project uses external APIs (Stripe, GitHub, AWS SDKs, etc.), suggest sandbox.network.allowedDomains to restrict outbound traffic
|
|
2492
|
-
- If you detect a monorepo (Turborepo, Lerna, pnpm workspaces, multiple package.json), suggest claudeMdExcludes in settings.json
|
|
2493
|
-
|
|
2494
|
-
Rules:
|
|
2495
|
-
- Don't remove existing content \u2014 only add or improve
|
|
2496
|
-
- Be specific to THIS project, not generic advice
|
|
2497
|
-
- Use bullet points, not paragraphs
|
|
2498
|
-
- If a section would exceed 8 bullets, split into a .claude/rules/ file and reference it
|
|
2499
|
-
- After editing, count the actionable lines. If over 120, move content to rules files until under`;
|
|
2500
|
-
function createEnhanceCommand() {
|
|
2501
|
-
return new Command4("enhance").description("Use Claude to analyze your codebase and complete CLAUDE.md").option("-p, --path <path>", "Project root path", process.cwd()).action(async (opts) => {
|
|
2502
|
-
printBanner();
|
|
2503
|
-
const root = opts.path;
|
|
2504
|
-
const claudeMdPath = join10(root, "CLAUDE.md");
|
|
2505
|
-
try {
|
|
2506
|
-
await access7(claudeMdPath);
|
|
2507
|
-
} catch {
|
|
2508
|
-
log.error("No CLAUDE.md found. Run `claude-launchpad init` first.");
|
|
2509
|
-
process.exit(1);
|
|
2590
|
+
import { Command as Command4 } from "commander";
|
|
2591
|
+
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
2592
|
+
function isMemoryInstalled() {
|
|
2593
|
+
try {
|
|
2594
|
+
const settingsPath = join10(process.cwd(), ".claude", "settings.json");
|
|
2595
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
2596
|
+
const hooks = settings.hooks;
|
|
2597
|
+
if (!hooks) return false;
|
|
2598
|
+
const sessionStart = hooks.SessionStart;
|
|
2599
|
+
return sessionStart?.some((h) => {
|
|
2600
|
+
const inner = h.hooks;
|
|
2601
|
+
return inner?.some((ih) => String(ih.command ?? "").includes("memory context"));
|
|
2602
|
+
}) ?? false;
|
|
2603
|
+
} catch {
|
|
2604
|
+
return false;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
function createMemoryCommand() {
|
|
2608
|
+
const memory = new Command4("memory").description("Persistent memory system for Claude Code sessions").option("--dashboard", "Open the memory dashboard").action(async (opts) => {
|
|
2609
|
+
if (opts.dashboard) {
|
|
2610
|
+
if (!isMemoryInstalled()) {
|
|
2611
|
+
log.error("Memory system is not installed. Run `claude-launchpad memory` first.");
|
|
2612
|
+
return;
|
|
2613
|
+
}
|
|
2614
|
+
const { startTui } = await import("./tui-R25NTQ4K.js");
|
|
2615
|
+
await startTui();
|
|
2616
|
+
return;
|
|
2510
2617
|
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
log.
|
|
2515
|
-
|
|
2618
|
+
if (!isMemoryInstalled()) {
|
|
2619
|
+
log.blank();
|
|
2620
|
+
log.step("Agentic memory is not set up for this project.");
|
|
2621
|
+
log.blank();
|
|
2622
|
+
log.info("This will (skipping what's already in place):");
|
|
2623
|
+
log.info(" - Set up SQLite database at ~/.agentic-memory/");
|
|
2624
|
+
log.info(" - Add SessionStart + Stop hooks to .claude/settings.json");
|
|
2625
|
+
log.info(" - Register the MCP server with Claude Code (global)");
|
|
2626
|
+
log.info(" - Add memory guidance to CLAUDE.md");
|
|
2627
|
+
log.blank();
|
|
2628
|
+
const proceed = await confirm2({
|
|
2629
|
+
message: "Install agentic-memory?",
|
|
2630
|
+
default: true
|
|
2631
|
+
});
|
|
2632
|
+
if (!proceed) {
|
|
2633
|
+
log.info("Skipped.");
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2636
|
+
const { runInstall } = await import("./install-65P6LMUN.js");
|
|
2637
|
+
await runInstall({});
|
|
2638
|
+
} else {
|
|
2639
|
+
const { runStats } = await import("./stats-FYAK7KZW.js");
|
|
2640
|
+
await runStats({});
|
|
2516
2641
|
}
|
|
2517
|
-
log.step("Launching Claude to enhance your CLAUDE.md...");
|
|
2518
|
-
log.blank();
|
|
2519
|
-
const child = spawn(
|
|
2520
|
-
"claude",
|
|
2521
|
-
[ENHANCE_PROMPT],
|
|
2522
|
-
{ cwd: root, stdio: "inherit" }
|
|
2523
|
-
);
|
|
2524
|
-
await new Promise((resolve3) => {
|
|
2525
|
-
child.on("close", (code) => resolve3(code ?? 0));
|
|
2526
|
-
});
|
|
2527
|
-
log.blank();
|
|
2528
|
-
log.success("Run `claude-launchpad doctor` to check your updated score.");
|
|
2529
2642
|
});
|
|
2643
|
+
memory.addCommand(
|
|
2644
|
+
new Command4("context").description("Load session context (hook handler)").option("--json", "JSON output").action(async (opts) => {
|
|
2645
|
+
const { runContext } = await import("./context-LNUZ4GCF.js");
|
|
2646
|
+
await runContext(opts);
|
|
2647
|
+
}).helpCommand(false),
|
|
2648
|
+
{ hidden: true }
|
|
2649
|
+
);
|
|
2650
|
+
memory.addCommand(
|
|
2651
|
+
new Command4("extract").description("Extract facts from transcript (hook handler)").action(async () => {
|
|
2652
|
+
const { runExtract } = await import("./extract-NVAXO5CK.js");
|
|
2653
|
+
await runExtract();
|
|
2654
|
+
}).helpCommand(false),
|
|
2655
|
+
{ hidden: true }
|
|
2656
|
+
);
|
|
2657
|
+
memory.addCommand(
|
|
2658
|
+
new Command4("serve").description("Start MCP server (Claude Code)").action(async () => {
|
|
2659
|
+
const { startServer } = await import("./commands/memory/server.js");
|
|
2660
|
+
await startServer();
|
|
2661
|
+
}).helpCommand(false),
|
|
2662
|
+
{ hidden: true }
|
|
2663
|
+
);
|
|
2664
|
+
return memory;
|
|
2530
2665
|
}
|
|
2531
2666
|
|
|
2532
2667
|
// src/cli.ts
|
|
2533
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2668
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.7.1", "-v, --version").action(async () => {
|
|
2534
2669
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2535
2670
|
if (hasConfig) {
|
|
2536
2671
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|
|
@@ -2540,13 +2675,14 @@ var program = new Command5().name("claude-launchpad").description("CLI toolkit t
|
|
|
2540
2675
|
log.blank();
|
|
2541
2676
|
log.step("Run `claude-launchpad init` to set up your project");
|
|
2542
2677
|
log.step("Run `claude-launchpad doctor` to diagnose an existing config");
|
|
2678
|
+
log.step("Use `/lp-enhance` skill inside Claude Code to AI-complete your CLAUDE.md");
|
|
2543
2679
|
log.step("Run `claude-launchpad eval` to test your config quality");
|
|
2544
2680
|
log.blank();
|
|
2545
2681
|
}
|
|
2546
2682
|
});
|
|
2547
2683
|
program.addCommand(createInitCommand());
|
|
2548
2684
|
program.addCommand(createDoctorCommand());
|
|
2549
|
-
program.addCommand(createEnhanceCommand());
|
|
2550
2685
|
program.addCommand(createEvalCommand());
|
|
2686
|
+
program.addCommand(createMemoryCommand());
|
|
2551
2687
|
program.parse();
|
|
2552
2688
|
//# sourceMappingURL=cli.js.map
|