@bennys001/claude-code-memory 0.9.12 → 0.11.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.
Files changed (2) hide show
  1. package/dist/index.js +210 -69
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  var package_default = {
5
5
  name: "@bennys001/claude-code-memory",
6
6
  publishConfig: { access: "public" },
7
- version: "0.9.12",
7
+ version: "0.11.1",
8
8
  description: "MCP server that gives Claude Code persistent memory via an Obsidian knowledge vault",
9
9
  module: "dist/index.js",
10
10
  main: "dist/index.js",
@@ -866,6 +866,107 @@ function registerResearchTool(server, entries, vaultPath) {
866
866
  });
867
867
  }
868
868
 
869
+ // src/cli/claude-code.ts
870
+ import { spawn } from "child_process";
871
+ var SERVER_CMD = ["ccm", "--stdio"];
872
+ function installGlobal() {
873
+ return new Promise((resolve4) => {
874
+ let stderr = "";
875
+ const proc = spawn("bun", ["install", "-g", "@bennys001/claude-code-memory"], { stdio: ["ignore", "ignore", "pipe"] });
876
+ proc.stderr.on("data", (data) => {
877
+ stderr += data.toString();
878
+ });
879
+ proc.on("error", (err) => {
880
+ resolve4({ success: false, error: err.message });
881
+ });
882
+ proc.on("close", (code) => {
883
+ if (code === 0) {
884
+ resolve4({ success: true });
885
+ } else {
886
+ resolve4({ success: false, error: stderr.trim() || `bun install exited with code ${code}` });
887
+ }
888
+ });
889
+ });
890
+ }
891
+ function uninstallGlobal() {
892
+ return new Promise((resolve4) => {
893
+ let stderr = "";
894
+ const proc = spawn("bun", ["remove", "-g", "@bennys001/claude-code-memory"], { stdio: ["ignore", "ignore", "pipe"] });
895
+ proc.stderr.on("data", (data) => {
896
+ stderr += data.toString();
897
+ });
898
+ proc.on("error", (err) => {
899
+ resolve4({ success: false, error: err.message });
900
+ });
901
+ proc.on("close", (code) => {
902
+ if (code === 0) {
903
+ resolve4({ success: true });
904
+ } else {
905
+ resolve4({ success: false, error: stderr.trim() || `bun remove exited with code ${code}` });
906
+ }
907
+ });
908
+ });
909
+ }
910
+ var REGISTER_ARGS = [
911
+ "mcp",
912
+ "add",
913
+ "--transport",
914
+ "stdio",
915
+ "--scope",
916
+ "user",
917
+ "ccm",
918
+ "--",
919
+ ...SERVER_CMD
920
+ ];
921
+ var MANUAL_COMMAND = `claude mcp add --transport stdio --scope user ccm -- ${SERVER_CMD.join(" ")}`;
922
+ function removeMcpServer() {
923
+ return new Promise((resolve4) => {
924
+ const proc = spawn("claude", ["mcp", "remove", "ccm"], { stdio: "ignore" });
925
+ proc.on("error", () => resolve4());
926
+ proc.on("close", () => resolve4());
927
+ });
928
+ }
929
+ async function registerMcpServer() {
930
+ await removeMcpServer();
931
+ return new Promise((resolve4) => {
932
+ let stdout = "";
933
+ let stderr = "";
934
+ const proc = spawn("claude", REGISTER_ARGS, { stdio: "pipe" });
935
+ proc.stdout.on("data", (data) => {
936
+ stdout += data.toString();
937
+ });
938
+ proc.stderr.on("data", (data) => {
939
+ stderr += data.toString();
940
+ });
941
+ proc.on("error", (err) => {
942
+ if (err.code === "ENOENT") {
943
+ resolve4({
944
+ success: false,
945
+ error: "Claude CLI not found in PATH",
946
+ manualCommand: MANUAL_COMMAND
947
+ });
948
+ } else {
949
+ resolve4({
950
+ success: false,
951
+ error: err.message,
952
+ manualCommand: MANUAL_COMMAND
953
+ });
954
+ }
955
+ });
956
+ proc.on("close", (code) => {
957
+ if (code === 0) {
958
+ resolve4({ success: true, output: (stdout || stderr).trim() });
959
+ } else {
960
+ resolve4({
961
+ success: false,
962
+ error: (stderr || stdout).trim() || `Process exited with code ${code}`,
963
+ manualCommand: MANUAL_COMMAND
964
+ });
965
+ }
966
+ });
967
+ });
968
+ }
969
+
869
970
  // src/cli/init.ts
870
971
  import { mkdir as mkdir2 } from "fs/promises";
871
972
  import { join as join6 } from "path";
@@ -1027,72 +1128,17 @@ async function registerVaultWithObsidian(vaultPath, configPath = DEFAULT_CONFIG_
1027
1128
  await writeFile2(configPath, JSON.stringify(config, null, 2));
1028
1129
  return { registered: true, vaultId };
1029
1130
  }
1030
-
1031
- // src/cli/claude-code.ts
1032
- import { spawn } from "child_process";
1033
- import { resolve as resolvePath } from "path";
1034
- function buildServerCommand() {
1035
- const runtime = resolvePath(process.argv[0]);
1036
- const script = resolvePath(process.argv[1]);
1037
- return [runtime, script, "--stdio"];
1038
- }
1039
- function buildRegisterArgs(serverCmd) {
1040
- return [
1041
- "mcp",
1042
- "add",
1043
- "--transport",
1044
- "stdio",
1045
- "--scope",
1046
- "user",
1047
- "ccm",
1048
- "--",
1049
- ...serverCmd
1050
- ];
1051
- }
1052
- function formatManualCommand(serverCmd) {
1053
- return `claude mcp add --transport stdio --scope user ccm -- ${serverCmd.join(" ")}`;
1054
- }
1055
- function registerMcpServer() {
1056
- const serverCmd = buildServerCommand();
1057
- const registerArgs = buildRegisterArgs(serverCmd);
1058
- const manualCommand = formatManualCommand(serverCmd);
1059
- return new Promise((resolve4) => {
1060
- let stdout = "";
1061
- let stderr = "";
1062
- const proc = spawn("claude", registerArgs, { stdio: "pipe" });
1063
- proc.stdout.on("data", (data) => {
1064
- stdout += data.toString();
1065
- });
1066
- proc.stderr.on("data", (data) => {
1067
- stderr += data.toString();
1068
- });
1069
- proc.on("error", (err) => {
1070
- if (err.code === "ENOENT") {
1071
- resolve4({
1072
- success: false,
1073
- error: "Claude CLI not found in PATH",
1074
- manualCommand
1075
- });
1076
- } else {
1077
- resolve4({
1078
- success: false,
1079
- error: err.message,
1080
- manualCommand
1081
- });
1082
- }
1083
- });
1084
- proc.on("close", (code) => {
1085
- if (code === 0) {
1086
- resolve4({ success: true, output: (stdout || stderr).trim() });
1087
- } else {
1088
- resolve4({
1089
- success: false,
1090
- error: (stderr || stdout).trim() || `Process exited with code ${code}`,
1091
- manualCommand
1092
- });
1093
- }
1094
- });
1095
- });
1131
+ async function unregisterVaultFromObsidian(vaultPath, configPath = DEFAULT_CONFIG_PATH) {
1132
+ const config = await loadObsidianConfig(configPath);
1133
+ if (!config)
1134
+ return false;
1135
+ const vaultId = findVaultByPath(config, vaultPath);
1136
+ if (!vaultId)
1137
+ return false;
1138
+ await copyFile(configPath, `${configPath}.backup`);
1139
+ delete config.vaults[vaultId];
1140
+ await writeFile2(configPath, JSON.stringify(config, null, 2));
1141
+ return true;
1096
1142
  }
1097
1143
 
1098
1144
  // src/cli/init.ts
@@ -1135,6 +1181,12 @@ async function executeInit() {
1135
1181
  detail: obsidianResult.reason
1136
1182
  });
1137
1183
  }
1184
+ const installResult = await installGlobal();
1185
+ if (installResult.success) {
1186
+ steps.push({ name: "global install", status: "created", detail: "ccm binary installed" });
1187
+ } else {
1188
+ steps.push({ name: "global install", status: "failed", detail: installResult.error });
1189
+ }
1138
1190
  const mcpResult = await registerMcpServer();
1139
1191
  if (mcpResult.success) {
1140
1192
  steps.push({ name: "Claude Code MCP", status: "created", detail: mcpResult.output });
@@ -1178,24 +1230,100 @@ function formatInitSummary(result) {
1178
1230
  }
1179
1231
 
1180
1232
  // src/index.ts
1233
+ import { rm } from "fs/promises";
1234
+ import { createInterface } from "readline";
1181
1235
  var VAULT_PATH2 = join7(homedir4(), ".ccm", "knowledge-base");
1182
1236
  function parseCliArgs() {
1183
1237
  const args = process.argv.slice(2);
1238
+ if (args.includes("--version") || args.includes("-v"))
1239
+ return "version";
1240
+ if (args.includes("--update"))
1241
+ return "update";
1242
+ if (args.includes("--uninstall"))
1243
+ return "uninstall";
1184
1244
  if (args.includes("--init"))
1185
1245
  return "init";
1186
1246
  if (args.includes("--stdio"))
1187
1247
  return "serve";
1248
+ if (!process.stdin.isTTY)
1249
+ return "serve";
1188
1250
  return "help";
1189
1251
  }
1190
1252
  function printHelp() {
1191
1253
  console.log(`${C.bold}claude-code-memory${C.reset} ${C.dim}(ccm)${C.reset} \u2014 Persistent memory for Claude Code
1192
1254
 
1193
1255
  ${C.bold}Usage:${C.reset}
1194
- ${C.cyan}bunx @bennys001/claude-code-memory --init${C.reset}
1256
+ ${C.cyan}ccm --init${C.reset} Set up vault and register MCP server
1257
+ ${C.cyan}ccm --update${C.reset} Update to the latest version
1258
+ ${C.cyan}ccm --uninstall${C.reset} Remove ccm, MCP server, and optionally the vault
1259
+ ${C.cyan}ccm --version${C.reset} Show installed version
1260
+
1261
+ ${C.bold}First-time install:${C.reset}
1262
+ ${C.cyan}bun install -g @bennys001/claude-code-memory && ccm --init${C.reset}
1195
1263
 
1196
1264
  ${C.dim}Vault:${C.reset} ~/.ccm/knowledge-base/
1197
1265
  ${C.dim}Docs:${C.reset} https://github.com/bennys001/claude-code-memory`);
1198
1266
  }
1267
+ async function fetchLatestVersion() {
1268
+ const res = await fetch("https://registry.npmjs.org/@bennys001/claude-code-memory/latest");
1269
+ if (!res.ok)
1270
+ throw new Error(`npm registry returned ${res.status}`);
1271
+ const data = await res.json();
1272
+ return data.version;
1273
+ }
1274
+ async function runUpdate() {
1275
+ console.log(`${C.dim}Checking for updates...${C.reset}`);
1276
+ const latest = await fetchLatestVersion();
1277
+ if (latest === package_default.version) {
1278
+ console.log(`Already on the latest version: ${C.green}v${package_default.version}${C.reset}`);
1279
+ return;
1280
+ }
1281
+ console.log(`${C.dim}v${package_default.version}${C.reset} \u2192 ${C.green}v${latest}${C.reset}
1282
+ `);
1283
+ const installResult = await installGlobal();
1284
+ if (!installResult.success) {
1285
+ throw new Error(`Global install failed: ${installResult.error}`);
1286
+ }
1287
+ const mcpResult = await registerMcpServer();
1288
+ if (!mcpResult.success) {
1289
+ throw new Error(`MCP registration failed: ${mcpResult.error}`);
1290
+ }
1291
+ console.log(`
1292
+ ${C.green}Updated to v${latest}${C.reset}`);
1293
+ }
1294
+ function promptConfirm(question) {
1295
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1296
+ return new Promise((resolve4) => {
1297
+ rl.question(question, (answer) => {
1298
+ rl.close();
1299
+ resolve4(answer.toLowerCase() === "y");
1300
+ });
1301
+ });
1302
+ }
1303
+ async function runUninstall() {
1304
+ console.log(`${C.bold}ccm uninstall${C.reset}
1305
+ `);
1306
+ await removeMcpServer();
1307
+ console.log(` ${C.green}+${C.reset} Removed MCP server`);
1308
+ await unregisterVaultFromObsidian(VAULT_PATH);
1309
+ console.log(` ${C.green}+${C.reset} Unregistered Obsidian vault`);
1310
+ const ccmDir = join7(homedir4(), ".ccm");
1311
+ const deleteVault = await promptConfirm(` Delete vault at ${C.dim}${VAULT_PATH}${C.reset}? ${C.dim}(y/N)${C.reset} `);
1312
+ if (deleteVault) {
1313
+ await rm(ccmDir, { recursive: true, force: true });
1314
+ console.log(` ${C.green}+${C.reset} Deleted vault`);
1315
+ } else {
1316
+ console.log(` ${C.yellow}-${C.reset} Kept vault`);
1317
+ }
1318
+ const uninstallResult = await uninstallGlobal();
1319
+ if (uninstallResult.success) {
1320
+ console.log(` ${C.green}+${C.reset} Uninstalled ccm binary`);
1321
+ } else {
1322
+ console.log(` ${C.red}!${C.reset} Failed to uninstall: ${uninstallResult.error}`);
1323
+ }
1324
+ console.log(`
1325
+ ${C.green}Done${C.reset}`);
1326
+ }
1199
1327
  async function runInit() {
1200
1328
  const result = await executeInit();
1201
1329
  console.log(formatInitSummary(result));
@@ -1226,9 +1354,22 @@ async function runServer() {
1226
1354
  process.on("SIGTERM", shutdown);
1227
1355
  }
1228
1356
  var cli = parseCliArgs();
1229
- if (cli === "help") {
1357
+ if (cli === "version") {
1358
+ console.log(package_default.version);
1359
+ process.exit(0);
1360
+ } else if (cli === "help") {
1230
1361
  printHelp();
1231
1362
  process.exit(0);
1363
+ } else if (cli === "update") {
1364
+ runUpdate().catch((err) => {
1365
+ console.error("Fatal:", err);
1366
+ process.exit(1);
1367
+ });
1368
+ } else if (cli === "uninstall") {
1369
+ runUninstall().catch((err) => {
1370
+ console.error("Fatal:", err);
1371
+ process.exit(1);
1372
+ });
1232
1373
  } else if (cli === "init") {
1233
1374
  runInit().catch((err) => {
1234
1375
  console.error("Fatal:", err);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bennys001/claude-code-memory",
3
3
  "publishConfig": { "access": "public" },
4
- "version": "0.9.12",
4
+ "version": "0.11.1",
5
5
  "description": "MCP server that gives Claude Code persistent memory via an Obsidian knowledge vault",
6
6
  "module": "dist/index.js",
7
7
  "main": "dist/index.js",