code-session-memory 0.8.1 → 0.10.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 +59 -17
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +15 -13
- package/dist/mcp/index.js.map +1 -1
- package/dist/src/cli-query.d.ts +1 -0
- package/dist/src/cli-query.d.ts.map +1 -1
- package/dist/src/cli-query.js +8 -3
- package/dist/src/cli-query.js.map +1 -1
- package/dist/src/cli-sessions.d.ts.map +1 -1
- package/dist/src/cli-sessions.js +8 -0
- package/dist/src/cli-sessions.js.map +1 -1
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.js +608 -44
- package/dist/src/cli.js.map +1 -1
- package/dist/src/codex-session-to-messages.d.ts +22 -0
- package/dist/src/codex-session-to-messages.d.ts.map +1 -0
- package/dist/src/codex-session-to-messages.js +212 -0
- package/dist/src/codex-session-to-messages.js.map +1 -0
- package/dist/src/indexer-cli-codex.d.ts +12 -0
- package/dist/src/indexer-cli-codex.d.ts.map +1 -0
- package/dist/src/indexer-cli-codex.js +126 -0
- package/dist/src/indexer-cli-codex.js.map +1 -0
- package/dist/src/indexer-cli-vscode.d.ts +14 -0
- package/dist/src/indexer-cli-vscode.d.ts.map +1 -0
- package/dist/src/indexer-cli-vscode.js +88 -0
- package/dist/src/indexer-cli-vscode.js.map +1 -0
- package/dist/src/indexer.d.ts +1 -1
- package/dist/src/indexer.js +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/vscode-transcript-to-messages.d.ts +41 -0
- package/dist/src/vscode-transcript-to-messages.d.ts.map +1 -0
- package/dist/src/vscode-transcript-to-messages.js +167 -0
- package/dist/src/vscode-transcript-to-messages.js.map +1 -0
- package/package.json +6 -3
- package/skill/memory.md +10 -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
|
|
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");
|
|
@@ -120,6 +121,12 @@ function getIndexerCliClaudePath() {
|
|
|
120
121
|
function getIndexerCliCursorPath() {
|
|
121
122
|
return path_1.default.join(getPackageRoot(), "dist", "src", "indexer-cli-cursor.js");
|
|
122
123
|
}
|
|
124
|
+
function getIndexerCliVscodePath() {
|
|
125
|
+
return path_1.default.join(getPackageRoot(), "dist", "src", "indexer-cli-vscode.js");
|
|
126
|
+
}
|
|
127
|
+
function getIndexerCliCodexPath() {
|
|
128
|
+
return path_1.default.join(getPackageRoot(), "dist", "src", "indexer-cli-codex.js");
|
|
129
|
+
}
|
|
123
130
|
// ---------------------------------------------------------------------------
|
|
124
131
|
// Paths — Cursor
|
|
125
132
|
// ---------------------------------------------------------------------------
|
|
@@ -142,8 +149,59 @@ function getCursorSkillDst() {
|
|
|
142
149
|
return path_1.default.join(getCursorConfigDir(), "skills", "code-session-memory", "SKILL.md");
|
|
143
150
|
}
|
|
144
151
|
// ---------------------------------------------------------------------------
|
|
152
|
+
// Paths — VS Code
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
function getVscodeConfigDir() {
|
|
155
|
+
const envDir = process.env.VSCODE_CONFIG_DIR;
|
|
156
|
+
if (envDir)
|
|
157
|
+
return envDir;
|
|
158
|
+
if (process.platform === "darwin") {
|
|
159
|
+
return path_1.default.join(os_1.default.homedir(), "Library", "Application Support", "Code", "User");
|
|
160
|
+
}
|
|
161
|
+
// Linux (and fallback)
|
|
162
|
+
return path_1.default.join(os_1.default.homedir(), ".config", "Code", "User");
|
|
163
|
+
}
|
|
164
|
+
function getVscodeSettingsPath() {
|
|
165
|
+
return path_1.default.join(getVscodeConfigDir(), "settings.json");
|
|
166
|
+
}
|
|
167
|
+
function getVscodeMcpConfigPath() {
|
|
168
|
+
return path_1.default.join(getVscodeConfigDir(), "mcp.json");
|
|
169
|
+
}
|
|
170
|
+
function getVscodeHooksPath() {
|
|
171
|
+
return path_1.default.join(getVscodeConfigDir(), "hooks", "code-session-memory.json");
|
|
172
|
+
}
|
|
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
|
+
// ---------------------------------------------------------------------------
|
|
145
189
|
// Helpers
|
|
146
190
|
// ---------------------------------------------------------------------------
|
|
191
|
+
/**
|
|
192
|
+
* Parse a JSONC string (JSON with comments and trailing commas).
|
|
193
|
+
* VS Code's settings.json uses JSONC, so we need this to read it safely.
|
|
194
|
+
*/
|
|
195
|
+
function parseJsonc(text) {
|
|
196
|
+
// Remove single-line comments (// ...)
|
|
197
|
+
// Remove multi-line comments (/* ... */)
|
|
198
|
+
// Remove trailing commas before } or ]
|
|
199
|
+
const stripped = text
|
|
200
|
+
.replace(/\/\/[^\n]*/g, "")
|
|
201
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
202
|
+
.replace(/,(\s*[}\]])/g, "$1");
|
|
203
|
+
return JSON.parse(stripped);
|
|
204
|
+
}
|
|
147
205
|
function ensureDir(dir) {
|
|
148
206
|
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
149
207
|
}
|
|
@@ -613,7 +671,7 @@ function installCursorSkill(skillSrc) {
|
|
|
613
671
|
const cursorFrontmatter = [
|
|
614
672
|
"---",
|
|
615
673
|
"name: code-session-memory",
|
|
616
|
-
"description: Search past AI coding sessions semantically across OpenCode, Claude Code, and
|
|
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.",
|
|
617
675
|
"---",
|
|
618
676
|
"",
|
|
619
677
|
].join("\n");
|
|
@@ -639,6 +697,385 @@ function uninstallCursorSkill() {
|
|
|
639
697
|
return "done";
|
|
640
698
|
}
|
|
641
699
|
// ---------------------------------------------------------------------------
|
|
700
|
+
// VS Code — hook
|
|
701
|
+
// ---------------------------------------------------------------------------
|
|
702
|
+
/**
|
|
703
|
+
* Installs the VS Code Stop hook at ~/.vscode/hooks/code-session-memory.json
|
|
704
|
+
* using the Copilot hook format.
|
|
705
|
+
*/
|
|
706
|
+
function installVscodeHook(indexerCliVscodePath) {
|
|
707
|
+
const hooksPath = getVscodeHooksPath();
|
|
708
|
+
const existed = fs_1.default.existsSync(hooksPath);
|
|
709
|
+
// Always overwrite with our hook config (this file is owned by us)
|
|
710
|
+
const config = {
|
|
711
|
+
hooks: {
|
|
712
|
+
Stop: [
|
|
713
|
+
{
|
|
714
|
+
type: "command",
|
|
715
|
+
command: `node ${indexerCliVscodePath}`,
|
|
716
|
+
},
|
|
717
|
+
],
|
|
718
|
+
},
|
|
719
|
+
};
|
|
720
|
+
ensureDir(path_1.default.dirname(hooksPath));
|
|
721
|
+
fs_1.default.writeFileSync(hooksPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
722
|
+
return { hooksPath, existed };
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Removes the VS Code Stop hook file.
|
|
726
|
+
*/
|
|
727
|
+
function uninstallVscodeHook() {
|
|
728
|
+
const hooksPath = getVscodeHooksPath();
|
|
729
|
+
if (!fs_1.default.existsSync(hooksPath))
|
|
730
|
+
return "not_found";
|
|
731
|
+
fs_1.default.unlinkSync(hooksPath);
|
|
732
|
+
// Remove the directory if empty
|
|
733
|
+
try {
|
|
734
|
+
const dir = path_1.default.dirname(hooksPath);
|
|
735
|
+
if (fs_1.default.readdirSync(dir).length === 0)
|
|
736
|
+
fs_1.default.rmdirSync(dir);
|
|
737
|
+
}
|
|
738
|
+
catch { /* ignore */ }
|
|
739
|
+
return "done";
|
|
740
|
+
}
|
|
741
|
+
function checkVscodeHookInstalled() {
|
|
742
|
+
const hooksPath = getVscodeHooksPath();
|
|
743
|
+
try {
|
|
744
|
+
const config = JSON.parse(fs_1.default.readFileSync(hooksPath, "utf8"));
|
|
745
|
+
const stop = config.hooks?.Stop;
|
|
746
|
+
if (!Array.isArray(stop))
|
|
747
|
+
return false;
|
|
748
|
+
return stop.some((entry) => {
|
|
749
|
+
if (!entry || typeof entry !== "object")
|
|
750
|
+
return false;
|
|
751
|
+
const e = entry;
|
|
752
|
+
return typeof e.command === "string" && e.command.includes("indexer-cli-vscode");
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
catch {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
// ---------------------------------------------------------------------------
|
|
760
|
+
// VS Code — hook location registration
|
|
761
|
+
// ---------------------------------------------------------------------------
|
|
762
|
+
/**
|
|
763
|
+
* Returns the VS Code hooks path as a ~-prefixed string.
|
|
764
|
+
* VS Code supports ~ in hookFilesLocations, which improves portability across
|
|
765
|
+
* machines and avoids VS Code showing the fully-expanded path as an error.
|
|
766
|
+
*/
|
|
767
|
+
function getVscodeHooksPathTilde() {
|
|
768
|
+
const hooksPath = getVscodeHooksPath();
|
|
769
|
+
const home = os_1.default.homedir();
|
|
770
|
+
if (hooksPath.startsWith(home + path_1.default.sep)) {
|
|
771
|
+
return "~" + hooksPath.slice(home.length);
|
|
772
|
+
}
|
|
773
|
+
return hooksPath;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Adds the hook file path to VS Code's settings.json under
|
|
777
|
+
* `chat.hookFilesLocations` so VS Code discovers our hook.
|
|
778
|
+
* Uses a ~-prefixed path for portability.
|
|
779
|
+
*/
|
|
780
|
+
function installVscodeHookLocation() {
|
|
781
|
+
const settingsPath = getVscodeSettingsPath();
|
|
782
|
+
const existed = fs_1.default.existsSync(settingsPath);
|
|
783
|
+
let settings = {};
|
|
784
|
+
if (existed) {
|
|
785
|
+
try {
|
|
786
|
+
settings = parseJsonc(fs_1.default.readFileSync(settingsPath, "utf8"));
|
|
787
|
+
}
|
|
788
|
+
catch {
|
|
789
|
+
throw new Error(`Could not parse existing ${settingsPath} — please check it is valid JSON.`);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
const hookLocations = (settings["chat.hookFilesLocations"] ?? {});
|
|
793
|
+
// Remove any previously installed absolute path entry (migration)
|
|
794
|
+
const absolutePath = getVscodeHooksPath();
|
|
795
|
+
if (absolutePath in hookLocations) {
|
|
796
|
+
delete hookLocations[absolutePath];
|
|
797
|
+
}
|
|
798
|
+
hookLocations[getVscodeHooksPathTilde()] = true;
|
|
799
|
+
settings["chat.hookFilesLocations"] = hookLocations;
|
|
800
|
+
ensureDir(path_1.default.dirname(settingsPath));
|
|
801
|
+
fs_1.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
802
|
+
return { settingsPath, existed };
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Removes our hook file path from VS Code's `chat.hookFilesLocations` setting.
|
|
806
|
+
* Handles both ~ and absolute path variants.
|
|
807
|
+
*/
|
|
808
|
+
function uninstallVscodeHookLocation() {
|
|
809
|
+
const settingsPath = getVscodeSettingsPath();
|
|
810
|
+
if (!fs_1.default.existsSync(settingsPath))
|
|
811
|
+
return "not_found";
|
|
812
|
+
try {
|
|
813
|
+
const settings = parseJsonc(fs_1.default.readFileSync(settingsPath, "utf8"));
|
|
814
|
+
const hookLocations = settings["chat.hookFilesLocations"];
|
|
815
|
+
if (!hookLocations)
|
|
816
|
+
return "not_found";
|
|
817
|
+
const tildePath = getVscodeHooksPathTilde();
|
|
818
|
+
const absolutePath = getVscodeHooksPath();
|
|
819
|
+
const foundTilde = tildePath in hookLocations;
|
|
820
|
+
const foundAbsolute = absolutePath in hookLocations;
|
|
821
|
+
if (!foundTilde && !foundAbsolute)
|
|
822
|
+
return "not_found";
|
|
823
|
+
if (foundTilde)
|
|
824
|
+
delete hookLocations[tildePath];
|
|
825
|
+
if (foundAbsolute)
|
|
826
|
+
delete hookLocations[absolutePath];
|
|
827
|
+
settings["chat.hookFilesLocations"] = hookLocations;
|
|
828
|
+
fs_1.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
829
|
+
return "done";
|
|
830
|
+
}
|
|
831
|
+
catch {
|
|
832
|
+
return "not_found";
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function checkVscodeHookLocationRegistered() {
|
|
836
|
+
const settingsPath = getVscodeSettingsPath();
|
|
837
|
+
try {
|
|
838
|
+
const settings = parseJsonc(fs_1.default.readFileSync(settingsPath, "utf8"));
|
|
839
|
+
const hookLocations = settings["chat.hookFilesLocations"];
|
|
840
|
+
if (!hookLocations)
|
|
841
|
+
return false;
|
|
842
|
+
return hookLocations[getVscodeHooksPathTilde()] === true ||
|
|
843
|
+
hookLocations[getVscodeHooksPath()] === true;
|
|
844
|
+
}
|
|
845
|
+
catch {
|
|
846
|
+
return false;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// ---------------------------------------------------------------------------
|
|
850
|
+
// VS Code — MCP config
|
|
851
|
+
// ---------------------------------------------------------------------------
|
|
852
|
+
/**
|
|
853
|
+
* Merges the code-session-memory MCP entry into VS Code's mcp.json.
|
|
854
|
+
*/
|
|
855
|
+
function installVscodeMcpConfig(mcpServerPath) {
|
|
856
|
+
const configPath = getVscodeMcpConfigPath();
|
|
857
|
+
const existed = fs_1.default.existsSync(configPath);
|
|
858
|
+
let config = {};
|
|
859
|
+
if (existed) {
|
|
860
|
+
try {
|
|
861
|
+
config = JSON.parse(fs_1.default.readFileSync(configPath, "utf8"));
|
|
862
|
+
}
|
|
863
|
+
catch {
|
|
864
|
+
throw new Error(`Could not parse existing ${configPath} — please check it is valid JSON.`);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (!config.servers || typeof config.servers !== "object")
|
|
868
|
+
config.servers = {};
|
|
869
|
+
config.servers["code-session-memory"] = {
|
|
870
|
+
type: "stdio",
|
|
871
|
+
command: "node",
|
|
872
|
+
args: [mcpServerPath],
|
|
873
|
+
};
|
|
874
|
+
ensureDir(path_1.default.dirname(configPath));
|
|
875
|
+
fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
876
|
+
return { configPath, existed };
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Removes the code-session-memory MCP entry from VS Code's mcp.json.
|
|
880
|
+
*/
|
|
881
|
+
function uninstallVscodeMcpConfig() {
|
|
882
|
+
const configPath = getVscodeMcpConfigPath();
|
|
883
|
+
if (!fs_1.default.existsSync(configPath))
|
|
884
|
+
return "not_found";
|
|
885
|
+
try {
|
|
886
|
+
const config = JSON.parse(fs_1.default.readFileSync(configPath, "utf8"));
|
|
887
|
+
if (config.servers &&
|
|
888
|
+
typeof config.servers === "object" &&
|
|
889
|
+
"code-session-memory" in config.servers) {
|
|
890
|
+
delete config.servers["code-session-memory"];
|
|
891
|
+
fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
892
|
+
return "done";
|
|
893
|
+
}
|
|
894
|
+
return "not_found";
|
|
895
|
+
}
|
|
896
|
+
catch {
|
|
897
|
+
return "not_found";
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
function checkVscodeMcpConfigured() {
|
|
901
|
+
const configPath = getVscodeMcpConfigPath();
|
|
902
|
+
try {
|
|
903
|
+
const config = JSON.parse(fs_1.default.readFileSync(configPath, "utf8"));
|
|
904
|
+
return !!(config.servers &&
|
|
905
|
+
typeof config.servers === "object" &&
|
|
906
|
+
"code-session-memory" in config.servers);
|
|
907
|
+
}
|
|
908
|
+
catch {
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
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
|
+
// ---------------------------------------------------------------------------
|
|
642
1079
|
// Formatting helpers
|
|
643
1080
|
// ---------------------------------------------------------------------------
|
|
644
1081
|
function bold(s) { return `\x1b[1m${s}\x1b[0m`; }
|
|
@@ -646,6 +1083,24 @@ function green(s) { return `\x1b[32m${s}\x1b[0m`; }
|
|
|
646
1083
|
function red(s) { return `\x1b[31m${s}\x1b[0m`; }
|
|
647
1084
|
function dim(s) { return `\x1b[2m${s}\x1b[0m`; }
|
|
648
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
|
+
}
|
|
649
1104
|
function step(label, fn) {
|
|
650
1105
|
process.stdout.write(` ${label}... `);
|
|
651
1106
|
try {
|
|
@@ -658,6 +1113,13 @@ function step(label, fn) {
|
|
|
658
1113
|
process.exit(1);
|
|
659
1114
|
}
|
|
660
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
|
+
}
|
|
661
1123
|
// ---------------------------------------------------------------------------
|
|
662
1124
|
// Commands
|
|
663
1125
|
// ---------------------------------------------------------------------------
|
|
@@ -667,6 +1129,13 @@ function install() {
|
|
|
667
1129
|
const mcpPath = getMcpServerPath();
|
|
668
1130
|
const indexerClaudePath = getIndexerCliClaudePath();
|
|
669
1131
|
const indexerCursorPath = getIndexerCliCursorPath();
|
|
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();
|
|
670
1139
|
// 1. DB
|
|
671
1140
|
step("Initialising database", () => {
|
|
672
1141
|
ensureDir(path_1.default.dirname(dbPath));
|
|
@@ -674,53 +1143,73 @@ function install() {
|
|
|
674
1143
|
db.close();
|
|
675
1144
|
return dbPath;
|
|
676
1145
|
});
|
|
677
|
-
//
|
|
678
|
-
|
|
1146
|
+
// OpenCode
|
|
1147
|
+
stepIf(openCodeInstalled, "Installing OpenCode plugin", () => {
|
|
679
1148
|
const dst = getOpenCodePluginDst();
|
|
680
1149
|
installOpenCodePlugin(getPluginSrc(), dst);
|
|
681
1150
|
return dst;
|
|
682
1151
|
});
|
|
683
|
-
|
|
684
|
-
step("Installing OpenCode skill", () => {
|
|
1152
|
+
stepIf(openCodeInstalled, "Installing OpenCode skill", () => {
|
|
685
1153
|
const dst = getOpenCodeSkillDst();
|
|
686
1154
|
copyFile(getSkillSrc(), dst);
|
|
687
1155
|
return dst;
|
|
688
1156
|
});
|
|
689
|
-
|
|
690
|
-
step("Configuring OpenCode MCP server", () => {
|
|
1157
|
+
stepIf(openCodeInstalled, "Configuring OpenCode MCP server", () => {
|
|
691
1158
|
const { configPath, existed } = installOpenCodeMcpConfig(mcpPath);
|
|
692
1159
|
return `${existed ? "updated" : "created"} ${configPath}`;
|
|
693
1160
|
});
|
|
694
|
-
//
|
|
695
|
-
|
|
1161
|
+
// Claude Code
|
|
1162
|
+
stepIf(claudeInstalled, "Configuring Claude Code MCP server", () => {
|
|
696
1163
|
const { configPath, existed } = installClaudeMcpConfig(mcpPath);
|
|
697
1164
|
return `${existed ? "updated" : "created"} ${configPath}`;
|
|
698
1165
|
});
|
|
699
|
-
|
|
700
|
-
step("Installing Claude Code Stop hook", () => {
|
|
1166
|
+
stepIf(claudeInstalled, "Installing Claude Code Stop hook", () => {
|
|
701
1167
|
const { settingsPath, existed } = installClaudeHook(indexerClaudePath);
|
|
702
1168
|
return `${existed ? "updated" : "created"} ${settingsPath}`;
|
|
703
1169
|
});
|
|
704
|
-
|
|
705
|
-
step("Installing Claude Code context (CLAUDE.md)", () => {
|
|
1170
|
+
stepIf(claudeInstalled, "Installing Claude Code context (CLAUDE.md)", () => {
|
|
706
1171
|
const { mdPath, existed } = installClaudeMd(getSkillSrc());
|
|
707
1172
|
return `${existed ? "updated" : "created"} ${mdPath}`;
|
|
708
1173
|
});
|
|
709
|
-
//
|
|
710
|
-
|
|
1174
|
+
// Cursor
|
|
1175
|
+
stepIf(cursorInstalled, "Configuring Cursor MCP server", () => {
|
|
711
1176
|
const { configPath, existed } = installCursorMcpConfig(mcpPath);
|
|
712
1177
|
return `${existed ? "updated" : "created"} ${configPath}`;
|
|
713
1178
|
});
|
|
714
|
-
|
|
715
|
-
step("Installing Cursor stop hook", () => {
|
|
1179
|
+
stepIf(cursorInstalled, "Installing Cursor stop hook", () => {
|
|
716
1180
|
const { hooksPath, existed } = installCursorHook(indexerCursorPath);
|
|
717
1181
|
return `${existed ? "updated" : "created"} ${hooksPath}`;
|
|
718
1182
|
});
|
|
719
|
-
|
|
720
|
-
step("Installing Cursor skill", () => {
|
|
1183
|
+
stepIf(cursorInstalled, "Installing Cursor skill", () => {
|
|
721
1184
|
const { dstPath, existed } = installCursorSkill(getSkillSrc());
|
|
722
1185
|
return `${existed ? "updated" : "created"} ${dstPath}`;
|
|
723
1186
|
});
|
|
1187
|
+
// VS Code
|
|
1188
|
+
stepIf(vscodeInstalled, "Configuring VS Code MCP server", () => {
|
|
1189
|
+
const { configPath, existed } = installVscodeMcpConfig(mcpPath);
|
|
1190
|
+
return `${existed ? "updated" : "created"} ${configPath}`;
|
|
1191
|
+
});
|
|
1192
|
+
stepIf(vscodeInstalled, "Installing VS Code Stop hook", () => {
|
|
1193
|
+
const { hooksPath, existed } = installVscodeHook(indexerVscodePath);
|
|
1194
|
+
return `${existed ? "updated" : "created"} ${hooksPath}`;
|
|
1195
|
+
});
|
|
1196
|
+
stepIf(vscodeInstalled, "Registering VS Code hook location", () => {
|
|
1197
|
+
const { settingsPath, existed } = installVscodeHookLocation();
|
|
1198
|
+
return `${existed ? "updated" : "created"} ${settingsPath}`;
|
|
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
|
+
});
|
|
724
1213
|
console.log(`
|
|
725
1214
|
${bold("Installation complete!")}
|
|
726
1215
|
|
|
@@ -729,7 +1218,10 @@ ${bold("Required environment variable:")}
|
|
|
729
1218
|
|
|
730
1219
|
${bold("Default DB path:")} ${dbPath}
|
|
731
1220
|
|
|
732
|
-
Restart ${bold("OpenCode")}, ${bold("Claude Code")}, and ${bold("
|
|
1221
|
+
Restart ${bold("OpenCode")}, ${bold("Claude Code")}, ${bold("Cursor")}, ${bold("VS Code")}, and ${bold("Codex")} to activate.
|
|
1222
|
+
|
|
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())}.
|
|
733
1225
|
Run ${bold("npx code-session-memory status")} to verify.
|
|
734
1226
|
`);
|
|
735
1227
|
}
|
|
@@ -737,18 +1229,57 @@ function status() {
|
|
|
737
1229
|
console.log(bold("\ncode-session-memory status\n"));
|
|
738
1230
|
const dbPath = (0, database_1.resolveDbPath)();
|
|
739
1231
|
const mcpPath = getMcpServerPath();
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
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
|
+
}
|
|
752
1283
|
console.log(bold("\n Shared"));
|
|
753
1284
|
console.log(` ${ok(fs_1.default.existsSync(mcpPath))} MCP server ${dim(mcpPath)}`);
|
|
754
1285
|
console.log(` ${ok(fs_1.default.existsSync(dbPath))} Database ${dim(dbPath)}`);
|
|
@@ -772,15 +1303,22 @@ function status() {
|
|
|
772
1303
|
}
|
|
773
1304
|
catch { /* DB might be empty */ }
|
|
774
1305
|
}
|
|
775
|
-
const allOk = fs_1.default.existsSync(getOpenCodePluginDst()) &&
|
|
1306
|
+
const allOk = (!openCodeInstalled || (fs_1.default.existsSync(getOpenCodePluginDst()) &&
|
|
776
1307
|
fs_1.default.existsSync(getOpenCodeSkillDst()) &&
|
|
777
|
-
checkMcpConfigured() &&
|
|
778
|
-
checkClaudeMcpConfigured() &&
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
checkCursorMcpConfigured() &&
|
|
782
|
-
|
|
783
|
-
|
|
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()))) &&
|
|
784
1322
|
fs_1.default.existsSync(mcpPath) &&
|
|
785
1323
|
fs_1.default.existsSync(dbPath);
|
|
786
1324
|
console.log(`\n ${allOk
|
|
@@ -832,6 +1370,30 @@ function uninstall() {
|
|
|
832
1370
|
if (uninstallCursorSkill() === "not_found")
|
|
833
1371
|
throw new Error("not found");
|
|
834
1372
|
}],
|
|
1373
|
+
["VS Code MCP config", () => {
|
|
1374
|
+
if (uninstallVscodeMcpConfig() === "not_found")
|
|
1375
|
+
throw new Error("not found");
|
|
1376
|
+
}],
|
|
1377
|
+
["VS Code Stop hook", () => {
|
|
1378
|
+
if (uninstallVscodeHook() === "not_found")
|
|
1379
|
+
throw new Error("not found");
|
|
1380
|
+
}],
|
|
1381
|
+
["VS Code hook location", () => {
|
|
1382
|
+
if (uninstallVscodeHookLocation() === "not_found")
|
|
1383
|
+
throw new Error("not found");
|
|
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
|
+
}],
|
|
835
1397
|
];
|
|
836
1398
|
for (const [label, fn] of items) {
|
|
837
1399
|
process.stdout.write(` Removing ${label}... `);
|
|
@@ -886,15 +1448,15 @@ async function resetDb() {
|
|
|
886
1448
|
}
|
|
887
1449
|
function help() {
|
|
888
1450
|
console.log(`
|
|
889
|
-
${bold("code-session-memory")} — Shared vector memory for OpenCode, Claude Code, and
|
|
1451
|
+
${bold("code-session-memory")} — Shared vector memory for OpenCode, Claude Code, Cursor, VS Code, and Codex sessions
|
|
890
1452
|
|
|
891
1453
|
${bold("Usage:")}
|
|
892
|
-
npx code-session-memory install Install
|
|
1454
|
+
npx code-session-memory install Install components for detected tools
|
|
893
1455
|
npx code-session-memory status Show installation status and DB stats
|
|
894
1456
|
npx code-session-memory uninstall Remove all installed components (keeps DB)
|
|
895
1457
|
npx code-session-memory reset-db Delete all indexed data (keeps installation)
|
|
896
1458
|
npx code-session-memory query <text> Semantic search across all indexed sessions
|
|
897
|
-
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)
|
|
898
1460
|
npx code-session-memory query <text> --limit <n> Max results (default: 5)
|
|
899
1461
|
npx code-session-memory query <text> --from <date> Results from date (e.g. 2026-02-01)
|
|
900
1462
|
npx code-session-memory query <text> --to <date> Results up to date (e.g. 2026-02-20)
|
|
@@ -911,6 +1473,8 @@ ${bold("Environment variables:")}
|
|
|
911
1473
|
OPENCODE_CONFIG_DIR Override the OpenCode config directory
|
|
912
1474
|
CLAUDE_CONFIG_DIR Override the Claude Code config directory
|
|
913
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)
|
|
914
1478
|
`);
|
|
915
1479
|
}
|
|
916
1480
|
// ---------------------------------------------------------------------------
|