code-session-memory 0.4.4 → 0.7.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 +78 -58
- package/dist/mcp/index.js +23 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +4 -2
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +11 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/src/cli-sessions.d.ts +6 -7
- package/dist/src/cli-sessions.d.ts.map +1 -1
- package/dist/src/cli-sessions.js +238 -178
- package/dist/src/cli-sessions.js.map +1 -1
- package/dist/src/cli.js +272 -12
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cursor-to-messages.d.ts +64 -0
- package/dist/src/cursor-to-messages.d.ts.map +1 -0
- package/dist/src/cursor-to-messages.js +243 -0
- package/dist/src/cursor-to-messages.js.map +1 -0
- package/dist/src/cursor-transcript-to-messages.d.ts +22 -0
- package/dist/src/cursor-transcript-to-messages.d.ts.map +1 -0
- package/dist/src/cursor-transcript-to-messages.js +79 -0
- package/dist/src/cursor-transcript-to-messages.js.map +1 -0
- package/dist/src/database.d.ts +13 -2
- package/dist/src/database.d.ts.map +1 -1
- package/dist/src/database.js +42 -8
- package/dist/src/database.js.map +1 -1
- package/dist/src/indexer-cli-cursor.d.ts +25 -0
- package/dist/src/indexer-cli-cursor.d.ts.map +1 -0
- package/dist/src/indexer-cli-cursor.js +118 -0
- package/dist/src/indexer-cli-cursor.js.map +1 -0
- package/dist/src/indexer-cli.js +76 -6
- package/dist/src/indexer-cli.js.map +1 -1
- package/dist/src/indexer.d.ts.map +1 -1
- package/dist/src/indexer.js +46 -9
- package/dist/src/indexer.js.map +1 -1
- package/dist/src/opencode-db-to-messages.d.ts +30 -0
- package/dist/src/opencode-db-to-messages.d.ts.map +1 -0
- package/dist/src/opencode-db-to-messages.js +88 -0
- package/dist/src/opencode-db-to-messages.js.map +1 -0
- package/dist/src/types.d.ts +6 -1
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/plugin/memory.ts +9 -1
- package/skill/memory.md +7 -2
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reads a Cursor conversation from the SQLite state.vscdb and converts it
|
|
4
|
+
* to the FullMessage[] format used by the indexer.
|
|
5
|
+
*
|
|
6
|
+
* Cursor stores conversations in:
|
|
7
|
+
* ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
|
|
8
|
+
*
|
|
9
|
+
* Key namespaces used:
|
|
10
|
+
* composerData:<composerId> — session metadata + ordered bubble headers
|
|
11
|
+
* bubbleId:<composerId>:<bubbleId> — individual message bubbles
|
|
12
|
+
*
|
|
13
|
+
* Bubble types:
|
|
14
|
+
* type 1 — user message (field: text)
|
|
15
|
+
* type 2 — AI message (field: text, or toolFormerData for tool calls)
|
|
16
|
+
*
|
|
17
|
+
* Tool call bubbles have toolFormerData:
|
|
18
|
+
* { name, rawArgs (JSON string), result (JSON string), status }
|
|
19
|
+
*
|
|
20
|
+
* Empty AI bubbles (no text, no toolFormerData) are placeholder/streaming
|
|
21
|
+
* artifacts — we skip them.
|
|
22
|
+
*/
|
|
23
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
25
|
+
};
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.resolveCursorDbPath = resolveCursorDbPath;
|
|
28
|
+
exports.openCursorDb = openCursorDb;
|
|
29
|
+
exports.getComposerData = getComposerData;
|
|
30
|
+
exports.listComposerIds = listComposerIds;
|
|
31
|
+
exports.cursorSessionToMessages = cursorSessionToMessages;
|
|
32
|
+
exports.deriveCursorSessionTitle = deriveCursorSessionTitle;
|
|
33
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
34
|
+
const path_1 = __importDefault(require("path"));
|
|
35
|
+
const os_1 = __importDefault(require("os"));
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// DB path resolution
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
function resolveCursorDbPath() {
|
|
40
|
+
switch (process.platform) {
|
|
41
|
+
case "darwin":
|
|
42
|
+
return path_1.default.join(os_1.default.homedir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
43
|
+
case "linux":
|
|
44
|
+
return path_1.default.join(os_1.default.homedir(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
45
|
+
case "win32":
|
|
46
|
+
return path_1.default.join(process.env.APPDATA ?? os_1.default.homedir(), "Cursor", "User", "globalStorage", "state.vscdb");
|
|
47
|
+
default:
|
|
48
|
+
throw new Error(`Unsupported platform for Cursor: ${process.platform}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Cursor DB reader
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
/**
|
|
55
|
+
* Opens the Cursor state.vscdb in read-only mode and returns a wrapper.
|
|
56
|
+
* The caller must call close() when done.
|
|
57
|
+
*/
|
|
58
|
+
function openCursorDb(dbPath) {
|
|
59
|
+
const resolved = dbPath ?? resolveCursorDbPath();
|
|
60
|
+
// Open read-only — we never write to Cursor's DB
|
|
61
|
+
return new better_sqlite3_1.default(resolved, { readonly: true, fileMustExist: true });
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Reads composer metadata for a given composerId.
|
|
65
|
+
*/
|
|
66
|
+
function getComposerData(db, composerId) {
|
|
67
|
+
const row = db
|
|
68
|
+
.prepare("SELECT value FROM cursorDiskKV WHERE key = ?")
|
|
69
|
+
.get(`composerData:${composerId}`);
|
|
70
|
+
if (!row)
|
|
71
|
+
return null;
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(row.value);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reads a single bubble by composerId + bubbleId.
|
|
81
|
+
*/
|
|
82
|
+
function getBubble(db, composerId, bubbleId) {
|
|
83
|
+
const row = db
|
|
84
|
+
.prepare("SELECT value FROM cursorDiskKV WHERE key = ?")
|
|
85
|
+
.get(`bubbleId:${composerId}:${bubbleId}`);
|
|
86
|
+
if (!row)
|
|
87
|
+
return null;
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(row.value);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Lists all composerIds in the DB, ordered by most-recently-updated first.
|
|
97
|
+
* Used by the incremental indexer to find new/updated sessions.
|
|
98
|
+
*/
|
|
99
|
+
function listComposerIds(db) {
|
|
100
|
+
const rows = db
|
|
101
|
+
.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%' ORDER BY rowid DESC")
|
|
102
|
+
.all();
|
|
103
|
+
return rows.map((r) => r.key.replace("composerData:", ""));
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Bubble → FullMessage conversion
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
function convertUserBubble(bubble) {
|
|
109
|
+
const text = (bubble.text ?? "").trim();
|
|
110
|
+
if (!text)
|
|
111
|
+
return null;
|
|
112
|
+
return {
|
|
113
|
+
info: {
|
|
114
|
+
id: bubble.bubbleId,
|
|
115
|
+
role: "user",
|
|
116
|
+
time: bubble.createdAt
|
|
117
|
+
? { created: new Date(bubble.createdAt).getTime() }
|
|
118
|
+
: {},
|
|
119
|
+
},
|
|
120
|
+
parts: [{ type: "text", text }],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function convertAiBubble(bubble) {
|
|
124
|
+
// Skip thinking bubbles
|
|
125
|
+
if (bubble.isThought)
|
|
126
|
+
return null;
|
|
127
|
+
const parts = [];
|
|
128
|
+
const tf = bubble.toolFormerData;
|
|
129
|
+
if (tf?.name) {
|
|
130
|
+
// Tool call bubble
|
|
131
|
+
let args;
|
|
132
|
+
try {
|
|
133
|
+
args = tf.rawArgs ? JSON.parse(tf.rawArgs) : undefined;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
args = tf.rawArgs;
|
|
137
|
+
}
|
|
138
|
+
let result;
|
|
139
|
+
try {
|
|
140
|
+
result = tf.result ? JSON.parse(tf.result) : undefined;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
result = tf.result;
|
|
144
|
+
}
|
|
145
|
+
// Extract a readable result string
|
|
146
|
+
let resultText;
|
|
147
|
+
if (result !== undefined) {
|
|
148
|
+
if (typeof result === "string") {
|
|
149
|
+
resultText = result;
|
|
150
|
+
}
|
|
151
|
+
else if (result &&
|
|
152
|
+
typeof result === "object" &&
|
|
153
|
+
"contents" in result &&
|
|
154
|
+
typeof result.contents === "string") {
|
|
155
|
+
resultText = result.contents;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
resultText = JSON.stringify(result, null, 2);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const state = tf.status === "completed" ? "result" : "call";
|
|
162
|
+
parts.push({
|
|
163
|
+
type: "tool-invocation",
|
|
164
|
+
toolName: tf.name,
|
|
165
|
+
toolCallId: tf.toolCallId ?? bubble.bubbleId,
|
|
166
|
+
state,
|
|
167
|
+
args,
|
|
168
|
+
result: state === "result" ? (resultText ?? "(no output)") : undefined,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// Text bubble
|
|
173
|
+
const text = (bubble.text ?? "").trim();
|
|
174
|
+
if (!text)
|
|
175
|
+
return null;
|
|
176
|
+
parts.push({ type: "text", text });
|
|
177
|
+
}
|
|
178
|
+
if (parts.length === 0)
|
|
179
|
+
return null;
|
|
180
|
+
return {
|
|
181
|
+
info: {
|
|
182
|
+
id: bubble.bubbleId,
|
|
183
|
+
role: "assistant",
|
|
184
|
+
time: bubble.createdAt
|
|
185
|
+
? { created: new Date(bubble.createdAt).getTime() }
|
|
186
|
+
: {},
|
|
187
|
+
},
|
|
188
|
+
parts,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Public API
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
/**
|
|
195
|
+
* Reads all messages for a Cursor conversation from the DB and converts them
|
|
196
|
+
* to FullMessage[]. Preserves the order defined by fullConversationHeadersOnly.
|
|
197
|
+
*
|
|
198
|
+
* @param db Open Cursor state.vscdb connection
|
|
199
|
+
* @param composerId The conversation ID (same as conversation_id in hook payload)
|
|
200
|
+
*/
|
|
201
|
+
function cursorSessionToMessages(db, composerId) {
|
|
202
|
+
const composer = getComposerData(db, composerId);
|
|
203
|
+
if (!composer)
|
|
204
|
+
return [];
|
|
205
|
+
const headers = composer.fullConversationHeadersOnly ?? [];
|
|
206
|
+
const messages = [];
|
|
207
|
+
for (const header of headers) {
|
|
208
|
+
const bubble = getBubble(db, composerId, header.bubbleId);
|
|
209
|
+
if (!bubble)
|
|
210
|
+
continue;
|
|
211
|
+
let msg = null;
|
|
212
|
+
if (bubble.type === 1) {
|
|
213
|
+
msg = convertUserBubble(bubble);
|
|
214
|
+
}
|
|
215
|
+
else if (bubble.type === 2) {
|
|
216
|
+
msg = convertAiBubble(bubble);
|
|
217
|
+
}
|
|
218
|
+
if (msg)
|
|
219
|
+
messages.push(msg);
|
|
220
|
+
}
|
|
221
|
+
return messages;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Derives a session title from the first user message text.
|
|
225
|
+
*/
|
|
226
|
+
function deriveCursorSessionTitle(composer, messages) {
|
|
227
|
+
// Use the composer name if it was set by Cursor
|
|
228
|
+
if (composer.name && composer.name.trim()) {
|
|
229
|
+
return composer.name.trim().slice(0, 80);
|
|
230
|
+
}
|
|
231
|
+
// Fall back to first user message text
|
|
232
|
+
for (const msg of messages) {
|
|
233
|
+
if (msg.info.role !== "user")
|
|
234
|
+
continue;
|
|
235
|
+
for (const part of msg.parts) {
|
|
236
|
+
if (part.type === "text" && part.text) {
|
|
237
|
+
return part.text.replace(/\s+/g, " ").trim().slice(0, 80);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return "Cursor Session";
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=cursor-to-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-to-messages.js","sourceRoot":"","sources":["../../src/cursor-to-messages.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;AA+CH,kDAgCC;AAUD,oCAIC;AAKD,0CAaC;AAyBD,0CAQC;AAwGD,0DAyBC;AAKD,4DAkBC;AAtSD,oEAAsC;AACtC,gDAAwB;AACxB,4CAAoB;AAuCpB,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,SAAgB,mBAAmB;IACjC,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,cAAI,CAAC,IAAI,CACd,YAAE,CAAC,OAAO,EAAE,EACZ,SAAS,EACT,qBAAqB,EACrB,QAAQ,EACR,MAAM,EACN,eAAe,EACf,aAAa,CACd,CAAC;QACJ,KAAK,OAAO;YACV,OAAO,cAAI,CAAC,IAAI,CACd,YAAE,CAAC,OAAO,EAAE,EACZ,SAAS,EACT,QAAQ,EACR,MAAM,EACN,eAAe,EACf,aAAa,CACd,CAAC;QACJ,KAAK,OAAO;YACV,OAAO,cAAI,CAAC,IAAI,CACd,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,YAAE,CAAC,OAAO,EAAE,EACnC,QAAQ,EACR,MAAM,EACN,eAAe,EACf,aAAa,CACd,CAAC;QACJ;YACE,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;GAGG;AACH,SAAgB,YAAY,CAAC,MAAe;IAC1C,MAAM,QAAQ,GAAG,MAAM,IAAI,mBAAmB,EAAE,CAAC;IACjD,iDAAiD;IACjD,OAAO,IAAI,wBAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AACzE,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe,CAC7B,EAAqB,EACrB,UAAkB;IAElB,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,8CAA8C,CAAC;SACvD,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAkC,CAAC;IACtE,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAiB,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAChB,EAAqB,EACrB,UAAkB,EAClB,QAAgB;IAEhB,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,8CAA8C,CAAC;SACvD,GAAG,CAAC,YAAY,UAAU,IAAI,QAAQ,EAAE,CAAkC,CAAC;IAC9E,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAiB,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,EAAqB;IACnD,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN,yFAAyF,CAC1F;SACA,GAAG,EAA2C,CAAC;IAElD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E,SAAS,iBAAiB,CAAC,MAAoB;IAC7C,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO;QACL,IAAI,EAAE;YACJ,EAAE,EAAE,MAAM,CAAC,QAAQ;YACnB,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM,CAAC,SAAS;gBACpB,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE;gBACnD,CAAC,CAAC,EAAE;SACP;QACD,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAAoB;IAC3C,wBAAwB;IACxB,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC;IAEjC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC;QACb,mBAAmB;QACnB,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;QACpB,CAAC;QAED,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;QACrB,CAAC;QAED,mCAAmC;QACnC,IAAI,UAA8B,CAAC;QACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,UAAU,GAAG,MAAM,CAAC;YACtB,CAAC;iBAAM,IACL,MAAM;gBACN,OAAO,MAAM,KAAK,QAAQ;gBAC1B,UAAU,IAAI,MAAM;gBACpB,OAAQ,MAAkC,CAAC,QAAQ,KAAK,QAAQ,EAChE,CAAC;gBACD,UAAU,GAAI,MAAkC,CAAC,QAAkB,CAAC;YACtE,CAAC;iBAAM,CAAC;gBACN,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAE5D,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,iBAAiB;YACvB,QAAQ,EAAE,EAAE,CAAC,IAAI;YACjB,UAAU,EAAE,EAAE,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ;YAC5C,KAAK;YACL,IAAI;YACJ,MAAM,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS;SACvE,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,cAAc;QACd,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,OAAO;QACL,IAAI,EAAE;YACJ,EAAE,EAAE,MAAM,CAAC,QAAQ;YACnB,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,MAAM,CAAC,SAAS;gBACpB,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE;gBACnD,CAAC,CAAC,EAAE;SACP;QACD,KAAK;KACN,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;GAMG;AACH,SAAgB,uBAAuB,CACrC,EAAqB,EACrB,UAAkB;IAElB,MAAM,QAAQ,GAAG,eAAe,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEzB,MAAM,OAAO,GAAG,QAAQ,CAAC,2BAA2B,IAAI,EAAE,CAAC;IAC3D,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM;YAAE,SAAS;QAEtB,IAAI,GAAG,GAAuB,IAAI,CAAC;QACnC,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACtB,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,GAAG;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAgB,wBAAwB,CACtC,QAAsB,EACtB,QAAuB;IAEvB,gDAAgD;IAChD,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1C,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,uCAAuC;IACvC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QACvC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACtC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a Cursor agent transcript JSONL file into FullMessage[].
|
|
3
|
+
*
|
|
4
|
+
* Cursor writes the transcript to disk BEFORE firing the stop hook, so this
|
|
5
|
+
* file is always complete and consistent — unlike state.vscdb which is written
|
|
6
|
+
* asynchronously and may lag behind the hook by several seconds.
|
|
7
|
+
*
|
|
8
|
+
* Transcript format (one JSON object per line):
|
|
9
|
+
* { "role": "user" | "assistant", "message": { "content": [{ "type": "text", "text": "..." }] } }
|
|
10
|
+
*
|
|
11
|
+
* Message IDs are derived as "<composerId>-<lineIndex>" since the JSONL has no
|
|
12
|
+
* bubble IDs. These are stable: line order never changes (only appended).
|
|
13
|
+
*/
|
|
14
|
+
import type { FullMessage } from "./types";
|
|
15
|
+
/**
|
|
16
|
+
* Reads a Cursor transcript JSONL and returns FullMessage[].
|
|
17
|
+
*
|
|
18
|
+
* @param transcriptPath Absolute path to the .jsonl file
|
|
19
|
+
* @param composerId Used to derive stable per-message IDs
|
|
20
|
+
*/
|
|
21
|
+
export declare function cursorTranscriptToMessages(transcriptPath: string, composerId: string): FullMessage[];
|
|
22
|
+
//# sourceMappingURL=cursor-transcript-to-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-transcript-to-messages.d.ts","sourceRoot":"","sources":["../../src/cursor-transcript-to-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAsB3C;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,GACjB,WAAW,EAAE,CAoDf"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Parses a Cursor agent transcript JSONL file into FullMessage[].
|
|
4
|
+
*
|
|
5
|
+
* Cursor writes the transcript to disk BEFORE firing the stop hook, so this
|
|
6
|
+
* file is always complete and consistent — unlike state.vscdb which is written
|
|
7
|
+
* asynchronously and may lag behind the hook by several seconds.
|
|
8
|
+
*
|
|
9
|
+
* Transcript format (one JSON object per line):
|
|
10
|
+
* { "role": "user" | "assistant", "message": { "content": [{ "type": "text", "text": "..." }] } }
|
|
11
|
+
*
|
|
12
|
+
* Message IDs are derived as "<composerId>-<lineIndex>" since the JSONL has no
|
|
13
|
+
* bubble IDs. These are stable: line order never changes (only appended).
|
|
14
|
+
*/
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.cursorTranscriptToMessages = cursorTranscriptToMessages;
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Parser
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* Reads a Cursor transcript JSONL and returns FullMessage[].
|
|
26
|
+
*
|
|
27
|
+
* @param transcriptPath Absolute path to the .jsonl file
|
|
28
|
+
* @param composerId Used to derive stable per-message IDs
|
|
29
|
+
*/
|
|
30
|
+
function cursorTranscriptToMessages(transcriptPath, composerId) {
|
|
31
|
+
let raw;
|
|
32
|
+
try {
|
|
33
|
+
raw = fs_1.default.readFileSync(transcriptPath, "utf8");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
39
|
+
const messages = [];
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
let entry;
|
|
42
|
+
try {
|
|
43
|
+
entry = JSON.parse(lines[i]);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const { role, message } = entry;
|
|
49
|
+
if (role !== "user" && role !== "assistant")
|
|
50
|
+
continue;
|
|
51
|
+
// Extract plain text from content
|
|
52
|
+
const content = message?.content;
|
|
53
|
+
let text = "";
|
|
54
|
+
if (typeof content === "string") {
|
|
55
|
+
text = content;
|
|
56
|
+
}
|
|
57
|
+
else if (Array.isArray(content)) {
|
|
58
|
+
text = content
|
|
59
|
+
.filter((p) => p.type === "text" && p.text)
|
|
60
|
+
.map((p) => p.text)
|
|
61
|
+
.join("\n");
|
|
62
|
+
}
|
|
63
|
+
// Strip Cursor's <user_query> wrapper tags
|
|
64
|
+
text = text
|
|
65
|
+
.replace(/^<user_query>\s*/i, "")
|
|
66
|
+
.replace(/\s*<\/user_query>$/i, "")
|
|
67
|
+
.trim();
|
|
68
|
+
if (!text)
|
|
69
|
+
continue;
|
|
70
|
+
// Stable ID: composerId + line index
|
|
71
|
+
const id = `${composerId}-${i}`;
|
|
72
|
+
messages.push({
|
|
73
|
+
info: { id, role },
|
|
74
|
+
parts: [{ type: "text", text }],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return messages;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=cursor-transcript-to-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-transcript-to-messages.js","sourceRoot":"","sources":["../../src/cursor-transcript-to-messages.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;AA+BH,gEAuDC;AApFD,4CAAoB;AAmBpB,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAE9E;;;;;GAKG;AACH,SAAgB,0BAA0B,CACxC,cAAsB,EACtB,UAAkB;IAElB,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,KAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAoB,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QAChC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW;YAAE,SAAS;QAEtD,kCAAkC;QAClC,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC;QACjC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,GAAG,OAAO,CAAC;QACjB,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,IAAI,GAAG,OAAO;iBACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC;iBAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAK,CAAC;iBACnB,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;QAED,2CAA2C;QAC3C,IAAI,GAAG,IAAI;aACR,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;aAChC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC;aAClC,IAAI,EAAE,CAAC;QAEV,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,qCAAqC;QACrC,MAAM,EAAE,GAAG,GAAG,UAAU,IAAI,CAAC,EAAE,CAAC;QAEhC,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;YAClB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/src/database.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare function upsertSessionMeta(db: Database, meta: SessionMeta): void
|
|
|
40
40
|
* Chunks with duplicate chunk_ids are silently skipped (IGNORE conflict).
|
|
41
41
|
*/
|
|
42
42
|
export declare function insertChunks(db: Database, chunks: DocumentChunk[], embeddings: number[][]): void;
|
|
43
|
-
export declare function queryByEmbedding(db: Database, queryEmbedding: number[], topK?: number, projectFilter?: string, sourceFilter?: SessionSource): QueryResult[];
|
|
43
|
+
export declare function queryByEmbedding(db: Database, queryEmbedding: number[], topK?: number, projectFilter?: string, sourceFilter?: SessionSource, fromMs?: number, toMs?: number): QueryResult[];
|
|
44
44
|
export declare function getChunksByUrl(db: Database, url: string, startIndex?: number, endIndex?: number): QueryResult[];
|
|
45
45
|
/**
|
|
46
46
|
* Lists all session URLs stored in the DB (for "get_session_chunks" calls that
|
|
@@ -70,7 +70,10 @@ export interface ChunkRow {
|
|
|
70
70
|
url: string;
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
|
-
* Returns all chunks for a session ordered by chunk_index ASC.
|
|
73
|
+
* Returns all chunks for a session ordered by message_order ASC, chunk_index ASC.
|
|
74
|
+
* message_order is the 0-based position of the message within the session at
|
|
75
|
+
* index time — stable and source-agnostic (works for OpenCode, Claude Code,
|
|
76
|
+
* and Cursor whose message IDs are not guaranteed to sort chronologically).
|
|
74
77
|
*/
|
|
75
78
|
export declare function getSessionChunksOrdered(db: Database, sessionId: string): ChunkRow[];
|
|
76
79
|
/**
|
|
@@ -78,4 +81,12 @@ export declare function getSessionChunksOrdered(db: Database, sessionId: string)
|
|
|
78
81
|
* Returns the number of chunks deleted.
|
|
79
82
|
*/
|
|
80
83
|
export declare function deleteSession(db: Database, sessionId: string): number;
|
|
84
|
+
/**
|
|
85
|
+
* Deletes all sessions last updated before `olderThanMs` (unix milliseconds).
|
|
86
|
+
* Returns the number of sessions and chunks removed.
|
|
87
|
+
*/
|
|
88
|
+
export declare function deleteSessionsOlderThan(db: Database, olderThanMs: number): {
|
|
89
|
+
sessions: number;
|
|
90
|
+
chunks: number;
|
|
91
|
+
};
|
|
81
92
|
//# sourceMappingURL=database.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAQtG;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAS3D;AAMD,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IACpC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IAC9D,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACnF,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IACrC,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC;CACxC;AAkBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CAgB7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,kBAAkB,SAA8B,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":"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"}
|
package/dist/src/database.js
CHANGED
|
@@ -15,6 +15,7 @@ exports.listSessionUrls = listSessionUrls;
|
|
|
15
15
|
exports.listSessions = listSessions;
|
|
16
16
|
exports.getSessionChunksOrdered = getSessionChunksOrdered;
|
|
17
17
|
exports.deleteSession = deleteSession;
|
|
18
|
+
exports.deleteSessionsOlderThan = deleteSessionsOlderThan;
|
|
18
19
|
const path_1 = __importDefault(require("path"));
|
|
19
20
|
const os_1 = __importDefault(require("os"));
|
|
20
21
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -88,7 +89,9 @@ function initSchema(db, embeddingDimension = DEFAULT_EMBEDDING_DIMENSION) {
|
|
|
88
89
|
url TEXT,
|
|
89
90
|
hash TEXT,
|
|
90
91
|
chunk_index INTEGER,
|
|
91
|
-
total_chunks INTEGER
|
|
92
|
+
total_chunks INTEGER,
|
|
93
|
+
message_order INTEGER,
|
|
94
|
+
created_at INTEGER
|
|
92
95
|
);
|
|
93
96
|
`);
|
|
94
97
|
// Metadata table for tracking incremental indexing progress
|
|
@@ -148,11 +151,11 @@ function insertChunks(db, chunks, embeddings) {
|
|
|
148
151
|
INSERT INTO vec_items (
|
|
149
152
|
embedding, session_id, session_title, project,
|
|
150
153
|
heading_hierarchy, section, chunk_id, content, url, hash,
|
|
151
|
-
chunk_index, total_chunks
|
|
154
|
+
chunk_index, total_chunks, message_order, created_at
|
|
152
155
|
) VALUES (
|
|
153
156
|
?, ?, ?, ?,
|
|
154
157
|
?, ?, ?, ?, ?, ?,
|
|
155
|
-
?, ?
|
|
158
|
+
?, ?, ?, ?
|
|
156
159
|
)
|
|
157
160
|
`);
|
|
158
161
|
// sqlite-vec does not enforce UNIQUE constraints via INSERT OR IGNORE on
|
|
@@ -165,7 +168,7 @@ function insertChunks(db, chunks, embeddings) {
|
|
|
165
168
|
// Skip if chunk already exists (idempotent indexing)
|
|
166
169
|
if (exists.get(m.chunk_id))
|
|
167
170
|
continue;
|
|
168
|
-
insert.run(new Float32Array(embedding), m.session_id, m.session_title, m.project, JSON.stringify(m.heading_hierarchy), m.section, m.chunk_id, chunk.content, m.url, m.hash, BigInt(m.chunk_index), BigInt(m.total_chunks));
|
|
171
|
+
insert.run(new Float32Array(embedding), m.session_id, m.session_title, m.project, JSON.stringify(m.heading_hierarchy), m.section, m.chunk_id, chunk.content, m.url, m.hash, BigInt(m.chunk_index), BigInt(m.total_chunks), BigInt(m.message_order ?? 0), BigInt(m.created_at ?? Date.now()));
|
|
169
172
|
}
|
|
170
173
|
});
|
|
171
174
|
insertMany(chunks.map((chunk, i) => ({ chunk, embedding: embeddings[i] })));
|
|
@@ -173,7 +176,7 @@ function insertChunks(db, chunks, embeddings) {
|
|
|
173
176
|
// ---------------------------------------------------------------------------
|
|
174
177
|
// Query helpers (used by MCP server)
|
|
175
178
|
// ---------------------------------------------------------------------------
|
|
176
|
-
function queryByEmbedding(db, queryEmbedding, topK = 10, projectFilter, sourceFilter) {
|
|
179
|
+
function queryByEmbedding(db, queryEmbedding, topK = 10, projectFilter, sourceFilter, fromMs, toMs) {
|
|
177
180
|
// sqlite-vec requires the LIMIT (k) constraint to be part of the KNN WHERE
|
|
178
181
|
// clause. We use a CTE to perform the KNN first, then join sessions_meta for
|
|
179
182
|
// the source column and apply optional post-filters.
|
|
@@ -182,7 +185,7 @@ function queryByEmbedding(db, queryEmbedding, topK = 10, projectFilter, sourceFi
|
|
|
182
185
|
SELECT
|
|
183
186
|
chunk_id, content, url, section, heading_hierarchy,
|
|
184
187
|
chunk_index, total_chunks, session_id, session_title, project,
|
|
185
|
-
distance
|
|
188
|
+
distance, created_at
|
|
186
189
|
FROM vec_items
|
|
187
190
|
WHERE embedding MATCH ?
|
|
188
191
|
AND k = ?
|
|
@@ -201,6 +204,14 @@ function queryByEmbedding(db, queryEmbedding, topK = 10, projectFilter, sourceFi
|
|
|
201
204
|
sql += " AND m.source = ?";
|
|
202
205
|
params.push(sourceFilter);
|
|
203
206
|
}
|
|
207
|
+
if (typeof fromMs === "number") {
|
|
208
|
+
sql += " AND knn.created_at >= ?";
|
|
209
|
+
params.push(BigInt(fromMs));
|
|
210
|
+
}
|
|
211
|
+
if (typeof toMs === "number") {
|
|
212
|
+
sql += " AND knn.created_at <= ?";
|
|
213
|
+
params.push(BigInt(toMs));
|
|
214
|
+
}
|
|
204
215
|
sql += " ORDER BY distance";
|
|
205
216
|
const rows = db.prepare(sql).all(...params);
|
|
206
217
|
// Strip raw embedding bytes from results
|
|
@@ -273,14 +284,17 @@ function listSessions(db, filter = {}) {
|
|
|
273
284
|
return db.prepare(sql).all(...params);
|
|
274
285
|
}
|
|
275
286
|
/**
|
|
276
|
-
* Returns all chunks for a session ordered by chunk_index ASC.
|
|
287
|
+
* Returns all chunks for a session ordered by message_order ASC, chunk_index ASC.
|
|
288
|
+
* message_order is the 0-based position of the message within the session at
|
|
289
|
+
* index time — stable and source-agnostic (works for OpenCode, Claude Code,
|
|
290
|
+
* and Cursor whose message IDs are not guaranteed to sort chronologically).
|
|
277
291
|
*/
|
|
278
292
|
function getSessionChunksOrdered(db, sessionId) {
|
|
279
293
|
return db.prepare(`
|
|
280
294
|
SELECT chunk_id, chunk_index, total_chunks, section, heading_hierarchy, content, url
|
|
281
295
|
FROM vec_items
|
|
282
296
|
WHERE session_id = ?
|
|
283
|
-
ORDER BY chunk_index ASC
|
|
297
|
+
ORDER BY message_order ASC, chunk_index ASC
|
|
284
298
|
`).all(sessionId);
|
|
285
299
|
}
|
|
286
300
|
/**
|
|
@@ -298,4 +312,24 @@ function deleteSession(db, sessionId) {
|
|
|
298
312
|
})();
|
|
299
313
|
return chunkCount;
|
|
300
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Deletes all sessions last updated before `olderThanMs` (unix milliseconds).
|
|
317
|
+
* Returns the number of sessions and chunks removed.
|
|
318
|
+
*/
|
|
319
|
+
function deleteSessionsOlderThan(db, olderThanMs) {
|
|
320
|
+
const candidates = listSessions(db, { toDate: olderThanMs });
|
|
321
|
+
if (candidates.length === 0)
|
|
322
|
+
return { sessions: 0, chunks: 0 };
|
|
323
|
+
const deleteChunks = db.prepare("DELETE FROM vec_items WHERE session_id = ?");
|
|
324
|
+
const deleteMeta = db.prepare("DELETE FROM sessions_meta WHERE session_id = ?");
|
|
325
|
+
let totalChunks = 0;
|
|
326
|
+
db.transaction(() => {
|
|
327
|
+
for (const s of candidates) {
|
|
328
|
+
const result = deleteChunks.run(s.session_id);
|
|
329
|
+
totalChunks += result.changes;
|
|
330
|
+
deleteMeta.run(s.session_id);
|
|
331
|
+
}
|
|
332
|
+
})();
|
|
333
|
+
return { sessions: candidates.length, chunks: totalChunks };
|
|
334
|
+
}
|
|
301
335
|
//# sourceMappingURL=database.js.map
|
package/dist/src/database.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":";;;;;AAiBA,sCASC;AAwCD,oCAgBC;AAMD,
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Entry point for Cursor session indexing.
|
|
4
|
+
*
|
|
5
|
+
* Called by the Cursor stop hook. Receives JSON on stdin:
|
|
6
|
+
* {
|
|
7
|
+
* conversation_id: string, // the composerId
|
|
8
|
+
* workspace_roots: string[], // project directories
|
|
9
|
+
* transcript_path: string, // path to the JSONL transcript (always complete)
|
|
10
|
+
* model: string,
|
|
11
|
+
* status: "completed" | "aborted" | "error",
|
|
12
|
+
* ...
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Strategy:
|
|
16
|
+
* - Read messages from transcript_path (JSONL written by Cursor before the
|
|
17
|
+
* hook fires — always complete and race-condition-free).
|
|
18
|
+
* - Read session title from state.vscdb (best-effort, falls back to first
|
|
19
|
+
* user message).
|
|
20
|
+
* - Index new messages into the shared sqlite-vec DB incrementally.
|
|
21
|
+
*
|
|
22
|
+
* No retries needed: the transcript file is the authoritative source.
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=indexer-cli-cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer-cli-cursor.d.ts","sourceRoot":"","sources":["../../src/indexer-cli-cursor.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|