code-session-memory 0.10.0 → 0.12.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 +56 -18
- package/dist/mcp/index.js +2 -2
- 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 +5 -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 +69 -0
- package/dist/src/cli-sessions.js.map +1 -1
- package/dist/src/cli.js +288 -5
- package/dist/src/cli.js.map +1 -1
- package/dist/src/clipboard.d.ts +24 -0
- package/dist/src/clipboard.d.ts.map +1 -0
- package/dist/src/clipboard.js +48 -0
- package/dist/src/clipboard.js.map +1 -0
- package/dist/src/gemini-session-to-messages.d.ts +25 -0
- package/dist/src/gemini-session-to-messages.d.ts.map +1 -0
- package/dist/src/gemini-session-to-messages.js +205 -0
- package/dist/src/gemini-session-to-messages.js.map +1 -0
- package/dist/src/indexer-cli-gemini.d.ts +12 -0
- package/dist/src/indexer-cli-gemini.d.ts.map +1 -0
- package/dist/src/indexer-cli-gemini.js +148 -0
- package/dist/src/indexer-cli-gemini.js.map +1 -0
- package/dist/src/indexer.d.ts +1 -1
- package/dist/src/indexer.js +1 -1
- package/dist/src/restart-launchers.d.ts +37 -0
- package/dist/src/restart-launchers.d.ts.map +1 -0
- package/dist/src/restart-launchers.js +68 -0
- package/dist/src/restart-launchers.js.map +1 -0
- package/dist/src/session-compactor.d.ts +48 -0
- package/dist/src/session-compactor.d.ts.map +1 -0
- package/dist/src/session-compactor.js +203 -0
- package/dist/src/session-compactor.js.map +1 -0
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +4 -3
- package/skill/memory.md +7 -4
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Entry point for Gemini CLI session indexing.
|
|
5
|
+
*
|
|
6
|
+
* Called by the Gemini CLI AfterAgent hook. Receives JSON on stdin:
|
|
7
|
+
* { session_id, transcript_path, cwd, hook_event_name, ... }
|
|
8
|
+
*
|
|
9
|
+
* Reads the session JSON transcript, converts to FullMessage[], and indexes
|
|
10
|
+
* new messages into the shared sqlite-vec DB.
|
|
11
|
+
*/
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
const database_1 = require("./database");
|
|
17
|
+
const indexer_1 = require("./indexer");
|
|
18
|
+
const gemini_session_to_messages_1 = require("./gemini-session-to-messages");
|
|
19
|
+
const fs_1 = __importDefault(require("fs"));
|
|
20
|
+
const os_1 = __importDefault(require("os"));
|
|
21
|
+
const path_1 = __importDefault(require("path"));
|
|
22
|
+
function getGeminiConfigDir() {
|
|
23
|
+
return process.env.GEMINI_CONFIG_DIR ?? path_1.default.join(os_1.default.homedir(), ".gemini");
|
|
24
|
+
}
|
|
25
|
+
function getString(value) {
|
|
26
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
27
|
+
}
|
|
28
|
+
function findTranscriptBySessionId(sessionId, cwd) {
|
|
29
|
+
const tmpRoot = path_1.default.join(getGeminiConfigDir(), "tmp");
|
|
30
|
+
const projectName = cwd ? path_1.default.basename(cwd) : undefined;
|
|
31
|
+
const candidateDirs = [
|
|
32
|
+
projectName ? path_1.default.join(tmpRoot, projectName, "chats") : undefined,
|
|
33
|
+
path_1.default.join(tmpRoot),
|
|
34
|
+
].filter((d) => Boolean(d && fs_1.default.existsSync(d)));
|
|
35
|
+
const files = [];
|
|
36
|
+
function walk(dir) {
|
|
37
|
+
let entries;
|
|
38
|
+
try {
|
|
39
|
+
entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
walk(fullPath);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (entry.isFile() &&
|
|
51
|
+
entry.name.startsWith("session-") &&
|
|
52
|
+
entry.name.endsWith(".json")) {
|
|
53
|
+
let mtimeMs = 0;
|
|
54
|
+
try {
|
|
55
|
+
mtimeMs = fs_1.default.statSync(fullPath).mtimeMs;
|
|
56
|
+
}
|
|
57
|
+
catch { /* ignore */ }
|
|
58
|
+
files.push({ filePath: fullPath, mtimeMs });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
for (const dir of candidateDirs)
|
|
63
|
+
walk(dir);
|
|
64
|
+
// Newest first, and keep the search bounded.
|
|
65
|
+
files.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
66
|
+
const MAX_FILES_TO_CHECK = 200;
|
|
67
|
+
for (const { filePath } of files.slice(0, MAX_FILES_TO_CHECK)) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
70
|
+
const candidateId = parsed.sessionId ?? parsed.session_id;
|
|
71
|
+
if (candidateId === sessionId)
|
|
72
|
+
return filePath;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Ignore malformed files.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
async function main() {
|
|
81
|
+
const chunks = [];
|
|
82
|
+
for await (const chunk of process.stdin) {
|
|
83
|
+
chunks.push(chunk);
|
|
84
|
+
}
|
|
85
|
+
let payload;
|
|
86
|
+
try {
|
|
87
|
+
payload = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
process.stderr.write(`[code-session-memory] Failed to parse stdin: ${err}\n`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const { sessionId: sessionIdCamel, session_id: sessionIdSnake, transcriptPath: transcriptPathCamel, transcript_path: transcriptPathSnake, cwd, workspaceRoot, workspace_root: workspaceRootSnake, hookEventName, hook_event_name: hookEventNameSnake, eventName, } = payload;
|
|
95
|
+
const sessionId = sessionIdSnake ?? sessionIdCamel;
|
|
96
|
+
const projectDir = getString(cwd) ??
|
|
97
|
+
getString(workspaceRoot) ??
|
|
98
|
+
getString(workspaceRootSnake) ??
|
|
99
|
+
"";
|
|
100
|
+
const hookEvent = hookEventNameSnake ??
|
|
101
|
+
hookEventName ??
|
|
102
|
+
eventName;
|
|
103
|
+
const transcriptPath = transcriptPathSnake ??
|
|
104
|
+
transcriptPathCamel ??
|
|
105
|
+
(sessionId ? findTranscriptBySessionId(sessionId, projectDir) : undefined);
|
|
106
|
+
if (!sessionId) {
|
|
107
|
+
process.stderr.write("[code-session-memory] Missing session id in hook payload (session_id/sessionId)\n");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// Index only completed turns if an event name is provided.
|
|
112
|
+
if (hookEvent && hookEvent !== "AfterAgent") {
|
|
113
|
+
process.exit(0);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!transcriptPath) {
|
|
117
|
+
process.stderr.write("[code-session-memory] Missing transcript path in hook payload and could not auto-discover session file\n");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const dbPath = (0, database_1.resolveDbPath)();
|
|
122
|
+
const db = (0, database_1.openDatabase)({ dbPath });
|
|
123
|
+
try {
|
|
124
|
+
const messages = (0, gemini_session_to_messages_1.geminiSessionToMessages)(transcriptPath);
|
|
125
|
+
if (messages.length === 0)
|
|
126
|
+
return;
|
|
127
|
+
const existingMeta = (0, database_1.getSessionMeta)(db, sessionId);
|
|
128
|
+
const title = existingMeta?.session_title || (0, gemini_session_to_messages_1.deriveGeminiSessionTitle)(messages, sessionId);
|
|
129
|
+
const session = {
|
|
130
|
+
id: sessionId,
|
|
131
|
+
title,
|
|
132
|
+
directory: projectDir,
|
|
133
|
+
};
|
|
134
|
+
await (0, indexer_1.indexNewMessages)(db, session, messages, "gemini-cli");
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
138
|
+
process.stderr.write(`[code-session-memory] Indexing error: ${msg}\n`);
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
db.close();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
main().catch((err) => {
|
|
145
|
+
process.stderr.write(`[code-session-memory] Fatal: ${err}\n`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
});
|
|
148
|
+
//# sourceMappingURL=indexer-cli-gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer-cli-gemini.js","sourceRoot":"","sources":["../../src/indexer-cli-gemini.ts"],"names":[],"mappings":"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"}
|
package/dist/src/indexer.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface IndexerOptions {
|
|
|
19
19
|
* @param db Already-open database connection (caller manages lifecycle)
|
|
20
20
|
* @param session Session metadata (id, title, directory)
|
|
21
21
|
* @param messages All messages in the session
|
|
22
|
-
* @param source Which tool produced the session ("opencode" | "claude-code" | "cursor" | "vscode" | "codex")
|
|
22
|
+
* @param source Which tool produced the session ("opencode" | "claude-code" | "cursor" | "vscode" | "codex" | "gemini-cli")
|
|
23
23
|
* @param options Optional overrides for API key / model
|
|
24
24
|
*/
|
|
25
25
|
export declare function indexNewMessages(db: Database, session: SessionInfo, messages: FullMessage[], source?: SessionSource, options?: Pick<IndexerOptions, "openAiApiKey" | "embeddingModel">): Promise<{
|
package/dist/src/indexer.js
CHANGED
|
@@ -21,7 +21,7 @@ const session_to_md_1 = require("./session-to-md");
|
|
|
21
21
|
* @param db Already-open database connection (caller manages lifecycle)
|
|
22
22
|
* @param session Session metadata (id, title, directory)
|
|
23
23
|
* @param messages All messages in the session
|
|
24
|
-
* @param source Which tool produced the session ("opencode" | "claude-code" | "cursor" | "vscode" | "codex")
|
|
24
|
+
* @param source Which tool produced the session ("opencode" | "claude-code" | "cursor" | "vscode" | "codex" | "gemini-cli")
|
|
25
25
|
* @param options Optional overrides for API key / model
|
|
26
26
|
*/
|
|
27
27
|
async function indexNewMessages(db, session, messages, source = "opencode", options = {}) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* restart-launchers.ts — per-tool CLI launch adapters for "Restart from..."
|
|
3
|
+
*
|
|
4
|
+
* Supported tools and their CLI arguments:
|
|
5
|
+
* codex → codex "<prompt>"
|
|
6
|
+
* claude-code → claude "<prompt>"
|
|
7
|
+
* cursor → cursor agent "<prompt>"
|
|
8
|
+
* opencode → opencode run "<prompt>"
|
|
9
|
+
* vscode → fallback-only (no reliable session-create CLI)
|
|
10
|
+
*
|
|
11
|
+
* Contract: if compaction succeeded, the operation is still considered a
|
|
12
|
+
* success even if the launch fails — the compact summary is already on the
|
|
13
|
+
* clipboard for manual use.
|
|
14
|
+
*/
|
|
15
|
+
import type { CompactTarget } from "./session-compactor";
|
|
16
|
+
export interface LaunchResult {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
/** Human-readable error message when ok === false. */
|
|
19
|
+
error?: string;
|
|
20
|
+
/** True when the target has no supported launch path (e.g. vscode). */
|
|
21
|
+
isUnsupported?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Spawns the target tool's CLI with the compact prompt as an argument.
|
|
25
|
+
*
|
|
26
|
+
* The child process inherits stdio so the user sees its output.
|
|
27
|
+
* The process is detached so the CLI can exit without waiting.
|
|
28
|
+
*
|
|
29
|
+
* Returns immediately after spawning (does not wait for the child to exit).
|
|
30
|
+
*/
|
|
31
|
+
export declare function launchTool(target: CompactTarget, prompt: string): LaunchResult;
|
|
32
|
+
/**
|
|
33
|
+
* Returns [command, args] for the given target.
|
|
34
|
+
* Exported for unit testing without spawning a process.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveCommand(target: Exclude<CompactTarget, "vscode">, prompt: string): [string, string[]];
|
|
37
|
+
//# sourceMappingURL=restart-launchers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart-launchers.d.ts","sourceRoot":"","sources":["../../src/restart-launchers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,YAAY,CAyBd;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,EACxC,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAWpB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* restart-launchers.ts — per-tool CLI launch adapters for "Restart from..."
|
|
4
|
+
*
|
|
5
|
+
* Supported tools and their CLI arguments:
|
|
6
|
+
* codex → codex "<prompt>"
|
|
7
|
+
* claude-code → claude "<prompt>"
|
|
8
|
+
* cursor → cursor agent "<prompt>"
|
|
9
|
+
* opencode → opencode run "<prompt>"
|
|
10
|
+
* vscode → fallback-only (no reliable session-create CLI)
|
|
11
|
+
*
|
|
12
|
+
* Contract: if compaction succeeded, the operation is still considered a
|
|
13
|
+
* success even if the launch fails — the compact summary is already on the
|
|
14
|
+
* clipboard for manual use.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.launchTool = launchTool;
|
|
18
|
+
exports.resolveCommand = resolveCommand;
|
|
19
|
+
const child_process_1 = require("child_process");
|
|
20
|
+
/**
|
|
21
|
+
* Spawns the target tool's CLI with the compact prompt as an argument.
|
|
22
|
+
*
|
|
23
|
+
* The child process inherits stdio so the user sees its output.
|
|
24
|
+
* The process is detached so the CLI can exit without waiting.
|
|
25
|
+
*
|
|
26
|
+
* Returns immediately after spawning (does not wait for the child to exit).
|
|
27
|
+
*/
|
|
28
|
+
function launchTool(target, prompt) {
|
|
29
|
+
if (target === "vscode") {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
isUnsupported: true,
|
|
33
|
+
error: "VS Code has no reliable session-create CLI path. " +
|
|
34
|
+
"Paste the continuation prompt into a new Copilot Chat window manually.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const [cmd, args] = resolveCommand(target, prompt);
|
|
38
|
+
try {
|
|
39
|
+
const child = (0, child_process_1.spawn)(cmd, args, {
|
|
40
|
+
stdio: "inherit",
|
|
41
|
+
detached: true,
|
|
42
|
+
shell: false,
|
|
43
|
+
});
|
|
44
|
+
child.unref();
|
|
45
|
+
return { ok: true };
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
49
|
+
return { ok: false, error: `Failed to launch ${cmd}: ${msg}` };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns [command, args] for the given target.
|
|
54
|
+
* Exported for unit testing without spawning a process.
|
|
55
|
+
*/
|
|
56
|
+
function resolveCommand(target, prompt) {
|
|
57
|
+
switch (target) {
|
|
58
|
+
case "codex":
|
|
59
|
+
return ["codex", [prompt]];
|
|
60
|
+
case "claude-code":
|
|
61
|
+
return ["claude", [prompt]];
|
|
62
|
+
case "cursor":
|
|
63
|
+
return ["cursor", ["agent", prompt]];
|
|
64
|
+
case "opencode":
|
|
65
|
+
return ["opencode", ["run", prompt]];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=restart-launchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart-launchers.js","sourceRoot":"","sources":["../../src/restart-launchers.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAqBH,gCA4BC;AAMD,wCAcC;AAnED,iDAAsC;AAWtC;;;;;;;GAOG;AACH,SAAgB,UAAU,CACxB,MAAqB,EACrB,MAAc;IAEd,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,aAAa,EAAE,IAAI;YACnB,KAAK,EACH,mDAAmD;gBACnD,wEAAwE;SAC3E,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAA,qBAAK,EAAC,GAAG,EAAE,IAAI,EAAE;YAC7B,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,GAAG,KAAK,GAAG,EAAE,EAAE,CAAC;IACjE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAC5B,MAAwC,EACxC,MAAc;IAEd,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7B,KAAK,aAAa;YAChB,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9B,KAAK,QAAQ;YACX,OAAO,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACvC,KAAK,UAAU;YACb,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACzC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-compactor.ts — summarize a session's chunks into a compact restart document.
|
|
3
|
+
*
|
|
4
|
+
* Uses OpenAI chat completions with a map-reduce strategy for long sessions:
|
|
5
|
+
* 1. Single-pass for sessions whose estimated token count fits within the limit.
|
|
6
|
+
* 2. Multi-pass for longer sessions: map each window → reduce all partials → final format.
|
|
7
|
+
*
|
|
8
|
+
* Environment variables:
|
|
9
|
+
* OPENAI_API_KEY Required. Passed to the OpenAI client.
|
|
10
|
+
* OPENAI_SUMMARY_MODEL Override model (default: "gpt-5-nano").
|
|
11
|
+
* CSM_SUMMARY_MAX_OUTPUT_TOKENS Override max output tokens (default: 5000).
|
|
12
|
+
*/
|
|
13
|
+
import type { ChunkRow } from "./database";
|
|
14
|
+
export interface CompactOptions {
|
|
15
|
+
/** Override the summarizer model. Default: OPENAI_SUMMARY_MODEL env var or "gpt-5-nano". */
|
|
16
|
+
model?: string;
|
|
17
|
+
/** Override the max output token budget. Default: CSM_SUMMARY_MAX_OUTPUT_TOKENS env var or 5000. */
|
|
18
|
+
maxOutputTokens?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface CompactResult {
|
|
21
|
+
summary: string;
|
|
22
|
+
model: string;
|
|
23
|
+
/** Total number of LLM passes performed (map passes + reduce + final format). */
|
|
24
|
+
passes: number;
|
|
25
|
+
usage: {
|
|
26
|
+
inputTokens: number;
|
|
27
|
+
outputTokens: number;
|
|
28
|
+
totalTokens: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Summarizes the given ordered chunks into a restart document ready to paste
|
|
33
|
+
* into a new AI coding session.
|
|
34
|
+
*
|
|
35
|
+
* @throws Error if OPENAI_API_KEY is missing or any OpenAI call fails.
|
|
36
|
+
*/
|
|
37
|
+
export declare function compactSession(chunks: ChunkRow[], options?: CompactOptions): Promise<CompactResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Builds a human-readable transcript from ordered chunk rows.
|
|
40
|
+
* Groups consecutive chunks with the same section label under a single header.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildTranscript(chunks: ChunkRow[]): string;
|
|
43
|
+
/**
|
|
44
|
+
* Splits `text` into windows of at most `windowChars` characters.
|
|
45
|
+
* Splits on newline boundaries when possible.
|
|
46
|
+
*/
|
|
47
|
+
export declare function splitIntoWindows(text: string, windowChars: number): string[];
|
|
48
|
+
//# sourceMappingURL=session-compactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-compactor.d.ts","sourceRoot":"","sources":["../../src/session-compactor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM3C,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,QAAQ,EAAE,EAClB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA6GxB;AAgED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAgB1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAoB5E"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* session-compactor.ts — summarize a session's chunks into a compact restart document.
|
|
4
|
+
*
|
|
5
|
+
* Uses OpenAI chat completions with a map-reduce strategy for long sessions:
|
|
6
|
+
* 1. Single-pass for sessions whose estimated token count fits within the limit.
|
|
7
|
+
* 2. Multi-pass for longer sessions: map each window → reduce all partials → final format.
|
|
8
|
+
*
|
|
9
|
+
* Environment variables:
|
|
10
|
+
* OPENAI_API_KEY Required. Passed to the OpenAI client.
|
|
11
|
+
* OPENAI_SUMMARY_MODEL Override model (default: "gpt-5-nano").
|
|
12
|
+
* CSM_SUMMARY_MAX_OUTPUT_TOKENS Override max output tokens (default: 5000).
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.compactSession = compactSession;
|
|
19
|
+
exports.buildTranscript = buildTranscript;
|
|
20
|
+
exports.splitIntoWindows = splitIntoWindows;
|
|
21
|
+
const openai_1 = __importDefault(require("openai"));
|
|
22
|
+
/**
|
|
23
|
+
* Summarizes the given ordered chunks into a restart document ready to paste
|
|
24
|
+
* into a new AI coding session.
|
|
25
|
+
*
|
|
26
|
+
* @throws Error if OPENAI_API_KEY is missing or any OpenAI call fails.
|
|
27
|
+
*/
|
|
28
|
+
async function compactSession(chunks, options = {}) {
|
|
29
|
+
const model = options.model ??
|
|
30
|
+
process.env.OPENAI_SUMMARY_MODEL ??
|
|
31
|
+
"gpt-5-nano";
|
|
32
|
+
const maxOutputTokens = options.maxOutputTokens ??
|
|
33
|
+
Number(process.env.CSM_SUMMARY_MAX_OUTPUT_TOKENS ?? "5000");
|
|
34
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
35
|
+
if (!apiKey) {
|
|
36
|
+
throw new Error("OPENAI_API_KEY environment variable is required for session compaction.");
|
|
37
|
+
}
|
|
38
|
+
const client = new openai_1.default({ apiKey });
|
|
39
|
+
const useLowReasoningEffort = supportsLowReasoningEffort(model);
|
|
40
|
+
const usageTotals = {
|
|
41
|
+
inputTokens: 0,
|
|
42
|
+
outputTokens: 0,
|
|
43
|
+
totalTokens: 0,
|
|
44
|
+
};
|
|
45
|
+
async function runCompletion(messages, maxCompletionTokens) {
|
|
46
|
+
const response = await client.chat.completions.create({
|
|
47
|
+
model,
|
|
48
|
+
max_completion_tokens: maxCompletionTokens,
|
|
49
|
+
...(useLowReasoningEffort ? { reasoning_effort: "low" } : {}),
|
|
50
|
+
messages,
|
|
51
|
+
});
|
|
52
|
+
const promptTokens = response.usage?.prompt_tokens ?? 0;
|
|
53
|
+
const completionTokens = response.usage?.completion_tokens ?? 0;
|
|
54
|
+
const totalTokens = response.usage?.total_tokens ?? (promptTokens + completionTokens);
|
|
55
|
+
usageTotals.inputTokens += promptTokens;
|
|
56
|
+
usageTotals.outputTokens += completionTokens;
|
|
57
|
+
usageTotals.totalTokens += totalTokens;
|
|
58
|
+
return response.choices[0]?.message?.content ?? "";
|
|
59
|
+
}
|
|
60
|
+
const transcript = buildTranscript(chunks);
|
|
61
|
+
// Single-pass threshold: ~100k tokens (≈ 400k chars).
|
|
62
|
+
const SINGLE_PASS_CHAR_LIMIT = 400000;
|
|
63
|
+
let digest;
|
|
64
|
+
let passes;
|
|
65
|
+
if (transcript.length <= SINGLE_PASS_CHAR_LIMIT) {
|
|
66
|
+
// Single pass: summarize the whole transcript at once.
|
|
67
|
+
digest = await runCompletion([
|
|
68
|
+
{ role: "system", content: MAP_SYSTEM_PROMPT },
|
|
69
|
+
{ role: "user", content: transcript },
|
|
70
|
+
], maxOutputTokens);
|
|
71
|
+
passes = 1;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Multi-pass: split into ~80k-token windows (~320k chars), map then reduce.
|
|
75
|
+
const WINDOW_CHARS = 320000;
|
|
76
|
+
const windows = splitIntoWindows(transcript, WINDOW_CHARS);
|
|
77
|
+
// Map phase: summarize each window independently.
|
|
78
|
+
const partials = [];
|
|
79
|
+
const perWindowTokens = Math.max(500, Math.ceil(maxOutputTokens / windows.length));
|
|
80
|
+
for (const window of windows) {
|
|
81
|
+
const partial = await runCompletion([
|
|
82
|
+
{ role: "system", content: MAP_SYSTEM_PROMPT },
|
|
83
|
+
{ role: "user", content: window },
|
|
84
|
+
], perWindowTokens);
|
|
85
|
+
partials.push(partial);
|
|
86
|
+
}
|
|
87
|
+
// Reduce phase: merge all partial summaries.
|
|
88
|
+
const combined = partials.join("\n\n---\n\n");
|
|
89
|
+
digest = await runCompletion([
|
|
90
|
+
{ role: "system", content: REDUCE_SYSTEM_PROMPT },
|
|
91
|
+
{ role: "user", content: combined },
|
|
92
|
+
], maxOutputTokens);
|
|
93
|
+
passes = windows.length + 1; // N map passes + 1 reduce pass
|
|
94
|
+
}
|
|
95
|
+
// Final formatting pass: structure the digest into a restart document.
|
|
96
|
+
const summary = await runCompletion([
|
|
97
|
+
{
|
|
98
|
+
role: "system",
|
|
99
|
+
content: finalSystemPrompt(maxOutputTokens),
|
|
100
|
+
},
|
|
101
|
+
{ role: "user", content: digest },
|
|
102
|
+
], maxOutputTokens);
|
|
103
|
+
passes += 1;
|
|
104
|
+
return { summary, model, passes, usage: usageTotals };
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Prompts
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
const MAP_SYSTEM_PROMPT = `\
|
|
110
|
+
You are summarizing a segment of an AI coding session transcript.
|
|
111
|
+
|
|
112
|
+
Extract a concise faithful digest that preserves, in chronological order:
|
|
113
|
+
- Key decisions made and their rationale
|
|
114
|
+
- Failed attempts and why they failed
|
|
115
|
+
- Constraints and requirements discovered during the session
|
|
116
|
+
- Code file paths, function names, and data structures mentioned
|
|
117
|
+
- Unresolved issues or open questions
|
|
118
|
+
|
|
119
|
+
Be concise and structured. Use bullet points. Preserve technical specifics.
|
|
120
|
+
Do NOT add opinions or filler. Only what's in the transcript.`;
|
|
121
|
+
const REDUCE_SYSTEM_PROMPT = `\
|
|
122
|
+
You are merging partial summaries of an AI coding session into a single coherent digest.
|
|
123
|
+
|
|
124
|
+
Combine the summaries into one continuous narrative that:
|
|
125
|
+
- Preserves chronological order
|
|
126
|
+
- Includes all unique key decisions and rationale
|
|
127
|
+
- Includes all failed attempts and lessons learned
|
|
128
|
+
- Includes all constraints and requirements
|
|
129
|
+
- Includes all code file paths, function names, and data structures
|
|
130
|
+
- Includes all unresolved issues and remaining work
|
|
131
|
+
|
|
132
|
+
Remove redundancy. Preserve all unique technical details.
|
|
133
|
+
Output bullet-point lists, not prose paragraphs.`;
|
|
134
|
+
function finalSystemPrompt(maxOutputTokens) {
|
|
135
|
+
return `\
|
|
136
|
+
You are creating a "session restart document" for an AI coding session.
|
|
137
|
+
|
|
138
|
+
Transform the session digest into a structured document with these sections:
|
|
139
|
+
|
|
140
|
+
## Context
|
|
141
|
+
What was being built or fixed, and why.
|
|
142
|
+
|
|
143
|
+
## Key Decisions
|
|
144
|
+
Architectural and implementation choices made during the session.
|
|
145
|
+
|
|
146
|
+
## Current State
|
|
147
|
+
What was completed, what is in progress, and what files/code exist now.
|
|
148
|
+
|
|
149
|
+
## Unresolved Issues
|
|
150
|
+
Blockers, open questions, or known bugs not yet fixed.
|
|
151
|
+
|
|
152
|
+
Keep the total output under ${maxOutputTokens} tokens. Be precise and actionable.
|
|
153
|
+
Preserve every technical detail (file paths, function names, error messages).`;
|
|
154
|
+
}
|
|
155
|
+
function supportsLowReasoningEffort(model) {
|
|
156
|
+
const normalized = model.toLowerCase();
|
|
157
|
+
return normalized.startsWith("gpt-5") || normalized.startsWith("o1") || normalized.startsWith("o3") || normalized.startsWith("o4");
|
|
158
|
+
}
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// Helpers
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
/**
|
|
163
|
+
* Builds a human-readable transcript from ordered chunk rows.
|
|
164
|
+
* Groups consecutive chunks with the same section label under a single header.
|
|
165
|
+
*/
|
|
166
|
+
function buildTranscript(chunks) {
|
|
167
|
+
if (chunks.length === 0)
|
|
168
|
+
return "";
|
|
169
|
+
const lines = [];
|
|
170
|
+
let lastSection = "";
|
|
171
|
+
for (const chunk of chunks) {
|
|
172
|
+
const section = chunk.section || "Unknown";
|
|
173
|
+
if (section !== lastSection) {
|
|
174
|
+
lines.push(`\n### ${section}`);
|
|
175
|
+
lastSection = section;
|
|
176
|
+
}
|
|
177
|
+
lines.push(chunk.content);
|
|
178
|
+
}
|
|
179
|
+
return lines.join("\n").trimStart();
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Splits `text` into windows of at most `windowChars` characters.
|
|
183
|
+
* Splits on newline boundaries when possible.
|
|
184
|
+
*/
|
|
185
|
+
function splitIntoWindows(text, windowChars) {
|
|
186
|
+
if (text.length <= windowChars)
|
|
187
|
+
return [text];
|
|
188
|
+
const windows = [];
|
|
189
|
+
let offset = 0;
|
|
190
|
+
while (offset < text.length) {
|
|
191
|
+
let end = Math.min(offset + windowChars, text.length);
|
|
192
|
+
// Try to find the last newline before the hard boundary.
|
|
193
|
+
if (end < text.length) {
|
|
194
|
+
const lastNl = text.lastIndexOf("\n", end);
|
|
195
|
+
if (lastNl > offset)
|
|
196
|
+
end = lastNl + 1;
|
|
197
|
+
}
|
|
198
|
+
windows.push(text.slice(offset, end));
|
|
199
|
+
offset = end;
|
|
200
|
+
}
|
|
201
|
+
return windows;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=session-compactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-compactor.js","sourceRoot":"","sources":["../../src/session-compactor.ts"],"names":[],"mappings":"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"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface DocumentChunk {
|
|
|
23
23
|
/**
|
|
24
24
|
* Which tool produced a session.
|
|
25
25
|
*/
|
|
26
|
-
export type SessionSource = "opencode" | "claude-code" | "cursor" | "vscode" | "codex";
|
|
26
|
+
export type SessionSource = "opencode" | "claude-code" | "cursor" | "vscode" | "codex" | "gemini-cli";
|
|
27
27
|
/**
|
|
28
28
|
* A row in the sessions_meta table — tracks per-session indexing progress.
|
|
29
29
|
*/
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,gHAAgH;QAChH,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,kFAAkF;QAClF,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-session-memory",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Automatically index OpenCode, Claude Code, Cursor, VS Code, and
|
|
3
|
+
"version": "0.12.0",
|
|
4
|
+
"description": "Automatically index OpenCode, Claude Code, Cursor, VS Code, Codex, and Gemini CLI sessions into a shared sqlite-vec vector database for semantic search across your AI coding history",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/src/indexer.js",
|
|
7
7
|
"types": "dist/src/indexer.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"skill/"
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "tsc && chmod 755 dist/src/cli.js dist/mcp/index.js dist/src/indexer-cli-vscode.js dist/src/indexer-cli-codex.js",
|
|
17
|
+
"build": "tsc && chmod 755 dist/src/cli.js dist/mcp/index.js dist/src/indexer-cli-vscode.js dist/src/indexer-cli-codex.js dist/src/indexer-cli-gemini.js",
|
|
18
18
|
"build:watch": "tsc --watch",
|
|
19
19
|
"start:mcp": "node dist/mcp/index.js",
|
|
20
20
|
"test": "vitest run",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"cursor",
|
|
30
30
|
"vscode",
|
|
31
31
|
"codex",
|
|
32
|
+
"gemini-cli",
|
|
32
33
|
"mcp",
|
|
33
34
|
"sqlite-vec",
|
|
34
35
|
"vector",
|
package/skill/memory.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Search past OpenCode, Claude Code, Cursor, VS Code, and
|
|
2
|
+
description: Search past OpenCode, Claude Code, Cursor, VS Code, Codex, and Gemini CLI sessions stored in the shared vector memory database
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# code-session-memory
|
|
6
6
|
|
|
7
|
-
You have access to an MCP server called `code-session-memory` that automatically indexes all your past coding sessions — from **OpenCode**, **Claude Code**, **Cursor**, **VS Code**, and **
|
|
7
|
+
You have access to an MCP server called `code-session-memory` that automatically indexes all your past coding sessions — from **OpenCode**, **Claude Code**, **Cursor**, **VS Code**, **Codex**, and **Gemini CLI** — into a single shared local vector database. Every time a session completes a turn, the new messages are embedded and stored, giving you a searchable memory of your entire AI coding history across all tools.
|
|
8
8
|
|
|
9
9
|
## Available tools
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ Semantically search across all indexed sessions to find past conversations, deci
|
|
|
15
15
|
**Parameters:**
|
|
16
16
|
- `queryText` *(required)*: A natural language description of what you are looking for.
|
|
17
17
|
- `project` *(optional)*: Filter results to a specific project directory path (e.g. `"/Users/me/myproject"`).
|
|
18
|
-
- `source` *(optional)*: Filter by tool — `"opencode"`, `"claude-code"`, `"cursor"`, `"vscode"`, or `"
|
|
18
|
+
- `source` *(optional)*: Filter by tool — `"opencode"`, `"claude-code"`, `"cursor"`, `"vscode"`, `"codex"`, or `"gemini-cli"`. Omit to search across all.
|
|
19
19
|
- `limit` *(optional, default 5)*: Number of results to return (1–20).
|
|
20
20
|
- `fromDate` *(optional)*: Return only chunks indexed on or after this date. ISO 8601, e.g. `"2026-02-01"` or `"2026-02-20T15:00:00Z"`.
|
|
21
21
|
- `toDate` *(optional)*: Return only chunks indexed on or before this date. ISO 8601, e.g. `"2026-02-20"`. Date-only values are treated as end-of-day UTC.
|
|
@@ -57,6 +57,9 @@ query_sessions("refactoring utils", source="vscode")
|
|
|
57
57
|
# Search only Codex sessions
|
|
58
58
|
query_sessions("openapi mock server", source="codex")
|
|
59
59
|
|
|
60
|
+
# Search only Gemini CLI sessions
|
|
61
|
+
query_sessions("hook payload format", source="gemini-cli")
|
|
62
|
+
|
|
60
63
|
# Search sessions from a specific date range
|
|
61
64
|
query_sessions("authentication middleware", fromDate="2026-02-01", toDate="2026-02-20")
|
|
62
65
|
|
|
@@ -66,7 +69,7 @@ get_session_chunks("session://ses_abc123#msg_def456")
|
|
|
66
69
|
|
|
67
70
|
## Notes
|
|
68
71
|
|
|
69
|
-
- Sessions from OpenCode, Claude Code, Cursor, VS Code, and
|
|
72
|
+
- Sessions from OpenCode, Claude Code, Cursor, VS Code, Codex, and Gemini CLI are indexed into the **same** database.
|
|
70
73
|
- Indexing is automatic — no manual action needed.
|
|
71
74
|
- The database lives at `~/.local/share/code-session-memory/sessions.db`.
|
|
72
75
|
- Embeddings use OpenAI `text-embedding-3-large` (3072 dimensions).
|