@planckspace/cli 0.0.2 → 0.1.1
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 +109 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +12 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +45 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +7 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/scan.d.ts +5 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +51 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +31 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +15 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +77 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +40 -0
- package/dist/config.js.map +1 -0
- package/dist/correlate.d.ts +21 -0
- package/dist/correlate.d.ts.map +1 -0
- package/dist/correlate.js +204 -0
- package/dist/correlate.js.map +1 -0
- package/dist/db/store.d.ts +46 -0
- package/dist/db/store.d.ts.map +1 -0
- package/dist/db/store.js +210 -0
- package/dist/db/store.js.map +1 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +7 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/dist/scrapers/claudeCode.d.ts +4 -0
- package/dist/scrapers/claudeCode.d.ts.map +1 -0
- package/dist/scrapers/claudeCode.js +211 -0
- package/dist/scrapers/claudeCode.js.map +1 -0
- package/dist/scrapers/cursor.d.ts +9 -0
- package/dist/scrapers/cursor.d.ts.map +1 -0
- package/dist/scrapers/cursor.js +280 -0
- package/dist/scrapers/cursor.js.map +1 -0
- package/dist/scrapers/repo.d.ts +12 -0
- package/dist/scrapers/repo.d.ts.map +1 -0
- package/dist/scrapers/repo.js +40 -0
- package/dist/scrapers/repo.js.map +1 -0
- package/dist/scrapers/types.d.ts +36 -0
- package/dist/scrapers/types.d.ts.map +1 -0
- package/dist/scrapers/types.js +5 -0
- package/dist/scrapers/types.js.map +1 -0
- package/dist/scrapers/windsurf.d.ts +9 -0
- package/dist/scrapers/windsurf.d.ts.map +1 -0
- package/dist/scrapers/windsurf.js +255 -0
- package/dist/scrapers/windsurf.js.map +1 -0
- package/dist/sync/payload.d.ts +14 -0
- package/dist/sync/payload.d.ts.map +1 -0
- package/dist/sync/payload.js +36 -0
- package/dist/sync/payload.js.map +1 -0
- package/dist/sync/syncEngine.d.ts +16 -0
- package/dist/sync/syncEngine.d.ts.map +1 -0
- package/dist/sync/syncEngine.js +76 -0
- package/dist/sync/syncEngine.js.map +1 -0
- package/install.sh +126 -0
- package/package.json +39 -7
- package/index.js +0 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { computeCostUsd } from "@planckspace/core";
|
|
5
|
+
import { resolveRepo } from "./repo.js";
|
|
6
|
+
// ── File-touch detection ──────────────────────────────────────────────────────
|
|
7
|
+
const FILE_TOOLS = new Set(["Read", "Edit", "Write", "NotebookEdit"]);
|
|
8
|
+
function extractFilePath(item) {
|
|
9
|
+
if (!FILE_TOOLS.has(item.name))
|
|
10
|
+
return null;
|
|
11
|
+
const inp = item.input;
|
|
12
|
+
const fp = inp["file_path"] ??
|
|
13
|
+
inp["notebook_path"] ??
|
|
14
|
+
inp["path"];
|
|
15
|
+
return fp ?? null;
|
|
16
|
+
}
|
|
17
|
+
// ── JSONL parsing ─────────────────────────────────────────────────────────────
|
|
18
|
+
function parseLine(raw) {
|
|
19
|
+
const trimmed = raw.trim();
|
|
20
|
+
if (!trimmed)
|
|
21
|
+
return null;
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(trimmed);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function parseSessionFile(filePath, sessionId) {
|
|
30
|
+
let rawLines;
|
|
31
|
+
try {
|
|
32
|
+
rawLines = fs.readFileSync(filePath, "utf-8").split("\n");
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.warn(`[claudeCode] Cannot read ${filePath}: ${String(err)}`);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const events = [];
|
|
39
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
40
|
+
const ev = parseLine(rawLines[i]);
|
|
41
|
+
if (ev === null) {
|
|
42
|
+
if (rawLines[i].trim()) {
|
|
43
|
+
console.warn(`[claudeCode] Unparseable line ${i + 1} in ${filePath}`);
|
|
44
|
+
}
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
events.push(ev);
|
|
48
|
+
}
|
|
49
|
+
// Collect timestamps from all events
|
|
50
|
+
const timestamps = events
|
|
51
|
+
.filter((e) => "timestamp" in e && typeof e.timestamp === "string")
|
|
52
|
+
.map((e) => e.timestamp)
|
|
53
|
+
.sort();
|
|
54
|
+
if (timestamps.length === 0)
|
|
55
|
+
return null;
|
|
56
|
+
// First cwd / gitBranch from user events
|
|
57
|
+
let workingDir = "";
|
|
58
|
+
let gitBranchFromLog = null;
|
|
59
|
+
for (const ev of events) {
|
|
60
|
+
if (ev.type === "user") {
|
|
61
|
+
const ue = ev;
|
|
62
|
+
if (!workingDir && ue.cwd)
|
|
63
|
+
workingDir = ue.cwd;
|
|
64
|
+
if (!gitBranchFromLog && ue.gitBranch && ue.gitBranch !== "HEAD")
|
|
65
|
+
gitBranchFromLog = ue.gitBranch;
|
|
66
|
+
}
|
|
67
|
+
if (workingDir && gitBranchFromLog)
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
const msgMap = new Map();
|
|
71
|
+
let msgOrder = 0;
|
|
72
|
+
for (const ev of events) {
|
|
73
|
+
if (ev.type !== "assistant")
|
|
74
|
+
continue;
|
|
75
|
+
const ae = ev;
|
|
76
|
+
const msgId = ae.message.id;
|
|
77
|
+
if (!msgId)
|
|
78
|
+
continue;
|
|
79
|
+
if (!msgMap.has(msgId)) {
|
|
80
|
+
msgMap.set(msgId, {
|
|
81
|
+
model: ae.message.model ?? "",
|
|
82
|
+
usage: ae.message.usage,
|
|
83
|
+
toolItems: [],
|
|
84
|
+
timestamp: ae.timestamp,
|
|
85
|
+
order: msgOrder++,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const acc = msgMap.get(msgId);
|
|
89
|
+
for (const item of ae.message.content ?? []) {
|
|
90
|
+
if (item.type === "tool_use") {
|
|
91
|
+
acc.toolItems.push(item);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Aggregate tokens & build turns; cost computed per-turn with that turn's model.
|
|
96
|
+
let totalInput = 0;
|
|
97
|
+
let totalOutput = 0;
|
|
98
|
+
let totalCacheRead = 0;
|
|
99
|
+
let totalCacheWrite = 0;
|
|
100
|
+
let totalCost = 0;
|
|
101
|
+
let sessionModel = "";
|
|
102
|
+
const turns = [];
|
|
103
|
+
const allFilesTouched = new Set();
|
|
104
|
+
const orderedMsgs = [...msgMap.values()].sort((a, b) => a.order - b.order);
|
|
105
|
+
for (let seq = 0; seq < orderedMsgs.length; seq++) {
|
|
106
|
+
const m = orderedMsgs[seq];
|
|
107
|
+
const inp = m.usage.input_tokens ?? 0;
|
|
108
|
+
const out = m.usage.output_tokens ?? 0;
|
|
109
|
+
const cr = m.usage.cache_read_input_tokens ?? 0;
|
|
110
|
+
const cw = m.usage.cache_creation_input_tokens ?? 0;
|
|
111
|
+
totalInput += inp;
|
|
112
|
+
totalOutput += out;
|
|
113
|
+
totalCacheRead += cr;
|
|
114
|
+
totalCacheWrite += cw;
|
|
115
|
+
const turnCost = computeCostUsd({ inputTokens: inp, outputTokens: out, cacheReadTokens: cr, cacheWriteTokens: cw }, m.model);
|
|
116
|
+
totalCost += turnCost;
|
|
117
|
+
if (!sessionModel)
|
|
118
|
+
sessionModel = m.model;
|
|
119
|
+
// Aggregate tool calls
|
|
120
|
+
const toolCounts = new Map();
|
|
121
|
+
const turnFiles = [];
|
|
122
|
+
for (const item of m.toolItems) {
|
|
123
|
+
toolCounts.set(item.name, (toolCounts.get(item.name) ?? 0) + 1);
|
|
124
|
+
const fp = extractFilePath(item);
|
|
125
|
+
if (fp) {
|
|
126
|
+
turnFiles.push(fp);
|
|
127
|
+
allFilesTouched.add(fp);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const toolCalls = [...toolCounts.entries()].map(([name, count]) => ({
|
|
131
|
+
name,
|
|
132
|
+
count,
|
|
133
|
+
}));
|
|
134
|
+
turns.push({
|
|
135
|
+
sequence: seq + 1,
|
|
136
|
+
model: m.model,
|
|
137
|
+
inputTokens: inp,
|
|
138
|
+
outputTokens: out,
|
|
139
|
+
cacheReadTokens: cr,
|
|
140
|
+
cacheWriteTokens: cw,
|
|
141
|
+
costUsd: turnCost,
|
|
142
|
+
toolCalls,
|
|
143
|
+
filesTouched: turnFiles,
|
|
144
|
+
timestamp: m.timestamp,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (turns.length === 0)
|
|
148
|
+
return null;
|
|
149
|
+
const { repoName, gitBranch: gitBranchFromGit } = resolveRepo(workingDir);
|
|
150
|
+
const gitBranch = gitBranchFromLog ?? gitBranchFromGit;
|
|
151
|
+
const costUsd = totalCost;
|
|
152
|
+
return {
|
|
153
|
+
sessionId,
|
|
154
|
+
tool: "claude_code",
|
|
155
|
+
model: sessionModel,
|
|
156
|
+
startedAt: timestamps[0],
|
|
157
|
+
endedAt: timestamps[timestamps.length - 1],
|
|
158
|
+
inputTokens: totalInput,
|
|
159
|
+
outputTokens: totalOutput,
|
|
160
|
+
cacheReadTokens: totalCacheRead,
|
|
161
|
+
cacheWriteTokens: totalCacheWrite,
|
|
162
|
+
costUsd,
|
|
163
|
+
turns,
|
|
164
|
+
workingDir,
|
|
165
|
+
turnCount: turns.length,
|
|
166
|
+
filesTouchedCount: allFilesTouched.size,
|
|
167
|
+
repoName,
|
|
168
|
+
gitBranch,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
// ── Main entrypoint ───────────────────────────────────────────────────────────
|
|
172
|
+
export async function scanClaudeCodeLogs() {
|
|
173
|
+
const projectsDir = path.join(os.homedir(), ".claude", "projects");
|
|
174
|
+
let projectDirs;
|
|
175
|
+
try {
|
|
176
|
+
projectDirs = fs
|
|
177
|
+
.readdirSync(projectsDir, { withFileTypes: true })
|
|
178
|
+
.filter((d) => d.isDirectory())
|
|
179
|
+
.map((d) => path.join(projectsDir, d.name));
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
console.warn(`[claudeCode] Cannot read ${projectsDir} — skipping`);
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
const sessions = [];
|
|
186
|
+
for (const projectDir of projectDirs) {
|
|
187
|
+
let entries;
|
|
188
|
+
try {
|
|
189
|
+
entries = fs.readdirSync(projectDir, { withFileTypes: true });
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
|
|
196
|
+
continue;
|
|
197
|
+
const sessionId = entry.name.replace(/\.jsonl$/, "");
|
|
198
|
+
const filePath = path.join(projectDir, entry.name);
|
|
199
|
+
try {
|
|
200
|
+
const session = parseSessionFile(filePath, sessionId);
|
|
201
|
+
if (session)
|
|
202
|
+
sessions.push(session);
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
console.warn(`[claudeCode] Failed to parse ${filePath}: ${String(err)}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return sessions;
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=claudeCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/scrapers/claudeCode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedSession } from "./types.js";
|
|
2
|
+
/** Cross-platform path to Cursor's global state DB. */
|
|
3
|
+
export declare function defaultCursorDbPath(): string;
|
|
4
|
+
/**
|
|
5
|
+
* Scan Cursor's global state DB for composer/agent sessions.
|
|
6
|
+
* @param dbPath override the DB location (used by tests). Defaults to the OS path.
|
|
7
|
+
*/
|
|
8
|
+
export declare function scanCursorLogs(dbPath?: string): ParsedSession[];
|
|
9
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/scrapers/cursor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAQ,aAAa,EAAE,MAAM,YAAY,CAAC;AAiFtD,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,MAAM,CAU5C;AAuMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,SAAwB,GAAG,aAAa,EAAE,CAwD9E"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import { computeCostUsd } from "@planckspace/core";
|
|
6
|
+
import { resolveRepo } from "./repo.js";
|
|
7
|
+
// Cursor tool names that operate on a single file; used to harvest touched paths.
|
|
8
|
+
// Cursor versions tool names (e.g. `edit_file_v2`, `read_file_v2`), so we compare
|
|
9
|
+
// against the name with any trailing `_vN` stripped.
|
|
10
|
+
const FILE_TOOL_NAMES = new Set([
|
|
11
|
+
"edit_file",
|
|
12
|
+
"write",
|
|
13
|
+
"write_file",
|
|
14
|
+
"create_file",
|
|
15
|
+
"search_replace",
|
|
16
|
+
"apply_diff",
|
|
17
|
+
"read_file",
|
|
18
|
+
"delete_file",
|
|
19
|
+
"reapply",
|
|
20
|
+
]);
|
|
21
|
+
function isFileTool(name) {
|
|
22
|
+
return FILE_TOOL_NAMES.has(name.replace(/_v\d+$/, ""));
|
|
23
|
+
}
|
|
24
|
+
// Param keys Cursor uses to name the target file, across tool variants.
|
|
25
|
+
const PATH_PARAM_KEYS = ["relativeWorkspacePath", "targetFile", "target_file", "path", "file", "filePath", "uri"];
|
|
26
|
+
// ── DB location ─────────────────────────────────────────────────────────────────
|
|
27
|
+
/** Cross-platform path to Cursor's global state DB. */
|
|
28
|
+
export function defaultCursorDbPath() {
|
|
29
|
+
const home = os.homedir();
|
|
30
|
+
if (process.platform === "darwin") {
|
|
31
|
+
return path.join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
32
|
+
}
|
|
33
|
+
if (process.platform === "win32") {
|
|
34
|
+
const appData = process.env.APPDATA ?? path.join(home, "AppData", "Roaming");
|
|
35
|
+
return path.join(appData, "Cursor", "User", "globalStorage", "state.vscdb");
|
|
36
|
+
}
|
|
37
|
+
return path.join(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
38
|
+
}
|
|
39
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────────
|
|
40
|
+
function parseJson(raw) {
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(raw);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function epochToIso(ms) {
|
|
49
|
+
if (typeof ms !== "number" || !Number.isFinite(ms))
|
|
50
|
+
return null;
|
|
51
|
+
const d = new Date(ms);
|
|
52
|
+
return Number.isNaN(d.getTime()) ? null : d.toISOString();
|
|
53
|
+
}
|
|
54
|
+
/** Pull a file path out of a tool call's argument JSON, if the tool touches a file. */
|
|
55
|
+
function fileFromToolCall(tfd) {
|
|
56
|
+
if (!tfd.name || !isFileTool(tfd.name))
|
|
57
|
+
return null;
|
|
58
|
+
const argsRaw = tfd.params ?? tfd.rawArgs;
|
|
59
|
+
if (!argsRaw)
|
|
60
|
+
return null;
|
|
61
|
+
const args = parseJson(argsRaw);
|
|
62
|
+
if (!args)
|
|
63
|
+
return null;
|
|
64
|
+
for (const k of PATH_PARAM_KEYS) {
|
|
65
|
+
const v = args[k];
|
|
66
|
+
if (typeof v === "string" && v.trim())
|
|
67
|
+
return v;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function workspaceDir(header, bubbles) {
|
|
72
|
+
const fromHeader = header.workspaceIdentifier?.uri?.fsPath;
|
|
73
|
+
if (fromHeader)
|
|
74
|
+
return fromHeader;
|
|
75
|
+
// Fallback: a workspace URI carried on a bubble (file:///… → fs path).
|
|
76
|
+
for (const b of bubbles) {
|
|
77
|
+
const uri = b.workspaceUris?.find((u) => typeof u === "string" && u.length > 0);
|
|
78
|
+
if (uri) {
|
|
79
|
+
try {
|
|
80
|
+
return decodeURIComponent(new URL(uri).pathname.replace(/^\/([A-Za-z]:)/, "$1"));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* ignore unparseable URI */
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
// ── Per-composer parsing ──────────────────────────────────────────────────────────
|
|
90
|
+
function buildSession(header, data, bubbles) {
|
|
91
|
+
const composerId = header.composerId;
|
|
92
|
+
// Ordered list of messages; prefer the composer's own ordering, else fall back
|
|
93
|
+
// to whatever bubbles we found.
|
|
94
|
+
const order = data?.fullConversationHeadersOnly ?? [];
|
|
95
|
+
const ordered = [];
|
|
96
|
+
if (order.length > 0) {
|
|
97
|
+
for (const h of order) {
|
|
98
|
+
const b = bubbles.get(h.bubbleId);
|
|
99
|
+
if (b)
|
|
100
|
+
ordered.push({ bubble: b, type: b.type ?? h.type });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
for (const b of bubbles.values())
|
|
105
|
+
ordered.push({ bubble: b, type: b.type ?? 0 });
|
|
106
|
+
}
|
|
107
|
+
// No conversation → skip empty drafts / placeholder composers.
|
|
108
|
+
if (ordered.length === 0)
|
|
109
|
+
return null;
|
|
110
|
+
const hasUserPrompt = ordered.some((o) => o.type === 1);
|
|
111
|
+
if (!hasUserPrompt)
|
|
112
|
+
return null;
|
|
113
|
+
const sessionModel = data?.modelConfig?.modelName || "default";
|
|
114
|
+
let totalInput = 0;
|
|
115
|
+
let totalOutput = 0;
|
|
116
|
+
let totalCost = 0;
|
|
117
|
+
const turns = [];
|
|
118
|
+
const timestamps = [];
|
|
119
|
+
const allFiles = new Set();
|
|
120
|
+
let current = null;
|
|
121
|
+
const closeTurn = () => {
|
|
122
|
+
if (current)
|
|
123
|
+
turns.push(current);
|
|
124
|
+
current = null;
|
|
125
|
+
};
|
|
126
|
+
for (const { bubble, type } of ordered) {
|
|
127
|
+
if (bubble.createdAt)
|
|
128
|
+
timestamps.push(bubble.createdAt);
|
|
129
|
+
if (type === 1) {
|
|
130
|
+
// User prompt starts a new exchange.
|
|
131
|
+
closeTurn();
|
|
132
|
+
current = {
|
|
133
|
+
sequence: turns.length + 1,
|
|
134
|
+
model: sessionModel,
|
|
135
|
+
inputTokens: 0,
|
|
136
|
+
outputTokens: 0,
|
|
137
|
+
cacheReadTokens: 0,
|
|
138
|
+
cacheWriteTokens: 0,
|
|
139
|
+
costUsd: 0,
|
|
140
|
+
toolCalls: [],
|
|
141
|
+
filesTouched: [],
|
|
142
|
+
timestamp: bubble.createdAt ?? "",
|
|
143
|
+
};
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// Assistant bubble: fold into the current exchange (or open one if the log
|
|
147
|
+
// starts mid-stream without a leading user bubble).
|
|
148
|
+
if (!current) {
|
|
149
|
+
current = {
|
|
150
|
+
sequence: turns.length + 1,
|
|
151
|
+
model: sessionModel,
|
|
152
|
+
inputTokens: 0,
|
|
153
|
+
outputTokens: 0,
|
|
154
|
+
cacheReadTokens: 0,
|
|
155
|
+
cacheWriteTokens: 0,
|
|
156
|
+
costUsd: 0,
|
|
157
|
+
toolCalls: [],
|
|
158
|
+
filesTouched: [],
|
|
159
|
+
timestamp: bubble.createdAt ?? "",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const inp = bubble.tokenCount?.inputTokens ?? 0;
|
|
163
|
+
const out = bubble.tokenCount?.outputTokens ?? 0;
|
|
164
|
+
const model = bubble.modelInfo?.modelName || sessionModel;
|
|
165
|
+
current.inputTokens += inp;
|
|
166
|
+
current.outputTokens += out;
|
|
167
|
+
current.costUsd += computeCostUsd({ inputTokens: inp, outputTokens: out, cacheReadTokens: 0, cacheWriteTokens: 0 }, model);
|
|
168
|
+
if (model && model !== "default")
|
|
169
|
+
current.model = model;
|
|
170
|
+
totalInput += inp;
|
|
171
|
+
totalOutput += out;
|
|
172
|
+
const tfd = bubble.toolFormerData;
|
|
173
|
+
if (tfd?.name) {
|
|
174
|
+
const existing = current.toolCalls.find((t) => t.name === tfd.name);
|
|
175
|
+
if (existing)
|
|
176
|
+
existing.count += 1;
|
|
177
|
+
else
|
|
178
|
+
current.toolCalls.push({ name: tfd.name, count: 1 });
|
|
179
|
+
const fp = fileFromToolCall(tfd);
|
|
180
|
+
if (fp) {
|
|
181
|
+
if (!current.filesTouched.includes(fp))
|
|
182
|
+
current.filesTouched.push(fp);
|
|
183
|
+
allFiles.add(fp);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
closeTurn();
|
|
188
|
+
totalCost = turns.reduce((s, t) => s + t.costUsd, 0);
|
|
189
|
+
timestamps.sort();
|
|
190
|
+
const startedAt = timestamps[0] ?? epochToIso(data?.createdAt ?? header.createdAt) ?? new Date(0).toISOString();
|
|
191
|
+
const endedAt = timestamps[timestamps.length - 1] ??
|
|
192
|
+
epochToIso(header.lastUpdatedAt ?? header.createdAt) ??
|
|
193
|
+
startedAt;
|
|
194
|
+
const workingDir = workspaceDir(header, [...bubbles.values()]);
|
|
195
|
+
const { repoName, gitBranch } = resolveRepo(workingDir);
|
|
196
|
+
// Cursor's own count of files the agent modified is more reliable than scraping
|
|
197
|
+
// every tool variant's arguments; fall back to what we harvested if absent.
|
|
198
|
+
const filesTouchedCount = header.filesChangedCount ?? allFiles.size;
|
|
199
|
+
// turnCount = number of user prompts (exchanges), the comparable unit to a
|
|
200
|
+
// Claude Code "turn".
|
|
201
|
+
const turnCount = turns.length;
|
|
202
|
+
return {
|
|
203
|
+
sessionId: `cursor:${composerId}`,
|
|
204
|
+
tool: "cursor",
|
|
205
|
+
model: sessionModel,
|
|
206
|
+
startedAt,
|
|
207
|
+
endedAt,
|
|
208
|
+
inputTokens: totalInput,
|
|
209
|
+
outputTokens: totalOutput,
|
|
210
|
+
cacheReadTokens: 0,
|
|
211
|
+
cacheWriteTokens: 0,
|
|
212
|
+
costUsd: totalCost,
|
|
213
|
+
turns,
|
|
214
|
+
workingDir,
|
|
215
|
+
turnCount,
|
|
216
|
+
filesTouchedCount,
|
|
217
|
+
repoName,
|
|
218
|
+
gitBranch,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
// ── Main entrypoint ─────────────────────────────────────────────────────────────
|
|
222
|
+
/**
|
|
223
|
+
* Scan Cursor's global state DB for composer/agent sessions.
|
|
224
|
+
* @param dbPath override the DB location (used by tests). Defaults to the OS path.
|
|
225
|
+
*/
|
|
226
|
+
export function scanCursorLogs(dbPath = defaultCursorDbPath()) {
|
|
227
|
+
if (!fs.existsSync(dbPath)) {
|
|
228
|
+
return []; // Cursor not installed / no history — silent, this is expected.
|
|
229
|
+
}
|
|
230
|
+
let db;
|
|
231
|
+
try {
|
|
232
|
+
// readonly + immutable-ish open; Cursor may be running with the DB in WAL mode.
|
|
233
|
+
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
console.warn(`[cursor] Cannot open ${dbPath}: ${String(err)} — skipping`);
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const headerRow = db
|
|
241
|
+
.prepare("SELECT value FROM ItemTable WHERE key = 'composer.composerHeaders'")
|
|
242
|
+
.get();
|
|
243
|
+
if (!headerRow)
|
|
244
|
+
return [];
|
|
245
|
+
const headerJson = parseJson(headerRow.value.toString());
|
|
246
|
+
const headers = headerJson?.allComposers ?? [];
|
|
247
|
+
if (headers.length === 0)
|
|
248
|
+
return [];
|
|
249
|
+
const dataStmt = db.prepare("SELECT value FROM cursorDiskKV WHERE key = ?");
|
|
250
|
+
const bubbleStmt = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ?");
|
|
251
|
+
const sessions = [];
|
|
252
|
+
for (const header of headers) {
|
|
253
|
+
if (!header?.composerId)
|
|
254
|
+
continue;
|
|
255
|
+
try {
|
|
256
|
+
const dataRow = dataStmt.get(`composerData:${header.composerId}`);
|
|
257
|
+
const data = dataRow ? parseJson(dataRow.value.toString()) : null;
|
|
258
|
+
const bubbles = new Map();
|
|
259
|
+
const prefix = `bubbleId:${header.composerId}:`;
|
|
260
|
+
for (const row of bubbleStmt.all(`${prefix}%`)) {
|
|
261
|
+
const bubbleId = row.key.slice(prefix.length);
|
|
262
|
+
const b = parseJson(row.value.toString());
|
|
263
|
+
if (b)
|
|
264
|
+
bubbles.set(bubbleId, b);
|
|
265
|
+
}
|
|
266
|
+
const session = buildSession(header, data, bubbles);
|
|
267
|
+
if (session)
|
|
268
|
+
sessions.push(session);
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
console.warn(`[cursor] Failed to parse composer ${header.composerId}: ${String(err)}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return sessions;
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
db.close();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/scrapers/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Walk up from `dir` looking for a `.git` entry; returns the repo root or null. */
|
|
2
|
+
export declare function findGitRoot(dir: string): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the repo name and current branch for a working directory by reading
|
|
5
|
+
* `.git/HEAD` directly (no git binary needed). The scraper only needs a best-effort
|
|
6
|
+
* snapshot; the git correlator does the authoritative outcome analysis later.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveRepo(workingDir: string): {
|
|
9
|
+
repoName: string | null;
|
|
10
|
+
gitBranch: string | null;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/scrapers/repo.ts"],"names":[],"mappings":"AAGA,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUtD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG;IAC/C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAcA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
/** Walk up from `dir` looking for a `.git` entry; returns the repo root or null. */
|
|
4
|
+
export function findGitRoot(dir) {
|
|
5
|
+
if (!dir)
|
|
6
|
+
return null;
|
|
7
|
+
let current = path.resolve(dir);
|
|
8
|
+
for (let i = 0; i < 20; i++) {
|
|
9
|
+
if (fs.existsSync(path.join(current, ".git")))
|
|
10
|
+
return current;
|
|
11
|
+
const parent = path.dirname(current);
|
|
12
|
+
if (parent === current)
|
|
13
|
+
break;
|
|
14
|
+
current = parent;
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the repo name and current branch for a working directory by reading
|
|
20
|
+
* `.git/HEAD` directly (no git binary needed). The scraper only needs a best-effort
|
|
21
|
+
* snapshot; the git correlator does the authoritative outcome analysis later.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveRepo(workingDir) {
|
|
24
|
+
try {
|
|
25
|
+
const root = findGitRoot(workingDir);
|
|
26
|
+
if (!root)
|
|
27
|
+
return { repoName: null, gitBranch: null };
|
|
28
|
+
const repoName = path.basename(root);
|
|
29
|
+
const headPath = path.join(root, ".git", "HEAD");
|
|
30
|
+
const head = fs.readFileSync(headPath, "utf-8").trim();
|
|
31
|
+
const branch = head.startsWith("ref: refs/heads/")
|
|
32
|
+
? head.slice("ref: refs/heads/".length)
|
|
33
|
+
: null;
|
|
34
|
+
return { repoName, gitBranch: branch };
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return { repoName: null, gitBranch: null };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.js","sourceRoot":"","sources":["../../src/scrapers/repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,oFAAoF;AACpF,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM;QAC9B,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB;IAI5C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC;YAChD,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC;QACT,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** AI coding tool a session came from. Mirrors `@planckspace/core`'s telemetry enum. */
|
|
2
|
+
export type Tool = "claude_code" | "cursor" | "windsurf";
|
|
3
|
+
export type Turn = {
|
|
4
|
+
sequence: number;
|
|
5
|
+
model: string;
|
|
6
|
+
inputTokens: number;
|
|
7
|
+
outputTokens: number;
|
|
8
|
+
cacheReadTokens: number;
|
|
9
|
+
cacheWriteTokens: number;
|
|
10
|
+
costUsd: number;
|
|
11
|
+
toolCalls: {
|
|
12
|
+
name: string;
|
|
13
|
+
count: number;
|
|
14
|
+
}[];
|
|
15
|
+
filesTouched: string[];
|
|
16
|
+
timestamp: string;
|
|
17
|
+
};
|
|
18
|
+
export type ParsedSession = {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
tool: Tool;
|
|
21
|
+
model: string;
|
|
22
|
+
startedAt: string;
|
|
23
|
+
endedAt: string;
|
|
24
|
+
inputTokens: number;
|
|
25
|
+
outputTokens: number;
|
|
26
|
+
cacheReadTokens: number;
|
|
27
|
+
cacheWriteTokens: number;
|
|
28
|
+
costUsd: number;
|
|
29
|
+
turns: Turn[];
|
|
30
|
+
workingDir: string;
|
|
31
|
+
turnCount: number;
|
|
32
|
+
filesTouchedCount: number;
|
|
33
|
+
repoName: string | null;
|
|
34
|
+
gitBranch: string | null;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scrapers/types.ts"],"names":[],"mappings":"AAIA,wFAAwF;AACxF,MAAM,MAAM,IAAI,GAAG,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEzD,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/scrapers/types.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,qFAAqF;AACrF,gCAAgC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedSession } from "./types.js";
|
|
2
|
+
/** Candidate Windsurf global-state DB paths for the current OS (stable + Next). */
|
|
3
|
+
export declare function windsurfDbPaths(): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Scan Windsurf's global state DB(s) for Cascade conversations.
|
|
6
|
+
* @param dbPaths override the DB locations (used by tests). Defaults to OS paths.
|
|
7
|
+
*/
|
|
8
|
+
export declare function scanWindsurfLogs(dbPaths?: string[]): ParsedSession[];
|
|
9
|
+
//# sourceMappingURL=windsurf.d.ts.map
|