code-session-memory 0.9.0 → 0.11.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.
Files changed (40) hide show
  1. package/README.md +56 -18
  2. package/dist/mcp/index.d.ts +1 -1
  3. package/dist/mcp/index.js +15 -13
  4. package/dist/mcp/index.js.map +1 -1
  5. package/dist/src/cli-query.d.ts +1 -0
  6. package/dist/src/cli-query.d.ts.map +1 -1
  7. package/dist/src/cli-query.js +8 -3
  8. package/dist/src/cli-query.js.map +1 -1
  9. package/dist/src/cli-sessions.d.ts.map +1 -1
  10. package/dist/src/cli-sessions.js +73 -0
  11. package/dist/src/cli-sessions.js.map +1 -1
  12. package/dist/src/cli.d.ts +1 -1
  13. package/dist/src/cli.js +332 -57
  14. package/dist/src/cli.js.map +1 -1
  15. package/dist/src/clipboard.d.ts +24 -0
  16. package/dist/src/clipboard.d.ts.map +1 -0
  17. package/dist/src/clipboard.js +48 -0
  18. package/dist/src/clipboard.js.map +1 -0
  19. package/dist/src/codex-session-to-messages.d.ts +22 -0
  20. package/dist/src/codex-session-to-messages.d.ts.map +1 -0
  21. package/dist/src/codex-session-to-messages.js +212 -0
  22. package/dist/src/codex-session-to-messages.js.map +1 -0
  23. package/dist/src/indexer-cli-codex.d.ts +12 -0
  24. package/dist/src/indexer-cli-codex.d.ts.map +1 -0
  25. package/dist/src/indexer-cli-codex.js +126 -0
  26. package/dist/src/indexer-cli-codex.js.map +1 -0
  27. package/dist/src/indexer.d.ts +1 -1
  28. package/dist/src/indexer.js +1 -1
  29. package/dist/src/restart-launchers.d.ts +37 -0
  30. package/dist/src/restart-launchers.d.ts.map +1 -0
  31. package/dist/src/restart-launchers.js +68 -0
  32. package/dist/src/restart-launchers.js.map +1 -0
  33. package/dist/src/session-compactor.d.ts +48 -0
  34. package/dist/src/session-compactor.d.ts.map +1 -0
  35. package/dist/src/session-compactor.js +203 -0
  36. package/dist/src/session-compactor.js.map +1 -0
  37. package/dist/src/types.d.ts +1 -1
  38. package/dist/src/types.d.ts.map +1 -1
  39. package/package.json +5 -3
  40. package/skill/memory.md +7 -4
package/dist/src/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * code-session-memory CLI
5
5
  *
6
6
  * Usage:
7
- * npx code-session-memory install — install for OpenCode + Claude Code
7
+ * npx code-session-memory install — install for all detected supported tools
8
8
  * npx code-session-memory status — show installation status
9
9
  * npx code-session-memory uninstall — remove all installed components
10
10
  * npx code-session-memory reset-db — wipe the database (with confirmation)
@@ -51,6 +51,7 @@ const fs_1 = __importDefault(require("fs"));
51
51
  const path_1 = __importDefault(require("path"));
52
52
  const os_1 = __importDefault(require("os"));
53
53
  const clack = __importStar(require("@clack/prompts"));
54
+ const smol_toml_1 = require("smol-toml");
54
55
  const database_1 = require("./database");
55
56
  const cli_sessions_1 = require("./cli-sessions");
56
57
  const cli_query_1 = require("./cli-query");
@@ -123,6 +124,9 @@ function getIndexerCliCursorPath() {
123
124
  function getIndexerCliVscodePath() {
124
125
  return path_1.default.join(getPackageRoot(), "dist", "src", "indexer-cli-vscode.js");
125
126
  }
127
+ function getIndexerCliCodexPath() {
128
+ return path_1.default.join(getPackageRoot(), "dist", "src", "indexer-cli-codex.js");
129
+ }
126
130
  // ---------------------------------------------------------------------------
127
131
  // Paths — Cursor
128
132
  // ---------------------------------------------------------------------------
@@ -167,6 +171,21 @@ function getVscodeHooksPath() {
167
171
  return path_1.default.join(getVscodeConfigDir(), "hooks", "code-session-memory.json");
168
172
  }
169
173
  // ---------------------------------------------------------------------------
174
+ // Paths — Codex
175
+ // ---------------------------------------------------------------------------
176
+ function getCodexConfigDir() {
177
+ const envDir = process.env.CODEX_HOME;
178
+ if (envDir)
179
+ return envDir;
180
+ return path_1.default.join(os_1.default.homedir(), ".codex");
181
+ }
182
+ function getCodexConfigPath() {
183
+ return path_1.default.join(getCodexConfigDir(), "config.toml");
184
+ }
185
+ function getCodexSkillDst() {
186
+ return path_1.default.join(getCodexConfigDir(), "skills", "code-session-memory", "SKILL.md");
187
+ }
188
+ // ---------------------------------------------------------------------------
170
189
  // Helpers
171
190
  // ---------------------------------------------------------------------------
172
191
  /**
@@ -652,7 +671,7 @@ function installCursorSkill(skillSrc) {
652
671
  const cursorFrontmatter = [
653
672
  "---",
654
673
  "name: code-session-memory",
655
- "description: Search past AI coding sessions semantically across OpenCode, Claude Code, and Cursor. Use this when the user asks about past work, decisions, or implementations.",
674
+ "description: Search past AI coding sessions semantically across OpenCode, Claude Code, Cursor, VS Code, and Codex. Use this when the user asks about past work, decisions, or implementations.",
656
675
  "---",
657
676
  "",
658
677
  ].join("\n");
@@ -891,6 +910,172 @@ function checkVscodeMcpConfigured() {
891
910
  }
892
911
  }
893
912
  // ---------------------------------------------------------------------------
913
+ // Codex — config.toml (TOML)
914
+ // ---------------------------------------------------------------------------
915
+ function parseCodexConfigOrEmpty(configPath) {
916
+ if (!fs_1.default.existsSync(configPath))
917
+ return {};
918
+ try {
919
+ return (0, smol_toml_1.parse)(fs_1.default.readFileSync(configPath, "utf8"));
920
+ }
921
+ catch {
922
+ throw new Error(`Could not parse existing ${configPath} — please check it is valid TOML.`);
923
+ }
924
+ }
925
+ function mergeCodexEnvVarsPassthrough(existing) {
926
+ const values = Array.isArray(existing)
927
+ ? existing.filter((v) => typeof v === "string" && v.trim().length > 0)
928
+ : [];
929
+ if (!values.includes("OPENAI_API_KEY"))
930
+ values.push("OPENAI_API_KEY");
931
+ return values;
932
+ }
933
+ function installCodexMcpConfig(mcpServerPath) {
934
+ const configPath = getCodexConfigPath();
935
+ const existed = fs_1.default.existsSync(configPath);
936
+ const config = parseCodexConfigOrEmpty(configPath);
937
+ const mcpServersRaw = config.mcp_servers;
938
+ const mcpServers = mcpServersRaw && typeof mcpServersRaw === "object"
939
+ ? mcpServersRaw
940
+ : {};
941
+ const existingServer = mcpServers["code-session-memory"];
942
+ const serverConfig = existingServer && typeof existingServer === "object"
943
+ ? existingServer
944
+ : {};
945
+ mcpServers["code-session-memory"] = {
946
+ ...serverConfig,
947
+ command: "node",
948
+ args: [mcpServerPath],
949
+ // Codex MCP servers run with a restricted environment by default.
950
+ // Pass-through env vars are configured via env_vars (env is a map of fixed values).
951
+ env_vars: mergeCodexEnvVarsPassthrough(serverConfig.env_vars),
952
+ };
953
+ config.mcp_servers = mcpServers;
954
+ ensureDir(path_1.default.dirname(configPath));
955
+ fs_1.default.writeFileSync(configPath, (0, smol_toml_1.stringify)(config) + "\n", "utf8");
956
+ return { configPath, existed };
957
+ }
958
+ function uninstallCodexMcpConfig() {
959
+ const configPath = getCodexConfigPath();
960
+ if (!fs_1.default.existsSync(configPath))
961
+ return "not_found";
962
+ try {
963
+ const config = (0, smol_toml_1.parse)(fs_1.default.readFileSync(configPath, "utf8"));
964
+ const mcpServers = config.mcp_servers;
965
+ if (!mcpServers || !(Object.prototype.hasOwnProperty.call(mcpServers, "code-session-memory"))) {
966
+ return "not_found";
967
+ }
968
+ delete mcpServers["code-session-memory"];
969
+ fs_1.default.writeFileSync(configPath, (0, smol_toml_1.stringify)(config) + "\n", "utf8");
970
+ return "done";
971
+ }
972
+ catch {
973
+ return "not_found";
974
+ }
975
+ }
976
+ function checkCodexMcpConfigured() {
977
+ const configPath = getCodexConfigPath();
978
+ try {
979
+ const config = (0, smol_toml_1.parse)(fs_1.default.readFileSync(configPath, "utf8"));
980
+ const mcpServers = config.mcp_servers;
981
+ return !!(mcpServers && Object.prototype.hasOwnProperty.call(mcpServers, "code-session-memory"));
982
+ }
983
+ catch {
984
+ return false;
985
+ }
986
+ }
987
+ function checkCodexOpenAiPassthroughConfigured() {
988
+ const configPath = getCodexConfigPath();
989
+ try {
990
+ const config = (0, smol_toml_1.parse)(fs_1.default.readFileSync(configPath, "utf8"));
991
+ const mcpServers = config.mcp_servers;
992
+ const server = mcpServers?.["code-session-memory"];
993
+ if (!server || typeof server !== "object")
994
+ return false;
995
+ const envVars = server.env_vars;
996
+ return Array.isArray(envVars) && envVars.includes("OPENAI_API_KEY");
997
+ }
998
+ catch {
999
+ return false;
1000
+ }
1001
+ }
1002
+ function installCodexHook(indexerCliCodexPath) {
1003
+ const configPath = getCodexConfigPath();
1004
+ const existed = fs_1.default.existsSync(configPath);
1005
+ const config = parseCodexConfigOrEmpty(configPath);
1006
+ config.notify = ["node", indexerCliCodexPath];
1007
+ ensureDir(path_1.default.dirname(configPath));
1008
+ fs_1.default.writeFileSync(configPath, (0, smol_toml_1.stringify)(config) + "\n", "utf8");
1009
+ return { configPath, existed };
1010
+ }
1011
+ function uninstallCodexHook() {
1012
+ const configPath = getCodexConfigPath();
1013
+ if (!fs_1.default.existsSync(configPath))
1014
+ return "not_found";
1015
+ try {
1016
+ const config = (0, smol_toml_1.parse)(fs_1.default.readFileSync(configPath, "utf8"));
1017
+ const notify = config.notify;
1018
+ if (!Array.isArray(notify))
1019
+ return "not_found";
1020
+ const hasOurHook = notify.some((v) => typeof v === "string" && v.includes("indexer-cli-codex"));
1021
+ if (!hasOurHook)
1022
+ return "not_found";
1023
+ delete config.notify;
1024
+ fs_1.default.writeFileSync(configPath, (0, smol_toml_1.stringify)(config) + "\n", "utf8");
1025
+ return "done";
1026
+ }
1027
+ catch {
1028
+ return "not_found";
1029
+ }
1030
+ }
1031
+ function checkCodexHookInstalled() {
1032
+ const configPath = getCodexConfigPath();
1033
+ try {
1034
+ const config = (0, smol_toml_1.parse)(fs_1.default.readFileSync(configPath, "utf8"));
1035
+ const notify = config.notify;
1036
+ if (!Array.isArray(notify))
1037
+ return false;
1038
+ return notify.some((v) => typeof v === "string" && v.includes("indexer-cli-codex"));
1039
+ }
1040
+ catch {
1041
+ return false;
1042
+ }
1043
+ }
1044
+ function installCodexSkill(skillSrc) {
1045
+ const dstPath = getCodexSkillDst();
1046
+ const existed = fs_1.default.existsSync(dstPath);
1047
+ if (!fs_1.default.existsSync(skillSrc)) {
1048
+ throw new Error(`Skill source not found: ${skillSrc}\nDid you run "npm run build" first?`);
1049
+ }
1050
+ const skillBody = fs_1.default.readFileSync(skillSrc, "utf8");
1051
+ const bodyWithoutFrontmatter = skillBody
1052
+ .replace(/^---[\s\S]*?---\s*\n?/, "")
1053
+ .trimStart();
1054
+ const codexFrontmatter = [
1055
+ "---",
1056
+ "name: code-session-memory",
1057
+ "description: Search past AI coding sessions semantically across OpenCode, Claude Code, Cursor, VS Code, and Codex.",
1058
+ "---",
1059
+ "",
1060
+ ].join("\n");
1061
+ ensureDir(path_1.default.dirname(dstPath));
1062
+ fs_1.default.writeFileSync(dstPath, codexFrontmatter + bodyWithoutFrontmatter, "utf8");
1063
+ return { dstPath, existed };
1064
+ }
1065
+ function uninstallCodexSkill() {
1066
+ const dstPath = getCodexSkillDst();
1067
+ if (!fs_1.default.existsSync(dstPath))
1068
+ return "not_found";
1069
+ fs_1.default.unlinkSync(dstPath);
1070
+ try {
1071
+ const dir = path_1.default.dirname(dstPath);
1072
+ if (fs_1.default.readdirSync(dir).length === 0)
1073
+ fs_1.default.rmdirSync(dir);
1074
+ }
1075
+ catch { /* ignore */ }
1076
+ return "done";
1077
+ }
1078
+ // ---------------------------------------------------------------------------
894
1079
  // Formatting helpers
895
1080
  // ---------------------------------------------------------------------------
896
1081
  function bold(s) { return `\x1b[1m${s}\x1b[0m`; }
@@ -898,6 +1083,24 @@ function green(s) { return `\x1b[32m${s}\x1b[0m`; }
898
1083
  function red(s) { return `\x1b[31m${s}\x1b[0m`; }
899
1084
  function dim(s) { return `\x1b[2m${s}\x1b[0m`; }
900
1085
  function ok(v) { return v ? green("✓") : red("✗"); }
1086
+ // ---------------------------------------------------------------------------
1087
+ // Tool detection
1088
+ // ---------------------------------------------------------------------------
1089
+ function isOpenCodeInstalled() {
1090
+ return fs_1.default.existsSync(getOpenCodeConfigDir());
1091
+ }
1092
+ function isClaudeCodeInstalled() {
1093
+ return fs_1.default.existsSync(getClaudeConfigDir());
1094
+ }
1095
+ function isCursorInstalled() {
1096
+ return fs_1.default.existsSync(getCursorConfigDir());
1097
+ }
1098
+ function isVscodeInstalled() {
1099
+ return fs_1.default.existsSync(getVscodeConfigDir());
1100
+ }
1101
+ function isCodexInstalled() {
1102
+ return fs_1.default.existsSync(getCodexConfigDir());
1103
+ }
901
1104
  function step(label, fn) {
902
1105
  process.stdout.write(` ${label}... `);
903
1106
  try {
@@ -910,6 +1113,13 @@ function step(label, fn) {
910
1113
  process.exit(1);
911
1114
  }
912
1115
  }
1116
+ function stepIf(condition, label, fn) {
1117
+ if (!condition) {
1118
+ console.log(` ${dim("○")} ${dim(label)} ${dim("(tool not detected — skipped)")}`);
1119
+ return;
1120
+ }
1121
+ step(label, fn);
1122
+ }
913
1123
  // ---------------------------------------------------------------------------
914
1124
  // Commands
915
1125
  // ---------------------------------------------------------------------------
@@ -920,6 +1130,12 @@ function install() {
920
1130
  const indexerClaudePath = getIndexerCliClaudePath();
921
1131
  const indexerCursorPath = getIndexerCliCursorPath();
922
1132
  const indexerVscodePath = getIndexerCliVscodePath();
1133
+ const indexerCodexPath = getIndexerCliCodexPath();
1134
+ const openCodeInstalled = isOpenCodeInstalled();
1135
+ const claudeInstalled = isClaudeCodeInstalled();
1136
+ const cursorInstalled = isCursorInstalled();
1137
+ const vscodeInstalled = isVscodeInstalled();
1138
+ const codexInstalled = isCodexInstalled();
923
1139
  // 1. DB
924
1140
  step("Initialising database", () => {
925
1141
  ensureDir(path_1.default.dirname(dbPath));
@@ -927,68 +1143,73 @@ function install() {
927
1143
  db.close();
928
1144
  return dbPath;
929
1145
  });
930
- // 2. OpenCode plugin
931
- step("Installing OpenCode plugin", () => {
1146
+ // OpenCode
1147
+ stepIf(openCodeInstalled, "Installing OpenCode plugin", () => {
932
1148
  const dst = getOpenCodePluginDst();
933
1149
  installOpenCodePlugin(getPluginSrc(), dst);
934
1150
  return dst;
935
1151
  });
936
- // 3. OpenCode skill
937
- step("Installing OpenCode skill", () => {
1152
+ stepIf(openCodeInstalled, "Installing OpenCode skill", () => {
938
1153
  const dst = getOpenCodeSkillDst();
939
1154
  copyFile(getSkillSrc(), dst);
940
1155
  return dst;
941
1156
  });
942
- // 4. OpenCode MCP config
943
- step("Configuring OpenCode MCP server", () => {
1157
+ stepIf(openCodeInstalled, "Configuring OpenCode MCP server", () => {
944
1158
  const { configPath, existed } = installOpenCodeMcpConfig(mcpPath);
945
1159
  return `${existed ? "updated" : "created"} ${configPath}`;
946
1160
  });
947
- // 5. Claude Code MCP config
948
- step("Configuring Claude Code MCP server", () => {
1161
+ // Claude Code
1162
+ stepIf(claudeInstalled, "Configuring Claude Code MCP server", () => {
949
1163
  const { configPath, existed } = installClaudeMcpConfig(mcpPath);
950
1164
  return `${existed ? "updated" : "created"} ${configPath}`;
951
1165
  });
952
- // 6. Claude Code hook
953
- step("Installing Claude Code Stop hook", () => {
1166
+ stepIf(claudeInstalled, "Installing Claude Code Stop hook", () => {
954
1167
  const { settingsPath, existed } = installClaudeHook(indexerClaudePath);
955
1168
  return `${existed ? "updated" : "created"} ${settingsPath}`;
956
1169
  });
957
- // 7. Claude Code CLAUDE.md
958
- step("Installing Claude Code context (CLAUDE.md)", () => {
1170
+ stepIf(claudeInstalled, "Installing Claude Code context (CLAUDE.md)", () => {
959
1171
  const { mdPath, existed } = installClaudeMd(getSkillSrc());
960
1172
  return `${existed ? "updated" : "created"} ${mdPath}`;
961
1173
  });
962
- // 8. Cursor MCP config
963
- step("Configuring Cursor MCP server", () => {
1174
+ // Cursor
1175
+ stepIf(cursorInstalled, "Configuring Cursor MCP server", () => {
964
1176
  const { configPath, existed } = installCursorMcpConfig(mcpPath);
965
1177
  return `${existed ? "updated" : "created"} ${configPath}`;
966
1178
  });
967
- // 9. Cursor stop hook
968
- step("Installing Cursor stop hook", () => {
1179
+ stepIf(cursorInstalled, "Installing Cursor stop hook", () => {
969
1180
  const { hooksPath, existed } = installCursorHook(indexerCursorPath);
970
1181
  return `${existed ? "updated" : "created"} ${hooksPath}`;
971
1182
  });
972
- // 10. Cursor skill
973
- step("Installing Cursor skill", () => {
1183
+ stepIf(cursorInstalled, "Installing Cursor skill", () => {
974
1184
  const { dstPath, existed } = installCursorSkill(getSkillSrc());
975
1185
  return `${existed ? "updated" : "created"} ${dstPath}`;
976
1186
  });
977
- // 11. VS Code MCP config
978
- step("Configuring VS Code MCP server", () => {
1187
+ // VS Code
1188
+ stepIf(vscodeInstalled, "Configuring VS Code MCP server", () => {
979
1189
  const { configPath, existed } = installVscodeMcpConfig(mcpPath);
980
1190
  return `${existed ? "updated" : "created"} ${configPath}`;
981
1191
  });
982
- // 12. VS Code Stop hook
983
- step("Installing VS Code Stop hook", () => {
1192
+ stepIf(vscodeInstalled, "Installing VS Code Stop hook", () => {
984
1193
  const { hooksPath, existed } = installVscodeHook(indexerVscodePath);
985
1194
  return `${existed ? "updated" : "created"} ${hooksPath}`;
986
1195
  });
987
- // 13. VS Code hook location registration
988
- step("Registering VS Code hook location", () => {
1196
+ stepIf(vscodeInstalled, "Registering VS Code hook location", () => {
989
1197
  const { settingsPath, existed } = installVscodeHookLocation();
990
1198
  return `${existed ? "updated" : "created"} ${settingsPath}`;
991
1199
  });
1200
+ // Codex
1201
+ stepIf(codexInstalled, "Configuring Codex MCP server", () => {
1202
+ const { configPath, existed } = installCodexMcpConfig(mcpPath);
1203
+ return `${existed ? "updated" : "created"} ${configPath}`;
1204
+ });
1205
+ stepIf(codexInstalled, "Installing Codex notify hook", () => {
1206
+ const { configPath, existed } = installCodexHook(indexerCodexPath);
1207
+ return `${existed ? "updated" : "created"} ${configPath}`;
1208
+ });
1209
+ stepIf(codexInstalled, "Installing Codex skill", () => {
1210
+ const { dstPath, existed } = installCodexSkill(getSkillSrc());
1211
+ return `${existed ? "updated" : "created"} ${dstPath}`;
1212
+ });
992
1213
  console.log(`
993
1214
  ${bold("Installation complete!")}
994
1215
 
@@ -997,9 +1218,10 @@ ${bold("Required environment variable:")}
997
1218
 
998
1219
  ${bold("Default DB path:")} ${dbPath}
999
1220
 
1000
- Restart ${bold("OpenCode")}, ${bold("Claude Code")}, ${bold("Cursor")}, and ${bold("VS Code")} to activate.
1221
+ Restart ${bold("OpenCode")}, ${bold("Claude Code")}, ${bold("Cursor")}, ${bold("VS Code")}, and ${bold("Codex")} to activate.
1001
1222
 
1002
1223
  ${bold("VS Code note:")} Ensure ${bold("Chat: Use Hooks")} is enabled in VS Code settings.
1224
+ ${bold("Codex note:")} The notify hook and OPENAI_API_KEY passthrough are set in ${dim(getCodexConfigPath())}.
1003
1225
  Run ${bold("npx code-session-memory status")} to verify.
1004
1226
  `);
1005
1227
  }
@@ -1007,22 +1229,57 @@ function status() {
1007
1229
  console.log(bold("\ncode-session-memory status\n"));
1008
1230
  const dbPath = (0, database_1.resolveDbPath)();
1009
1231
  const mcpPath = getMcpServerPath();
1010
- console.log(bold(" OpenCode"));
1011
- console.log(` ${ok(fs_1.default.existsSync(getOpenCodePluginDst()))} Plugin ${dim(getOpenCodePluginDst())}`);
1012
- console.log(` ${ok(fs_1.default.existsSync(getOpenCodeSkillDst()))} Skill ${dim(getOpenCodeSkillDst())}`);
1013
- console.log(` ${ok(checkMcpConfigured())} MCP config ${dim(getGlobalOpenCodeConfigPath())}`);
1014
- console.log(bold("\n Claude Code"));
1015
- console.log(` ${ok(checkClaudeMcpConfigured())} MCP config ${dim(getClaudeUserConfigPath())}`);
1016
- console.log(` ${ok(checkClaudeHookInstalled())} Stop hook ${dim(getClaudeSettingsPath())}`);
1017
- console.log(` ${ok(checkClaudeMdInstalled())} CLAUDE.md ${dim(getClaudeMdPath())}`);
1018
- console.log(bold("\n Cursor"));
1019
- console.log(` ${ok(checkCursorMcpConfigured())} MCP config ${dim(getCursorMcpConfigPath())}`);
1020
- console.log(` ${ok(checkCursorHookInstalled())} Stop hook ${dim(getCursorHooksPath())}`);
1021
- console.log(` ${ok(fs_1.default.existsSync(getCursorSkillDst()))} Skill ${dim(getCursorSkillDst())}`);
1022
- console.log(bold("\n VS Code"));
1023
- console.log(` ${ok(checkVscodeMcpConfigured())} MCP config ${dim(getVscodeMcpConfigPath())}`);
1024
- console.log(` ${ok(checkVscodeHookInstalled())} Stop hook ${dim(getVscodeHooksPath())}`);
1025
- console.log(` ${ok(checkVscodeHookLocationRegistered())} Hook loc ${dim(getVscodeSettingsPath())}`);
1232
+ const openCodeInstalled = isOpenCodeInstalled();
1233
+ const claudeInstalled = isClaudeCodeInstalled();
1234
+ const cursorInstalled = isCursorInstalled();
1235
+ const vscodeInstalled = isVscodeInstalled();
1236
+ const codexInstalled = isCodexInstalled();
1237
+ if (openCodeInstalled) {
1238
+ console.log(bold(" OpenCode"));
1239
+ console.log(` ${ok(fs_1.default.existsSync(getOpenCodePluginDst()))} Plugin ${dim(getOpenCodePluginDst())}`);
1240
+ console.log(` ${ok(fs_1.default.existsSync(getOpenCodeSkillDst()))} Skill ${dim(getOpenCodeSkillDst())}`);
1241
+ console.log(` ${ok(checkMcpConfigured())} MCP config ${dim(getGlobalOpenCodeConfigPath())}`);
1242
+ }
1243
+ else {
1244
+ console.log(bold(" OpenCode") + dim(" (not installed — skipped)"));
1245
+ }
1246
+ if (claudeInstalled) {
1247
+ console.log(bold("\n Claude Code"));
1248
+ console.log(` ${ok(checkClaudeMcpConfigured())} MCP config ${dim(getClaudeUserConfigPath())}`);
1249
+ console.log(` ${ok(checkClaudeHookInstalled())} Stop hook ${dim(getClaudeSettingsPath())}`);
1250
+ console.log(` ${ok(checkClaudeMdInstalled())} CLAUDE.md ${dim(getClaudeMdPath())}`);
1251
+ }
1252
+ else {
1253
+ console.log(bold("\n Claude Code") + dim(" (not installed — skipped)"));
1254
+ }
1255
+ if (cursorInstalled) {
1256
+ console.log(bold("\n Cursor"));
1257
+ console.log(` ${ok(checkCursorMcpConfigured())} MCP config ${dim(getCursorMcpConfigPath())}`);
1258
+ console.log(` ${ok(checkCursorHookInstalled())} Stop hook ${dim(getCursorHooksPath())}`);
1259
+ console.log(` ${ok(fs_1.default.existsSync(getCursorSkillDst()))} Skill ${dim(getCursorSkillDst())}`);
1260
+ }
1261
+ else {
1262
+ console.log(bold("\n Cursor") + dim(" (not installed — skipped)"));
1263
+ }
1264
+ if (vscodeInstalled) {
1265
+ console.log(bold("\n VS Code"));
1266
+ console.log(` ${ok(checkVscodeMcpConfigured())} MCP config ${dim(getVscodeMcpConfigPath())}`);
1267
+ console.log(` ${ok(checkVscodeHookInstalled())} Stop hook ${dim(getVscodeHooksPath())}`);
1268
+ console.log(` ${ok(checkVscodeHookLocationRegistered())} Hook loc ${dim(getVscodeSettingsPath())}`);
1269
+ }
1270
+ else {
1271
+ console.log(bold("\n VS Code") + dim(" (not installed — skipped)"));
1272
+ }
1273
+ if (codexInstalled) {
1274
+ console.log(bold("\n Codex"));
1275
+ console.log(` ${ok(checkCodexMcpConfigured())} MCP config ${dim(getCodexConfigPath())}`);
1276
+ console.log(` ${ok(checkCodexOpenAiPassthroughConfigured())} OPENAI_KEY ${dim(getCodexConfigPath())}`);
1277
+ console.log(` ${ok(checkCodexHookInstalled())} Notify hook ${dim(getCodexConfigPath())}`);
1278
+ console.log(` ${ok(fs_1.default.existsSync(getCodexSkillDst()))} Skill ${dim(getCodexSkillDst())}`);
1279
+ }
1280
+ else {
1281
+ console.log(bold("\n Codex") + dim(" (not installed — skipped)"));
1282
+ }
1026
1283
  console.log(bold("\n Shared"));
1027
1284
  console.log(` ${ok(fs_1.default.existsSync(mcpPath))} MCP server ${dim(mcpPath)}`);
1028
1285
  console.log(` ${ok(fs_1.default.existsSync(dbPath))} Database ${dim(dbPath)}`);
@@ -1046,18 +1303,22 @@ function status() {
1046
1303
  }
1047
1304
  catch { /* DB might be empty */ }
1048
1305
  }
1049
- const allOk = fs_1.default.existsSync(getOpenCodePluginDst()) &&
1306
+ const allOk = (!openCodeInstalled || (fs_1.default.existsSync(getOpenCodePluginDst()) &&
1050
1307
  fs_1.default.existsSync(getOpenCodeSkillDst()) &&
1051
- checkMcpConfigured() &&
1052
- checkClaudeMcpConfigured() &&
1053
- checkClaudeHookInstalled() &&
1054
- checkClaudeMdInstalled() &&
1055
- checkCursorMcpConfigured() &&
1056
- checkCursorHookInstalled() &&
1057
- fs_1.default.existsSync(getCursorSkillDst()) &&
1058
- checkVscodeMcpConfigured() &&
1059
- checkVscodeHookInstalled() &&
1060
- checkVscodeHookLocationRegistered() &&
1308
+ checkMcpConfigured())) &&
1309
+ (!claudeInstalled || (checkClaudeMcpConfigured() &&
1310
+ checkClaudeHookInstalled() &&
1311
+ checkClaudeMdInstalled())) &&
1312
+ (!cursorInstalled || (checkCursorMcpConfigured() &&
1313
+ checkCursorHookInstalled() &&
1314
+ fs_1.default.existsSync(getCursorSkillDst()))) &&
1315
+ (!vscodeInstalled || (checkVscodeMcpConfigured() &&
1316
+ checkVscodeHookInstalled() &&
1317
+ checkVscodeHookLocationRegistered())) &&
1318
+ (!codexInstalled || (checkCodexMcpConfigured() &&
1319
+ checkCodexOpenAiPassthroughConfigured() &&
1320
+ checkCodexHookInstalled() &&
1321
+ fs_1.default.existsSync(getCodexSkillDst()))) &&
1061
1322
  fs_1.default.existsSync(mcpPath) &&
1062
1323
  fs_1.default.existsSync(dbPath);
1063
1324
  console.log(`\n ${allOk
@@ -1121,6 +1382,18 @@ function uninstall() {
1121
1382
  if (uninstallVscodeHookLocation() === "not_found")
1122
1383
  throw new Error("not found");
1123
1384
  }],
1385
+ ["Codex MCP config", () => {
1386
+ if (uninstallCodexMcpConfig() === "not_found")
1387
+ throw new Error("not found");
1388
+ }],
1389
+ ["Codex notify hook", () => {
1390
+ if (uninstallCodexHook() === "not_found")
1391
+ throw new Error("not found");
1392
+ }],
1393
+ ["Codex skill", () => {
1394
+ if (uninstallCodexSkill() === "not_found")
1395
+ throw new Error("not found");
1396
+ }],
1124
1397
  ];
1125
1398
  for (const [label, fn] of items) {
1126
1399
  process.stdout.write(` Removing ${label}... `);
@@ -1175,15 +1448,15 @@ async function resetDb() {
1175
1448
  }
1176
1449
  function help() {
1177
1450
  console.log(`
1178
- ${bold("code-session-memory")} — Shared vector memory for OpenCode, Claude Code, and Cursor sessions
1451
+ ${bold("code-session-memory")} — Shared vector memory for OpenCode, Claude Code, Cursor, VS Code, and Codex sessions
1179
1452
 
1180
1453
  ${bold("Usage:")}
1181
- npx code-session-memory install Install all components (OpenCode + Claude Code + Cursor)
1454
+ npx code-session-memory install Install components for detected tools
1182
1455
  npx code-session-memory status Show installation status and DB stats
1183
1456
  npx code-session-memory uninstall Remove all installed components (keeps DB)
1184
1457
  npx code-session-memory reset-db Delete all indexed data (keeps installation)
1185
1458
  npx code-session-memory query <text> Semantic search across all indexed sessions
1186
- npx code-session-memory query <text> --source <s> Filter by source (opencode, claude-code, cursor)
1459
+ npx code-session-memory query <text> --source <s> Filter by source (opencode, claude-code, cursor, vscode, codex)
1187
1460
  npx code-session-memory query <text> --limit <n> Max results (default: 5)
1188
1461
  npx code-session-memory query <text> --from <date> Results from date (e.g. 2026-02-01)
1189
1462
  npx code-session-memory query <text> --to <date> Results up to date (e.g. 2026-02-20)
@@ -1200,6 +1473,8 @@ ${bold("Environment variables:")}
1200
1473
  OPENCODE_CONFIG_DIR Override the OpenCode config directory
1201
1474
  CLAUDE_CONFIG_DIR Override the Claude Code config directory
1202
1475
  CURSOR_CONFIG_DIR Override the Cursor config directory (~/.cursor)
1476
+ VSCODE_CONFIG_DIR Override the VS Code config directory
1477
+ CODEX_HOME Override the Codex home directory (~/.codex)
1203
1478
  `);
1204
1479
  }
1205
1480
  // ---------------------------------------------------------------------------