heyiam 0.1.2 → 0.1.3
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/app/dist/assets/index-Cv-3KLuW.js +14 -0
- package/app/dist/index.html +1 -1
- package/dist/analyzer.d.ts +4 -0
- package/dist/analyzer.js +1 -0
- package/dist/analyzer.js.map +1 -1
- package/dist/bridge.js +23 -3
- package/dist/bridge.js.map +1 -1
- package/dist/llm/triage.d.ts +3 -2
- package/dist/llm/triage.js +56 -46
- package/dist/llm/triage.js.map +1 -1
- package/dist/parsers/codex.d.ts +8 -0
- package/dist/parsers/codex.js +301 -0
- package/dist/parsers/codex.js.map +1 -0
- package/dist/parsers/cursor.d.ts +89 -0
- package/dist/parsers/cursor.js +531 -0
- package/dist/parsers/cursor.js.map +1 -0
- package/dist/parsers/gemini.d.ts +28 -0
- package/dist/parsers/gemini.js +209 -0
- package/dist/parsers/gemini.js.map +1 -0
- package/dist/parsers/index.d.ts +30 -9
- package/dist/parsers/index.js +266 -12
- package/dist/parsers/index.js.map +1 -1
- package/dist/parsers/types.d.ts +2 -0
- package/dist/parsers/types.js +8 -1
- package/dist/parsers/types.js.map +1 -1
- package/dist/server.js +83 -6
- package/dist/server.js.map +1 -1
- package/package.json +10 -2
- package/app/dist/assets/index-CROJdbHw.js +0 -14
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { readdir, readFile, access } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { homedir, platform } from "node:os";
|
|
5
|
+
// --- Cursor tool name mapping ---
|
|
6
|
+
const CURSOR_TOOL_MAP = {
|
|
7
|
+
// Current Cursor tool names
|
|
8
|
+
read_file: "Read",
|
|
9
|
+
search_replace: "Edit",
|
|
10
|
+
write: "Write",
|
|
11
|
+
list_dir: "Glob",
|
|
12
|
+
grep: "Grep",
|
|
13
|
+
codebase_search: "Grep",
|
|
14
|
+
run_terminal_cmd: "Bash",
|
|
15
|
+
delete_file: "Bash",
|
|
16
|
+
// Older Cursor tool names (pre-2025)
|
|
17
|
+
edit_file: "Edit",
|
|
18
|
+
write_file: "Write",
|
|
19
|
+
create_file: "Write",
|
|
20
|
+
search_files: "Grep",
|
|
21
|
+
run_terminal_command: "Bash",
|
|
22
|
+
terminal: "Bash",
|
|
23
|
+
grep_search: "Grep",
|
|
24
|
+
file_search: "Glob",
|
|
25
|
+
};
|
|
26
|
+
function mapCursorToolName(name) {
|
|
27
|
+
return CURSOR_TOOL_MAP[name] ?? name;
|
|
28
|
+
}
|
|
29
|
+
// --- Path utilities ---
|
|
30
|
+
function getCursorGlobalDbPath() {
|
|
31
|
+
if (platform() === "darwin") {
|
|
32
|
+
return join(homedir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
33
|
+
}
|
|
34
|
+
else if (platform() === "win32") {
|
|
35
|
+
return join(homedir(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
36
|
+
}
|
|
37
|
+
// Linux
|
|
38
|
+
return join(homedir(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
39
|
+
}
|
|
40
|
+
function getCursorWorkspaceStoragePath() {
|
|
41
|
+
if (platform() === "darwin") {
|
|
42
|
+
return join(homedir(), "Library", "Application Support", "Cursor", "User", "workspaceStorage");
|
|
43
|
+
}
|
|
44
|
+
else if (platform() === "win32") {
|
|
45
|
+
return join(homedir(), "AppData", "Roaming", "Cursor", "User", "workspaceStorage");
|
|
46
|
+
}
|
|
47
|
+
return join(homedir(), ".config", "Cursor", "User", "workspaceStorage");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Scan Cursor's workspaceStorage to find all workspaces and their project directories.
|
|
51
|
+
*/
|
|
52
|
+
export async function discoverCursorWorkspaces() {
|
|
53
|
+
const wsBase = getCursorWorkspaceStoragePath();
|
|
54
|
+
const workspaces = [];
|
|
55
|
+
let dirs;
|
|
56
|
+
try {
|
|
57
|
+
dirs = await readdir(wsBase, { withFileTypes: true });
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return workspaces; // Cursor not installed or no workspace storage
|
|
61
|
+
}
|
|
62
|
+
for (const entry of dirs) {
|
|
63
|
+
if (!entry.isDirectory())
|
|
64
|
+
continue;
|
|
65
|
+
const wsDir = join(wsBase, entry.name);
|
|
66
|
+
const wsJsonPath = join(wsDir, "workspace.json");
|
|
67
|
+
const dbPath = join(wsDir, "state.vscdb");
|
|
68
|
+
try {
|
|
69
|
+
await access(dbPath);
|
|
70
|
+
const wsJson = JSON.parse(await readFile(wsJsonPath, "utf-8"));
|
|
71
|
+
if (!wsJson.folder)
|
|
72
|
+
continue;
|
|
73
|
+
// folder is "file:///Users/ben/Dev/heyi-am"
|
|
74
|
+
const projectDir = decodeURIComponent(new URL(wsJson.folder).pathname);
|
|
75
|
+
workspaces.push({
|
|
76
|
+
workspaceId: entry.name,
|
|
77
|
+
dbPath,
|
|
78
|
+
projectDir,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
continue; // Missing workspace.json or state.vscdb
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return workspaces;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* List all composer conversations in a workspace's state DB.
|
|
89
|
+
*/
|
|
90
|
+
export function listConversations(workspace) {
|
|
91
|
+
let db;
|
|
92
|
+
try {
|
|
93
|
+
db = new Database(workspace.dbPath, { readonly: true });
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const row = db.prepare("SELECT value FROM ItemTable WHERE [key] = ?")
|
|
100
|
+
.get("composer.composerData");
|
|
101
|
+
if (!row)
|
|
102
|
+
return [];
|
|
103
|
+
const data = JSON.parse(row.value);
|
|
104
|
+
return (data.allComposers ?? [])
|
|
105
|
+
.filter((c) => !c.isArchived)
|
|
106
|
+
.map((c) => ({
|
|
107
|
+
composerId: c.composerId,
|
|
108
|
+
name: c.name,
|
|
109
|
+
createdAt: c.createdAt,
|
|
110
|
+
lastUpdatedAt: c.lastUpdatedAt,
|
|
111
|
+
mode: c.unifiedMode,
|
|
112
|
+
totalLinesAdded: c.totalLinesAdded,
|
|
113
|
+
totalLinesRemoved: c.totalLinesRemoved,
|
|
114
|
+
workspace,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
db.close();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// --- Bubble (message) reading ---
|
|
125
|
+
/**
|
|
126
|
+
* Read all bubbles for a conversation from the global state DB.
|
|
127
|
+
*/
|
|
128
|
+
export function readBubbles(conversationId, globalDbPath) {
|
|
129
|
+
const dbPath = globalDbPath ?? getCursorGlobalDbPath();
|
|
130
|
+
let db;
|
|
131
|
+
try {
|
|
132
|
+
db = new Database(dbPath, { readonly: true });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const prefix = `bubbleId:${conversationId}:`;
|
|
139
|
+
const rows = db.prepare("SELECT value FROM cursorDiskKV WHERE [key] LIKE ? ORDER BY [key]").all(`${prefix}%`);
|
|
140
|
+
const bubbles = [];
|
|
141
|
+
for (const row of rows) {
|
|
142
|
+
try {
|
|
143
|
+
bubbles.push(JSON.parse(row.value));
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Skip unparseable blobs
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Sort by createdAt if available
|
|
150
|
+
bubbles.sort((a, b) => {
|
|
151
|
+
if (!a.createdAt || !b.createdAt)
|
|
152
|
+
return 0;
|
|
153
|
+
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
|
154
|
+
});
|
|
155
|
+
return bubbles;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
db.close();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// --- Bubble → SessionAnalysis conversion ---
|
|
165
|
+
function extractToolCallsFromBubbles(bubbles) {
|
|
166
|
+
const calls = [];
|
|
167
|
+
for (const bubble of bubbles) {
|
|
168
|
+
const tfd = bubble.toolFormerData;
|
|
169
|
+
if (!tfd?.name)
|
|
170
|
+
continue;
|
|
171
|
+
let input = {};
|
|
172
|
+
try {
|
|
173
|
+
if (tfd.rawArgs) {
|
|
174
|
+
input = JSON.parse(tfd.rawArgs);
|
|
175
|
+
}
|
|
176
|
+
else if (tfd.params) {
|
|
177
|
+
input = JSON.parse(tfd.params);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Malformed JSON
|
|
182
|
+
}
|
|
183
|
+
// Normalize field names to match Claude's convention
|
|
184
|
+
const normalizedInput = normalizeCursorToolInput(tfd.name, input);
|
|
185
|
+
calls.push({
|
|
186
|
+
id: tfd.toolCallId ?? bubble.bubbleId,
|
|
187
|
+
name: mapCursorToolName(tfd.name),
|
|
188
|
+
input: normalizedInput,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return calls;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Normalize Cursor's tool input fields to match Claude's conventions
|
|
195
|
+
* so downstream extractFilesTouched / computeLocStats work unchanged.
|
|
196
|
+
*/
|
|
197
|
+
function normalizeCursorToolInput(toolName, input) {
|
|
198
|
+
const normalized = { ...input };
|
|
199
|
+
// Cursor uses target_file / targetFile; Claude uses file_path
|
|
200
|
+
if (typeof normalized.target_file === "string") {
|
|
201
|
+
normalized.file_path = normalized.target_file;
|
|
202
|
+
}
|
|
203
|
+
else if (typeof normalized.targetFile === "string") {
|
|
204
|
+
normalized.file_path = normalized.targetFile;
|
|
205
|
+
}
|
|
206
|
+
// search_replace and edit_file: use old_string/new_string same as Claude — pass through
|
|
207
|
+
// write: Cursor uses "contents" (plural); Claude uses "content" (singular)
|
|
208
|
+
if (typeof normalized.contents === "string" && !normalized.content) {
|
|
209
|
+
normalized.content = normalized.contents;
|
|
210
|
+
}
|
|
211
|
+
// create_file: Cursor uses "file_text"
|
|
212
|
+
if (toolName === "create_file" && typeof normalized.file_text === "string") {
|
|
213
|
+
normalized.content = normalized.file_text;
|
|
214
|
+
}
|
|
215
|
+
// For search: Cursor uses "query" or "pattern"; Claude uses "path"
|
|
216
|
+
if (toolName === "list_dir" && typeof normalized.relative_workspace_path === "string") {
|
|
217
|
+
normalized.path = normalized.relative_workspace_path;
|
|
218
|
+
}
|
|
219
|
+
return normalized;
|
|
220
|
+
}
|
|
221
|
+
function extractFilesFromBubbles(bubbles) {
|
|
222
|
+
const files = new Set();
|
|
223
|
+
for (const bubble of bubbles) {
|
|
224
|
+
// From codeBlocks
|
|
225
|
+
if (bubble.codeBlocks) {
|
|
226
|
+
for (const cb of bubble.codeBlocks) {
|
|
227
|
+
const path = cb.uri?.path ?? cb.uri?._fsPath;
|
|
228
|
+
if (path)
|
|
229
|
+
files.add(path);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// From toolFormerData
|
|
233
|
+
const tfd = bubble.toolFormerData;
|
|
234
|
+
if (tfd?.name) {
|
|
235
|
+
try {
|
|
236
|
+
const args = tfd.rawArgs ? JSON.parse(tfd.rawArgs) : {};
|
|
237
|
+
const target = args.target_file ?? args.targetFile;
|
|
238
|
+
if (typeof target === "string")
|
|
239
|
+
files.add(target);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Skip
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// From context file selections
|
|
246
|
+
if (bubble.context?.fileSelections) {
|
|
247
|
+
for (const fs of bubble.context.fileSelections) {
|
|
248
|
+
if (fs.uri?.path)
|
|
249
|
+
files.add(fs.uri.path);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return [...files].sort();
|
|
254
|
+
}
|
|
255
|
+
function countTurnsFromBubbles(bubbles) {
|
|
256
|
+
let turns = 0;
|
|
257
|
+
let lastType = null;
|
|
258
|
+
for (const bubble of bubbles) {
|
|
259
|
+
// type 1 = user, type 2 = AI
|
|
260
|
+
if (bubble.type === 2 && lastType === 1) {
|
|
261
|
+
turns++;
|
|
262
|
+
}
|
|
263
|
+
if (bubble.type === 1 || bubble.type === 2) {
|
|
264
|
+
lastType = bubble.type;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return turns;
|
|
268
|
+
}
|
|
269
|
+
const IDLE_THRESHOLD_MS = 5 * 60 * 1000;
|
|
270
|
+
function computeDurationFromBubbles(bubbles) {
|
|
271
|
+
const timestamps = [];
|
|
272
|
+
let startStr = null;
|
|
273
|
+
let endStr = null;
|
|
274
|
+
for (const bubble of bubbles) {
|
|
275
|
+
if (!bubble.createdAt)
|
|
276
|
+
continue;
|
|
277
|
+
if (!startStr)
|
|
278
|
+
startStr = bubble.createdAt;
|
|
279
|
+
endStr = bubble.createdAt;
|
|
280
|
+
timestamps.push(new Date(bubble.createdAt).getTime());
|
|
281
|
+
}
|
|
282
|
+
if (timestamps.length < 2 || !startStr || !endStr) {
|
|
283
|
+
return { duration_ms: 0, wall_clock_ms: 0, start_time: startStr, end_time: endStr };
|
|
284
|
+
}
|
|
285
|
+
const wallClock = timestamps[timestamps.length - 1] - timestamps[0];
|
|
286
|
+
let activeMs = 0;
|
|
287
|
+
for (let i = 1; i < timestamps.length; i++) {
|
|
288
|
+
const gap = timestamps[i] - timestamps[i - 1];
|
|
289
|
+
if (gap < IDLE_THRESHOLD_MS) {
|
|
290
|
+
activeMs += gap;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
duration_ms: Math.max(activeMs, 0),
|
|
295
|
+
wall_clock_ms: Math.max(wallClock, 0),
|
|
296
|
+
start_time: startStr,
|
|
297
|
+
end_time: endStr,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/** Normalize a file path to a consistent absolute form for use as a map/set key. */
|
|
301
|
+
function normalizePath(p) {
|
|
302
|
+
return resolve(p);
|
|
303
|
+
}
|
|
304
|
+
function computeLocFromBubbles(bubbles) {
|
|
305
|
+
let totalAdded = 0;
|
|
306
|
+
let totalRemoved = 0;
|
|
307
|
+
const filesChanged = new Set();
|
|
308
|
+
const writeLineCounts = new Map();
|
|
309
|
+
for (const bubble of bubbles) {
|
|
310
|
+
const tfd = bubble.toolFormerData;
|
|
311
|
+
if (!tfd?.name)
|
|
312
|
+
continue;
|
|
313
|
+
const mappedName = mapCursorToolName(tfd.name);
|
|
314
|
+
let args = {};
|
|
315
|
+
try {
|
|
316
|
+
if (tfd.rawArgs)
|
|
317
|
+
args = JSON.parse(tfd.rawArgs);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
const rawPath = args.file_path ?? args.target_file ?? args.targetFile;
|
|
323
|
+
if (!rawPath)
|
|
324
|
+
continue;
|
|
325
|
+
const filePath = normalizePath(rawPath);
|
|
326
|
+
if (mappedName === "Write") {
|
|
327
|
+
const content = args.content ?? args.contents ?? args.file_text ?? "";
|
|
328
|
+
if (!content)
|
|
329
|
+
continue;
|
|
330
|
+
const lines = content.split("\n").length;
|
|
331
|
+
const prevLines = writeLineCounts.get(filePath) ?? 0;
|
|
332
|
+
if (writeLineCounts.has(filePath)) {
|
|
333
|
+
totalAdded -= prevLines;
|
|
334
|
+
}
|
|
335
|
+
totalAdded += lines;
|
|
336
|
+
writeLineCounts.set(filePath, lines);
|
|
337
|
+
filesChanged.add(filePath);
|
|
338
|
+
}
|
|
339
|
+
else if (mappedName === "Edit") {
|
|
340
|
+
const oldStr = args.old_string ?? "";
|
|
341
|
+
const newStr = args.new_string ?? args.new_str ?? "";
|
|
342
|
+
totalAdded += newStr ? newStr.split("\n").length : 0;
|
|
343
|
+
totalRemoved += oldStr ? oldStr.split("\n").length : 0;
|
|
344
|
+
filesChanged.add(filePath);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// Also count codeBlocks (AI-suggested file writes)
|
|
348
|
+
for (const bubble of bubbles) {
|
|
349
|
+
if (!bubble.codeBlocks)
|
|
350
|
+
continue;
|
|
351
|
+
for (const cb of bubble.codeBlocks) {
|
|
352
|
+
const rawPath = cb.uri?.path ?? cb.uri?._fsPath;
|
|
353
|
+
if (rawPath && cb.content) {
|
|
354
|
+
const cbPath = normalizePath(rawPath);
|
|
355
|
+
filesChanged.add(cbPath);
|
|
356
|
+
// Only count if not already tracked via tool calls
|
|
357
|
+
if (!writeLineCounts.has(cbPath)) {
|
|
358
|
+
totalAdded += cb.content.split("\n").length;
|
|
359
|
+
writeLineCounts.set(cbPath, cb.content.split("\n").length);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
loc_added: totalAdded,
|
|
366
|
+
loc_removed: totalRemoved,
|
|
367
|
+
loc_net: totalAdded - totalRemoved,
|
|
368
|
+
files_changed: [...filesChanged].sort(),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Convert Cursor bubbles into the same RawEntry[] format used by Claude parser.
|
|
373
|
+
* This allows downstream code (signal extraction, triage) to work unchanged.
|
|
374
|
+
*/
|
|
375
|
+
function bubblesToRawEntries(bubbles, conversationId) {
|
|
376
|
+
const entries = [];
|
|
377
|
+
for (const bubble of bubbles) {
|
|
378
|
+
const timestamp = bubble.createdAt ?? new Date().toISOString();
|
|
379
|
+
const contentBlocks = [];
|
|
380
|
+
if (bubble.text) {
|
|
381
|
+
contentBlocks.push({ type: "text", text: bubble.text });
|
|
382
|
+
}
|
|
383
|
+
if (bubble.thinking?.text) {
|
|
384
|
+
contentBlocks.push({ type: "thinking", thinking: bubble.thinking.text });
|
|
385
|
+
}
|
|
386
|
+
// Synthesize tool_use blocks from toolFormerData
|
|
387
|
+
if (bubble.toolFormerData?.name) {
|
|
388
|
+
const tfd = bubble.toolFormerData;
|
|
389
|
+
let input = {};
|
|
390
|
+
try {
|
|
391
|
+
if (tfd.rawArgs)
|
|
392
|
+
input = JSON.parse(tfd.rawArgs);
|
|
393
|
+
}
|
|
394
|
+
catch { /* skip */ }
|
|
395
|
+
contentBlocks.push({
|
|
396
|
+
type: "tool_use",
|
|
397
|
+
id: tfd.toolCallId ?? bubble.bubbleId,
|
|
398
|
+
name: mapCursorToolName(tfd.name),
|
|
399
|
+
input: normalizeCursorToolInput(tfd.name, input),
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
const role = bubble.type === 1 ? "user" : "assistant";
|
|
403
|
+
entries.push({
|
|
404
|
+
type: role,
|
|
405
|
+
uuid: bubble.bubbleId,
|
|
406
|
+
timestamp,
|
|
407
|
+
sessionId: conversationId,
|
|
408
|
+
message: {
|
|
409
|
+
role,
|
|
410
|
+
content: contentBlocks.length > 0 ? contentBlocks : (bubble.text || undefined),
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return entries;
|
|
415
|
+
}
|
|
416
|
+
export async function parseCursorConversation(conversationId, globalDbPath, hints) {
|
|
417
|
+
const bubbles = readBubbles(conversationId, globalDbPath);
|
|
418
|
+
// When bubbles are empty, use hints from composer metadata
|
|
419
|
+
if (bubbles.length === 0) {
|
|
420
|
+
const hintDate = hints?.createdAt ? new Date(hints.createdAt).toISOString() : null;
|
|
421
|
+
// Synthesize a single user entry from the conversation name so title extraction works
|
|
422
|
+
const raw_entries = hints?.name ? [{
|
|
423
|
+
type: "user",
|
|
424
|
+
uuid: conversationId,
|
|
425
|
+
timestamp: hintDate ?? new Date().toISOString(),
|
|
426
|
+
sessionId: conversationId,
|
|
427
|
+
message: { role: "user", content: hints.name },
|
|
428
|
+
}] : [];
|
|
429
|
+
return {
|
|
430
|
+
source: "cursor",
|
|
431
|
+
turns: 0,
|
|
432
|
+
tool_calls: [],
|
|
433
|
+
files_touched: [],
|
|
434
|
+
duration_ms: 0,
|
|
435
|
+
wall_clock_ms: 0,
|
|
436
|
+
loc_stats: { loc_added: 0, loc_removed: 0, loc_net: 0, files_changed: [] },
|
|
437
|
+
raw_entries,
|
|
438
|
+
start_time: hintDate,
|
|
439
|
+
end_time: hintDate,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const toolCalls = extractToolCallsFromBubbles(bubbles);
|
|
443
|
+
const filesTouched = extractFilesFromBubbles(bubbles);
|
|
444
|
+
const turns = countTurnsFromBubbles(bubbles);
|
|
445
|
+
const { duration_ms, wall_clock_ms, start_time, end_time } = computeDurationFromBubbles(bubbles);
|
|
446
|
+
const loc_stats = computeLocFromBubbles(bubbles);
|
|
447
|
+
const raw_entries = bubblesToRawEntries(bubbles, conversationId);
|
|
448
|
+
// If no user message exists but we have a conversation name, prepend a
|
|
449
|
+
// synthetic user entry so downstream title extraction finds it.
|
|
450
|
+
const hasUserText = raw_entries.some((e) => e.type === "user" && typeof e.message?.content === "string" && e.message.content.trim().length > 0);
|
|
451
|
+
if (!hasUserText && hints?.name) {
|
|
452
|
+
const ts = start_time ?? (hints.createdAt ? new Date(hints.createdAt).toISOString() : new Date().toISOString());
|
|
453
|
+
raw_entries.unshift({
|
|
454
|
+
type: "user",
|
|
455
|
+
uuid: `${conversationId}-title`,
|
|
456
|
+
timestamp: ts,
|
|
457
|
+
sessionId: conversationId,
|
|
458
|
+
message: { role: "user", content: hints.name },
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
// Use hint date when bubbles have no timestamps
|
|
462
|
+
const hintDate = hints?.createdAt ? new Date(hints.createdAt).toISOString() : null;
|
|
463
|
+
const hintEndDate = hints?.lastUpdatedAt ? new Date(hints.lastUpdatedAt).toISOString() : null;
|
|
464
|
+
// Fall back to workspace metadata for duration when bubble timestamps are missing
|
|
465
|
+
let finalDuration = duration_ms;
|
|
466
|
+
let finalWallClock = wall_clock_ms;
|
|
467
|
+
if (finalDuration === 0 && hints?.createdAt && hints?.lastUpdatedAt) {
|
|
468
|
+
finalWallClock = hints.lastUpdatedAt - hints.createdAt;
|
|
469
|
+
finalDuration = finalWallClock; // best estimate without per-bubble idle detection
|
|
470
|
+
}
|
|
471
|
+
// Fall back to workspace metadata for LOC when bubble tool calls lack detail
|
|
472
|
+
let finalLoc = loc_stats;
|
|
473
|
+
if (finalLoc.loc_added === 0 && finalLoc.loc_removed === 0) {
|
|
474
|
+
const hintAdded = hints?.totalLinesAdded ?? 0;
|
|
475
|
+
const hintRemoved = hints?.totalLinesRemoved ?? 0;
|
|
476
|
+
if (hintAdded > 0 || hintRemoved > 0) {
|
|
477
|
+
finalLoc = {
|
|
478
|
+
loc_added: hintAdded,
|
|
479
|
+
loc_removed: hintRemoved,
|
|
480
|
+
loc_net: hintAdded - hintRemoved,
|
|
481
|
+
files_changed: loc_stats.files_changed, // keep whatever we found from bubbles
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
source: "cursor",
|
|
487
|
+
turns,
|
|
488
|
+
tool_calls: toolCalls,
|
|
489
|
+
files_touched: filesTouched,
|
|
490
|
+
duration_ms: finalDuration,
|
|
491
|
+
wall_clock_ms: finalWallClock,
|
|
492
|
+
loc_stats: finalLoc,
|
|
493
|
+
raw_entries,
|
|
494
|
+
start_time: start_time ?? hintDate,
|
|
495
|
+
end_time: end_time ?? hintEndDate ?? hintDate,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
// --- SessionParser interface adapter ---
|
|
499
|
+
// Cursor conversations aren't files, so detect/parse work with synthetic paths:
|
|
500
|
+
// "cursor://{conversationId}?db={globalDbPath}"
|
|
501
|
+
async function detect(path) {
|
|
502
|
+
return path.startsWith("cursor://");
|
|
503
|
+
}
|
|
504
|
+
async function parse(path) {
|
|
505
|
+
const url = new URL(path);
|
|
506
|
+
const conversationId = url.hostname;
|
|
507
|
+
const globalDbPath = url.searchParams.get("db") ?? undefined;
|
|
508
|
+
const hints = {};
|
|
509
|
+
const name = url.searchParams.get("name");
|
|
510
|
+
const createdAt = url.searchParams.get("createdAt");
|
|
511
|
+
const lastUpdatedAt = url.searchParams.get("lastUpdatedAt");
|
|
512
|
+
const linesAdded = url.searchParams.get("linesAdded");
|
|
513
|
+
const linesRemoved = url.searchParams.get("linesRemoved");
|
|
514
|
+
if (name)
|
|
515
|
+
hints.name = name;
|
|
516
|
+
if (createdAt)
|
|
517
|
+
hints.createdAt = Number(createdAt);
|
|
518
|
+
if (lastUpdatedAt)
|
|
519
|
+
hints.lastUpdatedAt = Number(lastUpdatedAt);
|
|
520
|
+
if (linesAdded)
|
|
521
|
+
hints.totalLinesAdded = Number(linesAdded);
|
|
522
|
+
if (linesRemoved)
|
|
523
|
+
hints.totalLinesRemoved = Number(linesRemoved);
|
|
524
|
+
return parseCursorConversation(conversationId, globalDbPath, hints);
|
|
525
|
+
}
|
|
526
|
+
export const cursorParser = {
|
|
527
|
+
name: "cursor",
|
|
528
|
+
detect,
|
|
529
|
+
parse,
|
|
530
|
+
};
|
|
531
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/parsers/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SessionParser, SessionAnalysis } from "./types.js";
|
|
2
|
+
interface GeminiLogEntry {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
messageId: number;
|
|
5
|
+
type: string;
|
|
6
|
+
message: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
}
|
|
9
|
+
export interface GeminiSessionFile {
|
|
10
|
+
path: string;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
projectHash: string;
|
|
13
|
+
projectDir?: string;
|
|
14
|
+
}
|
|
15
|
+
declare function extractFileRefsFromText(text: string): string[];
|
|
16
|
+
declare function parseGeminiLog(raw: string): GeminiLogEntry[];
|
|
17
|
+
declare function groupBySession(entries: GeminiLogEntry[]): Map<string, GeminiLogEntry[]>;
|
|
18
|
+
declare function analyzeSession(entries: GeminiLogEntry[]): SessionAnalysis;
|
|
19
|
+
export declare const geminiParser: SessionParser;
|
|
20
|
+
export declare function hashProjectDir(dir: string): string;
|
|
21
|
+
export declare function discoverGeminiSessions(): Promise<GeminiSessionFile[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Try to resolve a project hash to a directory by hashing candidate paths.
|
|
24
|
+
* Pass known project directories (e.g., from Claude or Cursor) and this
|
|
25
|
+
* will match them against Gemini's hashes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveProjectDirs(sessions: GeminiSessionFile[], knownDirs: string[]): GeminiSessionFile[];
|
|
28
|
+
export { parseGeminiLog, groupBySession, analyzeSession, extractFileRefsFromText };
|