claude-launchpad 0.14.3 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/chunk-KOSJII4R.js +62 -0
- package/dist/chunk-KOSJII4R.js.map +1 -0
- package/dist/cli.js +84 -39
- package/dist/cli.js.map +1 -1
- package/dist/{install-4GQ57KCQ.js → install-U6WARER4.js} +46 -20
- package/dist/install-U6WARER4.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-CSLWJEGD.js +0 -25
- package/dist/chunk-CSLWJEGD.js.map +0 -1
- package/dist/install-4GQ57KCQ.js.map +0 -1
package/README.md
CHANGED
|
@@ -201,6 +201,13 @@ 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
|
+
During setup, you choose where memory config lives:
|
|
205
|
+
|
|
206
|
+
- **Shared** (default) — config goes to `CLAUDE.md` + `settings.json` (committed, team sees it)
|
|
207
|
+
- **Local** — config goes to `.claude/CLAUDE.md` + `settings.local.json` (gitignored, only you)
|
|
208
|
+
|
|
209
|
+
Use "local" when co-devs have different memory setups (e.g. you use agentic-memory, they use built-in). Your choice is persisted so `doctor --fix` won't re-ask.
|
|
210
|
+
|
|
204
211
|
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
212
|
|
|
206
213
|
Browse everything with `--dashboard` -- a terminal UI with vim navigation, filtering, and search.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/settings.ts
|
|
4
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
async function readSettingsJson(root) {
|
|
7
|
+
const path = join(root, ".claude", "settings.json");
|
|
8
|
+
try {
|
|
9
|
+
const content = await readFile(path, "utf-8");
|
|
10
|
+
return JSON.parse(content);
|
|
11
|
+
} catch {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function writeSettingsJson(root, settings) {
|
|
16
|
+
const dir = join(root, ".claude");
|
|
17
|
+
await mkdir(dir, { recursive: true });
|
|
18
|
+
await writeFile(join(dir, "settings.json"), JSON.stringify(settings, null, 2) + "\n");
|
|
19
|
+
}
|
|
20
|
+
async function readSettingsLocalJson(root) {
|
|
21
|
+
const path = join(root, ".claude", "settings.local.json");
|
|
22
|
+
try {
|
|
23
|
+
const content = await readFile(path, "utf-8");
|
|
24
|
+
return JSON.parse(content);
|
|
25
|
+
} catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function writeSettingsLocalJson(root, settings) {
|
|
30
|
+
const dir = join(root, ".claude");
|
|
31
|
+
await mkdir(dir, { recursive: true });
|
|
32
|
+
await writeFile(join(dir, "settings.local.json"), JSON.stringify(settings, null, 2) + "\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/lib/memory-placement.ts
|
|
36
|
+
import { select } from "@inquirer/prompts";
|
|
37
|
+
async function getMemoryPlacement(root, skipPrompt = false) {
|
|
38
|
+
const local = await readSettingsLocalJson(root);
|
|
39
|
+
const persisted = local.memoryPlacement;
|
|
40
|
+
if (persisted === "shared" || persisted === "local") {
|
|
41
|
+
return persisted;
|
|
42
|
+
}
|
|
43
|
+
if (skipPrompt) return "shared";
|
|
44
|
+
const choice = await select({
|
|
45
|
+
message: "Where should memory config go?",
|
|
46
|
+
choices: [
|
|
47
|
+
{ value: "shared", name: "Shared (team sees it) \u2014 CLAUDE.md + settings.json" },
|
|
48
|
+
{ value: "local", name: "Local (only you) \u2014 .claude/CLAUDE.md + settings.local.json" }
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
await writeSettingsLocalJson(root, { ...local, memoryPlacement: choice });
|
|
52
|
+
return choice;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
readSettingsJson,
|
|
57
|
+
writeSettingsJson,
|
|
58
|
+
readSettingsLocalJson,
|
|
59
|
+
writeSettingsLocalJson,
|
|
60
|
+
getMemoryPlacement
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=chunk-KOSJII4R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/settings.ts","../src/lib/memory-placement.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport async function readSettingsJson(root: string): Promise<Record<string, unknown>> {\n const path = join(root, \".claude\", \"settings.json\");\n try {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nexport async function writeSettingsJson(root: string, settings: Record<string, unknown>): Promise<void> {\n const dir = join(root, \".claude\");\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, \"settings.json\"), JSON.stringify(settings, null, 2) + \"\\n\");\n}\n\nexport async function readSettingsLocalJson(root: string): Promise<Record<string, unknown>> {\n const path = join(root, \".claude\", \"settings.local.json\");\n try {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nexport async function writeSettingsLocalJson(root: string, settings: Record<string, unknown>): Promise<void> {\n const dir = join(root, \".claude\");\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, \"settings.local.json\"), JSON.stringify(settings, null, 2) + \"\\n\");\n}\n","import { select } from \"@inquirer/prompts\";\nimport { readSettingsLocalJson, writeSettingsLocalJson } from \"./settings.js\";\nimport type { MemoryPlacement } from \"../types/index.js\";\n\nexport async function getMemoryPlacement(root: string, skipPrompt = false): Promise<MemoryPlacement> {\n const local = await readSettingsLocalJson(root);\n const persisted = local.memoryPlacement;\n if (persisted === \"shared\" || persisted === \"local\") {\n return persisted;\n }\n\n if (skipPrompt) return \"shared\";\n\n const choice = await select<MemoryPlacement>({\n message: \"Where should memory config go?\",\n choices: [\n { value: \"shared\", name: \"Shared (team sees it) — CLAUDE.md + settings.json\" },\n { value: \"local\", name: \"Local (only you) — .claude/CLAUDE.md + settings.local.json\" },\n ],\n });\n\n await writeSettingsLocalJson(root, { ...local, memoryPlacement: choice });\n return choice;\n}\n"],"mappings":";;;AAAA,SAAS,UAAU,WAAW,aAAa;AAC3C,SAAS,YAAY;AAErB,eAAsB,iBAAiB,MAAgD;AACrF,QAAM,OAAO,KAAK,MAAM,WAAW,eAAe;AAClD,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,MAAM,OAAO;AAC5C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,kBAAkB,MAAc,UAAkD;AACtG,QAAM,MAAM,KAAK,MAAM,SAAS;AAChC,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,QAAM,UAAU,KAAK,KAAK,eAAe,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,IAAI;AACtF;AAEA,eAAsB,sBAAsB,MAAgD;AAC1F,QAAM,OAAO,KAAK,MAAM,WAAW,qBAAqB;AACxD,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,MAAM,OAAO;AAC5C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,uBAAuB,MAAc,UAAkD;AAC3G,QAAM,MAAM,KAAK,MAAM,SAAS;AAChC,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,QAAM,UAAU,KAAK,KAAK,qBAAqB,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,IAAI;AAC5F;;;ACjCA,SAAS,cAAc;AAIvB,eAAsB,mBAAmB,MAAc,aAAa,OAAiC;AACnG,QAAM,QAAQ,MAAM,sBAAsB,IAAI;AAC9C,QAAM,YAAY,MAAM;AACxB,MAAI,cAAc,YAAY,cAAc,SAAS;AACnD,WAAO;AAAA,EACT;AAEA,MAAI,WAAY,QAAO;AAEvB,QAAM,SAAS,MAAM,OAAwB;AAAA,IAC3C,SAAS;AAAA,IACT,SAAS;AAAA,MACP,EAAE,OAAO,UAAU,MAAM,yDAAoD;AAAA,MAC7E,EAAE,OAAO,SAAS,MAAM,kEAA6D;AAAA,IACvF;AAAA,EACF,CAAC;AAED,QAAM,uBAAuB,MAAM,EAAE,GAAG,OAAO,iBAAiB,OAAO,CAAC;AACxE,SAAO;AACT;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
getMemoryPlacement,
|
|
3
4
|
readSettingsJson,
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
readSettingsLocalJson,
|
|
6
|
+
writeSettingsJson,
|
|
7
|
+
writeSettingsLocalJson
|
|
8
|
+
} from "./chunk-KOSJII4R.js";
|
|
6
9
|
import {
|
|
7
10
|
log,
|
|
8
11
|
printBanner,
|
|
@@ -824,6 +827,7 @@ async function scaffold(root, options, detected, skipPrompts) {
|
|
|
824
827
|
if (!hasClaudeGitignore) {
|
|
825
828
|
writes.push(writeFile(claudeGitignorePath, [
|
|
826
829
|
"# Local-only Claude Code files (never commit these)",
|
|
830
|
+
"CLAUDE.md",
|
|
827
831
|
"settings.local.json",
|
|
828
832
|
"plans/",
|
|
829
833
|
"memory/",
|
|
@@ -942,13 +946,16 @@ import { join as join3, resolve } from "path";
|
|
|
942
946
|
var CLAUDE_MD = "CLAUDE.md";
|
|
943
947
|
var CLAUDE_DIR = ".claude";
|
|
944
948
|
var SETTINGS_FILE = "settings.json";
|
|
949
|
+
var SETTINGS_LOCAL_FILE = "settings.local.json";
|
|
945
950
|
var RULES_DIR = "rules";
|
|
946
951
|
async function parseClaudeConfig(projectRoot) {
|
|
947
952
|
const root = resolve(projectRoot);
|
|
948
953
|
const claudeDir = join3(root, CLAUDE_DIR);
|
|
949
|
-
const [claudeMd, settings, hooks, rules, mcpServers, skills, claudeignore] = await Promise.all([
|
|
954
|
+
const [claudeMd, localClaudeMd, settings, localSettings, hooks, rules, mcpServers, skills, claudeignore] = await Promise.all([
|
|
950
955
|
readClaudeMd(root),
|
|
956
|
+
readFileOrNull(join3(claudeDir, CLAUDE_MD)),
|
|
951
957
|
readSettings(claudeDir),
|
|
958
|
+
readSettingsFromFile(claudeDir, SETTINGS_LOCAL_FILE),
|
|
952
959
|
readHooks(claudeDir),
|
|
953
960
|
readRules(claudeDir),
|
|
954
961
|
readMcpServers(claudeDir),
|
|
@@ -962,6 +969,8 @@ async function parseClaudeConfig(projectRoot) {
|
|
|
962
969
|
claudeMdInstructionCount: instructionCount,
|
|
963
970
|
settingsPath: settings !== null ? join3(claudeDir, SETTINGS_FILE) : null,
|
|
964
971
|
settings,
|
|
972
|
+
localClaudeMdContent: localClaudeMd,
|
|
973
|
+
localSettings,
|
|
965
974
|
hooks,
|
|
966
975
|
rules,
|
|
967
976
|
mcpServers,
|
|
@@ -987,7 +996,10 @@ function countInstructions(content) {
|
|
|
987
996
|
return count;
|
|
988
997
|
}
|
|
989
998
|
async function readSettings(claudeDir) {
|
|
990
|
-
|
|
999
|
+
return readSettingsFromFile(claudeDir, SETTINGS_FILE);
|
|
1000
|
+
}
|
|
1001
|
+
async function readSettingsFromFile(claudeDir, filename) {
|
|
1002
|
+
const raw = await readFileOrNull(join3(claudeDir, filename));
|
|
991
1003
|
if (raw === null) return null;
|
|
992
1004
|
try {
|
|
993
1005
|
return JSON.parse(raw);
|
|
@@ -1567,16 +1579,16 @@ async function analyzeMemory(config) {
|
|
|
1567
1579
|
fix: "Run `doctor --fix` to remove the stale Stop hook"
|
|
1568
1580
|
});
|
|
1569
1581
|
}
|
|
1570
|
-
const autoMemoryDisabled = config.settings?.autoMemoryEnabled === false;
|
|
1582
|
+
const autoMemoryDisabled = config.settings?.autoMemoryEnabled === false || config.localSettings?.autoMemoryEnabled === false;
|
|
1571
1583
|
if (!autoMemoryDisabled) {
|
|
1572
1584
|
issues.push({
|
|
1573
1585
|
analyzer: "Memory",
|
|
1574
1586
|
severity: "medium",
|
|
1575
1587
|
message: "autoMemoryEnabled not disabled \u2014 built-in memory may conflict with agentic-memory",
|
|
1576
|
-
fix: "Set autoMemoryEnabled: false in .
|
|
1588
|
+
fix: "Set autoMemoryEnabled: false in settings.json or settings.local.json"
|
|
1577
1589
|
});
|
|
1578
1590
|
}
|
|
1579
|
-
const hasMemoryGuidance = config.claudeMdContent?.includes("agentic-memory") || config.claudeMdContent?.includes("## Memory");
|
|
1591
|
+
const hasMemoryGuidance = config.claudeMdContent?.includes("agentic-memory") || config.claudeMdContent?.includes("## Memory") || config.localClaudeMdContent?.includes("agentic-memory") || config.localClaudeMdContent?.includes("## Memory");
|
|
1580
1592
|
if (!hasMemoryGuidance) {
|
|
1581
1593
|
issues.push({
|
|
1582
1594
|
analyzer: "Memory",
|
|
@@ -1586,7 +1598,11 @@ async function analyzeMemory(config) {
|
|
|
1586
1598
|
});
|
|
1587
1599
|
}
|
|
1588
1600
|
const permissions = config.settings?.permissions ?? {};
|
|
1589
|
-
const
|
|
1601
|
+
const localPermissions = config.localSettings?.permissions ?? {};
|
|
1602
|
+
const allowList = [
|
|
1603
|
+
...permissions.allow ?? [],
|
|
1604
|
+
...localPermissions.allow ?? []
|
|
1605
|
+
];
|
|
1590
1606
|
const missingTools = MEMORY_MCP_TOOLS.filter((t) => !allowList.includes(t));
|
|
1591
1607
|
if (missingTools.length > 0) {
|
|
1592
1608
|
issues.push({
|
|
@@ -1639,9 +1655,10 @@ async function analyzeQuality(config) {
|
|
|
1639
1655
|
return { name: "CLAUDE.md Quality", issues, score: 0 };
|
|
1640
1656
|
}
|
|
1641
1657
|
const sections = hasMemoryIndicators(config) ? [...BASE_SECTIONS, MEMORY_SECTION] : [...BASE_SECTIONS];
|
|
1658
|
+
const combinedContent = [content, config.localClaudeMdContent].filter(Boolean).join("\n");
|
|
1642
1659
|
let sectionsFound = 0;
|
|
1643
1660
|
for (const section of sections) {
|
|
1644
|
-
if (section.pattern.test(
|
|
1661
|
+
if (section.pattern.test(combinedContent)) {
|
|
1645
1662
|
sectionsFound++;
|
|
1646
1663
|
} else {
|
|
1647
1664
|
issues.push({
|
|
@@ -1695,10 +1712,12 @@ import { join as join5 } from "path";
|
|
|
1695
1712
|
import { homedir as homedir3 } from "os";
|
|
1696
1713
|
async function applyFixes(issues, projectRoot) {
|
|
1697
1714
|
const detected = await detectProject(projectRoot);
|
|
1715
|
+
const hasMemoryIssues = issues.some((i) => i.analyzer === "Memory");
|
|
1716
|
+
const placement = hasMemoryIssues ? await getMemoryPlacement(projectRoot) : "shared";
|
|
1698
1717
|
let fixed = 0;
|
|
1699
1718
|
let skipped = 0;
|
|
1700
1719
|
for (const issue of issues) {
|
|
1701
|
-
const applied = await tryFix(issue, projectRoot, detected);
|
|
1720
|
+
const applied = await tryFix(issue, projectRoot, detected, placement);
|
|
1702
1721
|
if (applied) {
|
|
1703
1722
|
fixed++;
|
|
1704
1723
|
} else {
|
|
@@ -1742,15 +1761,19 @@ var FIX_TABLE = [
|
|
|
1742
1761
|
{ analyzer: "Settings", match: "Deprecated includeCoAuthoredBy", fix: (root) => migrateAttribution(root) },
|
|
1743
1762
|
{ analyzer: "Hooks", match: "SessionStart", fix: (root) => addSessionStartHook(root) },
|
|
1744
1763
|
{ analyzer: "Memory", match: "Deprecated Stop hook", fix: (root) => removeStaleStopHook(root) },
|
|
1745
|
-
{ analyzer: "Memory", match: "autoMemoryEnabled not disabled", fix: (root) => disableAutoMemory(root) },
|
|
1746
|
-
{ analyzer: "Memory", match: "MCP tool permission", fix: (root) => addMemoryToolPermissions(root) },
|
|
1747
|
-
{ analyzer: "Memory", match: "CLAUDE.md missing memory guidance", fix: (root
|
|
1764
|
+
{ analyzer: "Memory", match: "autoMemoryEnabled not disabled", fix: (root, _det, placement) => disableAutoMemory(root, placement) },
|
|
1765
|
+
{ analyzer: "Memory", match: "MCP tool permission", fix: (root, _det, placement) => addMemoryToolPermissions(root, placement) },
|
|
1766
|
+
{ analyzer: "Memory", match: "CLAUDE.md missing memory guidance", fix: (root, _det, placement) => {
|
|
1767
|
+
const content = "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";
|
|
1768
|
+
const target = placement === "local" ? join5(root, ".claude", "CLAUDE.md") : void 0;
|
|
1769
|
+
return addClaudeMdSection(root, "## Memory", content, target);
|
|
1770
|
+
} }
|
|
1748
1771
|
];
|
|
1749
|
-
async function tryFix(issue, root, detected) {
|
|
1772
|
+
async function tryFix(issue, root, detected, placement) {
|
|
1750
1773
|
const entry = FIX_TABLE.find(
|
|
1751
1774
|
(e) => e.analyzer === issue.analyzer && issue.message.includes(e.match)
|
|
1752
1775
|
);
|
|
1753
|
-
return entry ? entry.fix(root, detected) : false;
|
|
1776
|
+
return entry ? entry.fix(root, detected, placement) : false;
|
|
1754
1777
|
}
|
|
1755
1778
|
async function addHook(root, event, dedupKeyword, entry, successMsg) {
|
|
1756
1779
|
const settings = await readSettingsJson(root);
|
|
@@ -1877,13 +1900,15 @@ async function addEnvToClaudeignore(root) {
|
|
|
1877
1900
|
log.success("Added .env to .claudeignore");
|
|
1878
1901
|
return true;
|
|
1879
1902
|
}
|
|
1880
|
-
async function addClaudeMdSection(root, heading, content) {
|
|
1881
|
-
const claudeMdPath = join5(root, "CLAUDE.md");
|
|
1903
|
+
async function addClaudeMdSection(root, heading, content, targetPath) {
|
|
1904
|
+
const claudeMdPath = targetPath ?? join5(root, "CLAUDE.md");
|
|
1882
1905
|
let existing;
|
|
1883
1906
|
try {
|
|
1884
1907
|
existing = await readFile4(claudeMdPath, "utf-8");
|
|
1885
1908
|
} catch {
|
|
1886
|
-
return false;
|
|
1909
|
+
if (!targetPath) return false;
|
|
1910
|
+
await mkdir2(join5(root, ".claude"), { recursive: true });
|
|
1911
|
+
existing = "# Local Claude Config\n";
|
|
1887
1912
|
}
|
|
1888
1913
|
if (existing.includes(heading)) return false;
|
|
1889
1914
|
const keyDecisionsIdx = existing.indexOf("## Key Decisions");
|
|
@@ -1895,7 +1920,8 @@ ${content}
|
|
|
1895
1920
|
`;
|
|
1896
1921
|
const updated = existing.slice(0, insertAt) + section + existing.slice(insertAt);
|
|
1897
1922
|
await writeFile2(claudeMdPath, updated);
|
|
1898
|
-
|
|
1923
|
+
const label = targetPath ? ".claude/CLAUDE.md" : "CLAUDE.md";
|
|
1924
|
+
log.success(`Added "${heading}" section to ${label}`);
|
|
1899
1925
|
return true;
|
|
1900
1926
|
}
|
|
1901
1927
|
async function createBacklogMd(root) {
|
|
@@ -1947,16 +1973,21 @@ async function createStarterRules(root) {
|
|
|
1947
1973
|
log.success("Created .claude/rules/conventions.md with starter rules");
|
|
1948
1974
|
return true;
|
|
1949
1975
|
}
|
|
1950
|
-
async function disableAutoMemory(root) {
|
|
1951
|
-
const
|
|
1976
|
+
async function disableAutoMemory(root, placement) {
|
|
1977
|
+
const read = placement === "local" ? readSettingsLocalJson : readSettingsJson;
|
|
1978
|
+
const write = placement === "local" ? writeSettingsLocalJson : writeSettingsJson;
|
|
1979
|
+
const settings = await read(root);
|
|
1952
1980
|
if (settings.autoMemoryEnabled === false) return false;
|
|
1953
1981
|
settings.autoMemoryEnabled = false;
|
|
1954
|
-
await
|
|
1955
|
-
|
|
1982
|
+
await write(root, settings);
|
|
1983
|
+
const target = placement === "local" ? "settings.local.json" : "settings.json";
|
|
1984
|
+
log.success(`Set autoMemoryEnabled: false in ${target}`);
|
|
1956
1985
|
return true;
|
|
1957
1986
|
}
|
|
1958
|
-
async function addMemoryToolPermissions(root) {
|
|
1959
|
-
const
|
|
1987
|
+
async function addMemoryToolPermissions(root, placement) {
|
|
1988
|
+
const read = placement === "local" ? readSettingsLocalJson : readSettingsJson;
|
|
1989
|
+
const write = placement === "local" ? writeSettingsLocalJson : writeSettingsJson;
|
|
1990
|
+
const settings = await read(root);
|
|
1960
1991
|
const permissions = settings.permissions ?? {};
|
|
1961
1992
|
const allow = permissions.allow ?? [];
|
|
1962
1993
|
const tools = [
|
|
@@ -1971,8 +2002,9 @@ async function addMemoryToolPermissions(root) {
|
|
|
1971
2002
|
const missing = tools.filter((t) => !allow.includes(t));
|
|
1972
2003
|
if (missing.length === 0) return false;
|
|
1973
2004
|
settings.permissions = { ...permissions, allow: [...allow, ...missing] };
|
|
1974
|
-
await
|
|
1975
|
-
|
|
2005
|
+
await write(root, settings);
|
|
2006
|
+
const target = placement === "local" ? "settings.local.json" : "settings.json";
|
|
2007
|
+
log.success(`Added agentic-memory MCP tool permissions to ${target}`);
|
|
1976
2008
|
return true;
|
|
1977
2009
|
}
|
|
1978
2010
|
async function createEnhanceSkill(root) {
|
|
@@ -2780,9 +2812,12 @@ import { join as join10 } from "path";
|
|
|
2780
2812
|
import { Command as Command4 } from "commander";
|
|
2781
2813
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
2782
2814
|
function isMemoryInstalled() {
|
|
2815
|
+
const cwd = process.cwd();
|
|
2816
|
+
return hasMemoryHook(join10(cwd, ".claude", "settings.json")) || hasMemoryHook(join10(cwd, ".claude", "settings.local.json"));
|
|
2817
|
+
}
|
|
2818
|
+
function hasMemoryHook(path) {
|
|
2783
2819
|
try {
|
|
2784
|
-
const
|
|
2785
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
2820
|
+
const settings = JSON.parse(readFileSync(path, "utf-8"));
|
|
2786
2821
|
const hooks = settings.hooks;
|
|
2787
2822
|
if (!hooks) return false;
|
|
2788
2823
|
const sessionStart = hooks.SessionStart;
|
|
@@ -2808,14 +2843,24 @@ function createMemoryCommand() {
|
|
|
2808
2843
|
return;
|
|
2809
2844
|
}
|
|
2810
2845
|
if (!isMemoryInstalled()) {
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2846
|
+
const { detectExistingSetup } = await import("./install-U6WARER4.js");
|
|
2847
|
+
const existing = detectExistingSetup(process.cwd());
|
|
2848
|
+
if (existing) {
|
|
2849
|
+
const location = existing === "local" ? ".claude/CLAUDE.md + settings.local.json" : "CLAUDE.md + settings.json";
|
|
2850
|
+
log.blank();
|
|
2851
|
+
log.success(`Memory config found (${location}) but database not set up.`);
|
|
2852
|
+
log.info("Run the install to complete setup.");
|
|
2853
|
+
log.blank();
|
|
2854
|
+
} else {
|
|
2855
|
+
log.blank();
|
|
2856
|
+
log.step("Claude doesn't have a knowledge base for this project yet.");
|
|
2857
|
+
log.blank();
|
|
2858
|
+
log.info("After setup, Claude will:");
|
|
2859
|
+
log.info(" - Remember decisions, gotchas, and learnings across sessions");
|
|
2860
|
+
log.info(" - Automatically recall relevant context when you start a session");
|
|
2861
|
+
log.info(" - Save important facts as you work, so nothing gets lost");
|
|
2862
|
+
log.blank();
|
|
2863
|
+
}
|
|
2819
2864
|
const proceed = await confirm2({
|
|
2820
2865
|
message: "Set up knowledge base?",
|
|
2821
2866
|
default: true
|
|
@@ -2824,7 +2869,7 @@ function createMemoryCommand() {
|
|
|
2824
2869
|
log.info("Skipped.");
|
|
2825
2870
|
return;
|
|
2826
2871
|
}
|
|
2827
|
-
const { runInstall } = await import("./install-
|
|
2872
|
+
const { runInstall } = await import("./install-U6WARER4.js");
|
|
2828
2873
|
await runInstall({});
|
|
2829
2874
|
} else {
|
|
2830
2875
|
const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
|
|
@@ -2863,7 +2908,7 @@ function createMemoryCommand() {
|
|
|
2863
2908
|
}
|
|
2864
2909
|
|
|
2865
2910
|
// src/cli.ts
|
|
2866
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2911
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.15.0", "-v, --version").action(async () => {
|
|
2867
2912
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2868
2913
|
if (hasConfig) {
|
|
2869
2914
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|