@tracemarketplace/shared 0.0.8 → 0.0.9
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/dist/extractor-claude-code.test.js +63 -0
- package/dist/extractor-claude-code.test.js.map +1 -1
- package/dist/extractor-codex.test.d.ts +2 -0
- package/dist/extractor-codex.test.d.ts.map +1 -0
- package/dist/extractor-codex.test.js +212 -0
- package/dist/extractor-codex.test.js.map +1 -0
- package/dist/extractor-cursor.test.d.ts +2 -0
- package/dist/extractor-cursor.test.d.ts.map +1 -0
- package/dist/extractor-cursor.test.js +120 -0
- package/dist/extractor-cursor.test.js.map +1 -0
- package/dist/extractors/claude-code.d.ts.map +1 -1
- package/dist/extractors/claude-code.js +11 -5
- package/dist/extractors/claude-code.js.map +1 -1
- package/dist/extractors/codex.d.ts.map +1 -1
- package/dist/extractors/codex.js +63 -35
- package/dist/extractors/codex.js.map +1 -1
- package/dist/extractors/common.d.ts +14 -0
- package/dist/extractors/common.d.ts.map +1 -0
- package/dist/extractors/common.js +100 -0
- package/dist/extractors/common.js.map +1 -0
- package/dist/extractors/cursor.d.ts.map +1 -1
- package/dist/extractors/cursor.js +205 -45
- package/dist/extractors/cursor.js.map +1 -1
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js +35 -2
- package/dist/hash.js.map +1 -1
- package/dist/hash.test.js +29 -2
- package/dist/hash.test.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/redact.d.ts +12 -0
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +120 -38
- package/dist/redact.js.map +1 -1
- package/dist/redact.test.d.ts +2 -0
- package/dist/redact.test.d.ts.map +1 -0
- package/dist/redact.test.js +96 -0
- package/dist/redact.test.js.map +1 -0
- package/dist/turn-actors.d.ts +3 -0
- package/dist/turn-actors.d.ts.map +1 -0
- package/dist/turn-actors.js +57 -0
- package/dist/turn-actors.js.map +1 -0
- package/dist/turn-actors.test.d.ts +2 -0
- package/dist/turn-actors.test.d.ts.map +1 -0
- package/dist/turn-actors.test.js +65 -0
- package/dist/turn-actors.test.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validators.d.ts +24 -0
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +3 -0
- package/dist/validators.js.map +1 -1
- package/package.json +5 -1
- package/src/extractor-claude-code.test.ts +69 -0
- package/src/extractor-codex.test.ts +225 -0
- package/src/extractor-cursor.test.ts +141 -0
- package/src/extractors/claude-code.ts +12 -5
- package/src/extractors/codex.ts +69 -38
- package/src/extractors/common.ts +139 -0
- package/src/extractors/cursor.ts +294 -52
- package/src/hash.test.ts +31 -2
- package/src/hash.ts +38 -3
- package/src/index.ts +1 -0
- package/src/redact.test.ts +100 -0
- package/src/redact.ts +175 -58
- package/src/turn-actors.test.ts +71 -0
- package/src/turn-actors.ts +71 -0
- package/src/types.ts +6 -0
- package/src/validators.ts +3 -0
package/dist/extractors/codex.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { hashString, computeContentHash } from "../hash.js";
|
|
3
|
+
import { collectTraceMetrics, createPassiveEnvState, extractTextFragments, pushUniqueTextBlock, } from "./common.js";
|
|
4
|
+
function toNumber(value) {
|
|
5
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
6
|
+
}
|
|
7
|
+
function extractExitCode(output) {
|
|
8
|
+
if (!output)
|
|
9
|
+
return null;
|
|
10
|
+
const match = output.match(/Process exited with code (\d+)/);
|
|
11
|
+
return match ? Number.parseInt(match[1], 10) : null;
|
|
12
|
+
}
|
|
3
13
|
export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
4
14
|
const events = [];
|
|
5
15
|
for (const line of rolloutFileBuffer.toString("utf-8").split("\n")) {
|
|
@@ -21,6 +31,10 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
21
31
|
let currentBlocks = [];
|
|
22
32
|
let taskTimestamp = null;
|
|
23
33
|
let currentModel = null;
|
|
34
|
+
let currentTaskLastTimestamp = null;
|
|
35
|
+
let totalInputTokens = null;
|
|
36
|
+
let totalOutputTokens = null;
|
|
37
|
+
let totalCacheReadTokens = null;
|
|
24
38
|
for (const event of events) {
|
|
25
39
|
const type = event["type"];
|
|
26
40
|
const payload = (event["payload"] ?? {});
|
|
@@ -31,6 +45,7 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
31
45
|
currentUserMessage = null;
|
|
32
46
|
currentBlocks = [];
|
|
33
47
|
taskTimestamp = timestamp;
|
|
48
|
+
currentTaskLastTimestamp = timestamp;
|
|
34
49
|
continue;
|
|
35
50
|
}
|
|
36
51
|
if (type === "event_msg" && payload["type"] === "task_complete") {
|
|
@@ -49,16 +64,14 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
49
64
|
}
|
|
50
65
|
const lastMsg = payload["last_agent_message"];
|
|
51
66
|
if (lastMsg) {
|
|
52
|
-
|
|
53
|
-
if (!alreadyCaptured)
|
|
54
|
-
currentBlocks.push({ type: "text", text: lastMsg });
|
|
67
|
+
pushUniqueTextBlock(currentBlocks, "text", lastMsg);
|
|
55
68
|
}
|
|
56
69
|
if (currentBlocks.length > 0) {
|
|
57
70
|
turns.push({
|
|
58
71
|
turn_id: currentTurnId ?? randomUUID(),
|
|
59
72
|
parent_turn_id: currentUserMessage ? "user_" + currentTurnId : null,
|
|
60
73
|
role: "assistant",
|
|
61
|
-
timestamp: taskTimestamp,
|
|
74
|
+
timestamp: currentTaskLastTimestamp ?? timestamp ?? taskTimestamp,
|
|
62
75
|
content: currentBlocks,
|
|
63
76
|
model: currentModel,
|
|
64
77
|
usage: null,
|
|
@@ -72,10 +85,13 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
72
85
|
currentBlocks = [];
|
|
73
86
|
taskTimestamp = null;
|
|
74
87
|
currentModel = null;
|
|
88
|
+
currentTaskLastTimestamp = null;
|
|
75
89
|
continue;
|
|
76
90
|
}
|
|
77
91
|
if (!inTask)
|
|
78
92
|
continue;
|
|
93
|
+
if (timestamp)
|
|
94
|
+
currentTaskLastTimestamp = timestamp;
|
|
79
95
|
if (type === "turn_context") {
|
|
80
96
|
currentModel = payload["model"] ?? null;
|
|
81
97
|
continue;
|
|
@@ -86,17 +102,43 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
86
102
|
currentUserMessage = payload["message"] ?? "";
|
|
87
103
|
break;
|
|
88
104
|
case "agent_reasoning":
|
|
89
|
-
|
|
90
|
-
currentBlocks.push({ type: "thinking", text: payload["text"] });
|
|
105
|
+
pushUniqueTextBlock(currentBlocks, "thinking", payload["text"]);
|
|
91
106
|
break;
|
|
92
107
|
case "agent_message":
|
|
93
|
-
|
|
94
|
-
currentBlocks.push({ type: "text", text: payload["message"] });
|
|
108
|
+
pushUniqueTextBlock(currentBlocks, "text", payload["message"]);
|
|
95
109
|
break;
|
|
110
|
+
case "token_count": {
|
|
111
|
+
const info = (payload["info"] ?? {});
|
|
112
|
+
const usage = (info["total_token_usage"] ?? {});
|
|
113
|
+
totalInputTokens = toNumber(usage["input_tokens"]) ?? totalInputTokens;
|
|
114
|
+
totalOutputTokens = toNumber(usage["output_tokens"]) ?? totalOutputTokens;
|
|
115
|
+
totalCacheReadTokens =
|
|
116
|
+
toNumber(usage["cached_input_tokens"]) ?? totalCacheReadTokens;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
else if (type === "response_item") {
|
|
99
122
|
switch (payload["type"]) {
|
|
123
|
+
case "message": {
|
|
124
|
+
const role = payload["role"];
|
|
125
|
+
const texts = extractTextFragments(payload["content"]);
|
|
126
|
+
if (role === "assistant") {
|
|
127
|
+
for (const text of texts) {
|
|
128
|
+
pushUniqueTextBlock(currentBlocks, "text", text);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (role === "user" && !currentUserMessage) {
|
|
132
|
+
currentUserMessage = texts.join("\n\n") || currentUserMessage;
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "reasoning": {
|
|
137
|
+
const reasoningText = extractTextFragments(payload["content"]).join("\n\n") ||
|
|
138
|
+
extractTextFragments(payload["summary"]).join("\n\n");
|
|
139
|
+
pushUniqueTextBlock(currentBlocks, "thinking", reasoningText);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
100
142
|
case "function_call": {
|
|
101
143
|
const callId = payload["call_id"] ?? randomUUID();
|
|
102
144
|
let toolInput = {};
|
|
@@ -116,15 +158,13 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
116
158
|
}
|
|
117
159
|
case "function_call_output": {
|
|
118
160
|
const output = payload["output"];
|
|
119
|
-
const
|
|
120
|
-
&& output.includes("Process exited with code")
|
|
121
|
-
&& !output.includes("code 0");
|
|
161
|
+
const exitCode = extractExitCode(output);
|
|
122
162
|
currentBlocks.push({
|
|
123
163
|
type: "tool_result",
|
|
124
164
|
tool_call_id: payload["call_id"] ?? "",
|
|
125
|
-
is_error:
|
|
165
|
+
is_error: exitCode !== null ? exitCode !== 0 : false,
|
|
126
166
|
result_content: output ?? null,
|
|
127
|
-
exit_code:
|
|
167
|
+
exit_code: exitCode,
|
|
128
168
|
});
|
|
129
169
|
break;
|
|
130
170
|
}
|
|
@@ -141,11 +181,7 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
141
181
|
}
|
|
142
182
|
}
|
|
143
183
|
}
|
|
144
|
-
const
|
|
145
|
-
const toolCallCount = allBlocks.filter(b => b.type === "tool_use").length;
|
|
146
|
-
const hasFileChanges = allBlocks.some(b => b.type === "tool_use" && ["write_file", "file_change", "create_file"].includes(b.tool_name));
|
|
147
|
-
const hasShellCommands = allBlocks.some(b => b.type === "tool_use" && ["exec_command", "bash", "shell"].includes(b.tool_name));
|
|
148
|
-
const hasThinking = allBlocks.some(b => b.type === "thinking");
|
|
184
|
+
const metrics = collectTraceMetrics(turns);
|
|
149
185
|
const startedAt = sessionMetaPayload["timestamp"] ?? events[0]?.["timestamp"] ?? new Date().toISOString();
|
|
150
186
|
const endedAt = events[events.length - 1]?.["timestamp"] ?? new Date().toISOString();
|
|
151
187
|
const partialTrace = {
|
|
@@ -163,24 +199,16 @@ export async function extractCodex(rolloutFileBuffer, submittedBy = "unknown") {
|
|
|
163
199
|
ended_at: endedAt,
|
|
164
200
|
turns,
|
|
165
201
|
turn_count: turns.length,
|
|
166
|
-
tool_call_count: toolCallCount,
|
|
167
|
-
has_tool_calls: toolCallCount > 0,
|
|
168
|
-
has_thinking_blocks:
|
|
169
|
-
has_file_changes: hasFileChanges,
|
|
170
|
-
has_shell_commands: hasShellCommands,
|
|
171
|
-
total_input_tokens:
|
|
172
|
-
total_output_tokens:
|
|
173
|
-
total_cache_read_tokens:
|
|
202
|
+
tool_call_count: metrics.toolCallCount,
|
|
203
|
+
has_tool_calls: metrics.toolCallCount > 0,
|
|
204
|
+
has_thinking_blocks: metrics.hasThinkingBlocks,
|
|
205
|
+
has_file_changes: metrics.hasFileChanges,
|
|
206
|
+
has_shell_commands: metrics.hasShellCommands,
|
|
207
|
+
total_input_tokens: totalInputTokens,
|
|
208
|
+
total_output_tokens: totalOutputTokens,
|
|
209
|
+
total_cache_read_tokens: totalCacheReadTokens,
|
|
174
210
|
content_fidelity: "full",
|
|
175
|
-
env_state:
|
|
176
|
-
git_branch: null,
|
|
177
|
-
inferred_file_tree: null,
|
|
178
|
-
inferred_changed_files: null,
|
|
179
|
-
inferred_error_files: null,
|
|
180
|
-
shell_exit_codes: null,
|
|
181
|
-
open_files_in_editor: null,
|
|
182
|
-
extraction_method: "passive",
|
|
183
|
-
},
|
|
211
|
+
env_state: createPassiveEnvState(),
|
|
184
212
|
score: null,
|
|
185
213
|
raw_r2_key: "",
|
|
186
214
|
normalized_r2_key: "",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/extractors/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/extractors/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContentBlock, EnvState, Turn } from "../types.js";
|
|
2
|
+
export declare function isShellToolName(toolName: string): boolean;
|
|
3
|
+
export declare function isFileMutationTool(toolName: string, toolInput: Record<string, unknown>): boolean;
|
|
4
|
+
export declare function collectTraceMetrics(turns: Turn[]): {
|
|
5
|
+
toolCallCount: number;
|
|
6
|
+
hasFileChanges: boolean;
|
|
7
|
+
hasShellCommands: boolean;
|
|
8
|
+
hasThinkingBlocks: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function createPassiveEnvState(overrides?: Partial<EnvState>): EnvState;
|
|
11
|
+
export declare function extractTextFragments(value: unknown): string[];
|
|
12
|
+
export declare function pushUniqueTextBlock(blocks: ContentBlock[], type: "text" | "thinking", text: string | null | undefined): void;
|
|
13
|
+
export declare function normalizeTimestamp(value: unknown): string | null;
|
|
14
|
+
//# sourceMappingURL=common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/extractors/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AA0BhE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAiBT;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE;;;;;EAehD;AAED,wBAAgB,qBAAqB,CACnC,SAAS,GAAE,OAAO,CAAC,QAAQ,CAAM,GAChC,QAAQ,CAWV;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CA2B7D;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EAAE,EACtB,IAAI,EAAE,MAAM,GAAG,UAAU,EACzB,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,IAAI,CAUN;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAShE"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const SHELL_TOOL_NAMES = ["exec_command", "bash", "shell", "write_stdin"];
|
|
2
|
+
const FILE_MUTATION_TOOL_NAMES = [
|
|
3
|
+
"apply_patch",
|
|
4
|
+
"write_file",
|
|
5
|
+
"create_file",
|
|
6
|
+
"delete_file",
|
|
7
|
+
"rename_file",
|
|
8
|
+
"move_file",
|
|
9
|
+
"file_change",
|
|
10
|
+
"edit",
|
|
11
|
+
"edit_file",
|
|
12
|
+
"multiedit",
|
|
13
|
+
"write",
|
|
14
|
+
];
|
|
15
|
+
function normalizeToolName(toolName) {
|
|
16
|
+
return toolName.trim().toLowerCase();
|
|
17
|
+
}
|
|
18
|
+
function toolNameMatches(toolName, candidate) {
|
|
19
|
+
const normalized = normalizeToolName(toolName);
|
|
20
|
+
return normalized === candidate || normalized.endsWith(`.${candidate}`);
|
|
21
|
+
}
|
|
22
|
+
export function isShellToolName(toolName) {
|
|
23
|
+
return SHELL_TOOL_NAMES.some((candidate) => toolNameMatches(toolName, candidate));
|
|
24
|
+
}
|
|
25
|
+
export function isFileMutationTool(toolName, toolInput) {
|
|
26
|
+
if (FILE_MUTATION_TOOL_NAMES.some((candidate) => toolNameMatches(toolName, candidate))) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (!isShellToolName(toolName))
|
|
30
|
+
return false;
|
|
31
|
+
const command = typeof toolInput.cmd === "string"
|
|
32
|
+
? toolInput.cmd
|
|
33
|
+
: typeof toolInput.command === "string"
|
|
34
|
+
? toolInput.command
|
|
35
|
+
: null;
|
|
36
|
+
return command !== null && /\bapply_patch\b|\bsed\s+-i\b|\bperl\s+-pi\b/.test(command);
|
|
37
|
+
}
|
|
38
|
+
export function collectTraceMetrics(turns) {
|
|
39
|
+
const allBlocks = turns.flatMap((turn) => turn.content);
|
|
40
|
+
const toolUses = allBlocks.filter((block) => block.type === "tool_use");
|
|
41
|
+
return {
|
|
42
|
+
toolCallCount: toolUses.length,
|
|
43
|
+
hasFileChanges: toolUses.some((block) => isFileMutationTool(block.tool_name, block.tool_input)),
|
|
44
|
+
hasShellCommands: toolUses.some((block) => isShellToolName(block.tool_name)),
|
|
45
|
+
hasThinkingBlocks: allBlocks.some((block) => block.type === "thinking"),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function createPassiveEnvState(overrides = {}) {
|
|
49
|
+
return {
|
|
50
|
+
git_branch: null,
|
|
51
|
+
inferred_file_tree: null,
|
|
52
|
+
inferred_changed_files: null,
|
|
53
|
+
inferred_error_files: null,
|
|
54
|
+
shell_exit_codes: null,
|
|
55
|
+
open_files_in_editor: null,
|
|
56
|
+
extraction_method: "passive",
|
|
57
|
+
...overrides,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function extractTextFragments(value) {
|
|
61
|
+
if (typeof value === "string") {
|
|
62
|
+
return value.trim() ? [value] : [];
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
return value.flatMap((item) => extractTextFragments(item));
|
|
66
|
+
}
|
|
67
|
+
if (!value || typeof value !== "object") {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const record = value;
|
|
71
|
+
if (typeof record.text === "string" && record.text.trim()) {
|
|
72
|
+
return [record.text];
|
|
73
|
+
}
|
|
74
|
+
const nested = [];
|
|
75
|
+
for (const key of ["content", "summary", "thinking", "message"]) {
|
|
76
|
+
if (key in record) {
|
|
77
|
+
nested.push(...extractTextFragments(record[key]));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return nested;
|
|
81
|
+
}
|
|
82
|
+
export function pushUniqueTextBlock(blocks, type, text) {
|
|
83
|
+
const normalized = text?.trim();
|
|
84
|
+
if (!normalized)
|
|
85
|
+
return;
|
|
86
|
+
const exists = blocks.some((block) => block.type === type && block.text === normalized);
|
|
87
|
+
if (!exists) {
|
|
88
|
+
blocks.push({ type, text: normalized });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function normalizeTimestamp(value) {
|
|
92
|
+
if (typeof value === "string" && value.trim())
|
|
93
|
+
return value;
|
|
94
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
95
|
+
const millis = value > 1_000_000_000_000 ? value : value * 1000;
|
|
96
|
+
return new Date(millis).toISOString();
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/extractors/common.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/extractors/cursor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/extractors/cursor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,eAAe,EAAoB,MAAM,aAAa,CAAC;AAsPnF,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,WAAW,SAAY,GACtB,OAAO,CAAC,eAAe,CAAC,CA2G1B"}
|
|
@@ -1,4 +1,164 @@
|
|
|
1
1
|
import { hashString, computeContentHash } from "../hash.js";
|
|
2
|
+
import { collectTraceMetrics, createPassiveEnvState, extractTextFragments, normalizeTimestamp, pushUniqueTextBlock, } from "./common.js";
|
|
3
|
+
function toNumber(value) {
|
|
4
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5
|
+
}
|
|
6
|
+
function hasCursorConversationPayload(blob) {
|
|
7
|
+
return Boolean(blob.role ||
|
|
8
|
+
blob.text ||
|
|
9
|
+
blob.content ||
|
|
10
|
+
blob.message ||
|
|
11
|
+
blob.markdown ||
|
|
12
|
+
blob.thinking ||
|
|
13
|
+
blob.usage ||
|
|
14
|
+
blob.tokenCount ||
|
|
15
|
+
blob.model ||
|
|
16
|
+
blob.modelName ||
|
|
17
|
+
blob.context?.openFiles ||
|
|
18
|
+
blob.openFiles ||
|
|
19
|
+
blob.relevantFiles ||
|
|
20
|
+
blob.recentlyViewedFiles ||
|
|
21
|
+
blob.workspaceUris ||
|
|
22
|
+
blob.attachedFolders ||
|
|
23
|
+
blob.attachedFoldersNew);
|
|
24
|
+
}
|
|
25
|
+
function readCursorBlob(db, sessionId, bubbleId) {
|
|
26
|
+
const keys = [
|
|
27
|
+
`bubbleId:${sessionId}:${bubbleId}`,
|
|
28
|
+
`agentKv:blob:${bubbleId}`,
|
|
29
|
+
];
|
|
30
|
+
for (const key of keys) {
|
|
31
|
+
const row = db
|
|
32
|
+
.prepare("SELECT value FROM cursorDiskKV WHERE key = ?")
|
|
33
|
+
.get(key);
|
|
34
|
+
if (!row)
|
|
35
|
+
continue;
|
|
36
|
+
try {
|
|
37
|
+
const blob = JSON.parse(row.value);
|
|
38
|
+
if (hasCursorConversationPayload(blob))
|
|
39
|
+
return blob;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
function cursorRole(header, blob) {
|
|
48
|
+
const role = blob.role?.toLowerCase();
|
|
49
|
+
if (role === "user" || role === "assistant")
|
|
50
|
+
return role;
|
|
51
|
+
const type = typeof blob.type === "number" ? blob.type : header.type;
|
|
52
|
+
return type === 1 ? "user" : "assistant";
|
|
53
|
+
}
|
|
54
|
+
function extractCursorTokenUsage(blob) {
|
|
55
|
+
const usage = blob.usage;
|
|
56
|
+
const tokenCount = blob.tokenCount;
|
|
57
|
+
const inputTokens = toNumber(usage?.promptTokens) ?? toNumber(tokenCount?.inputTokens);
|
|
58
|
+
const outputTokens = toNumber(usage?.completionTokens) ?? toNumber(tokenCount?.outputTokens);
|
|
59
|
+
if (inputTokens === null && outputTokens === null) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
input_tokens: inputTokens ?? 0,
|
|
64
|
+
output_tokens: outputTokens ?? 0,
|
|
65
|
+
cache_read_input_tokens: null,
|
|
66
|
+
cache_creation_input_tokens: null,
|
|
67
|
+
reasoning_tokens: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function normalizeCursorPath(value) {
|
|
71
|
+
if (!value.startsWith("file://"))
|
|
72
|
+
return value;
|
|
73
|
+
try {
|
|
74
|
+
return decodeURIComponent(new URL(value).pathname);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function extractCursorPaths(value) {
|
|
81
|
+
if (typeof value === "string") {
|
|
82
|
+
return value ? [normalizeCursorPath(value)] : [];
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return value.flatMap((item) => extractCursorPaths(item));
|
|
86
|
+
}
|
|
87
|
+
if (!value || typeof value !== "object") {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const record = value;
|
|
91
|
+
const paths = [];
|
|
92
|
+
for (const key of [
|
|
93
|
+
"path",
|
|
94
|
+
"uri",
|
|
95
|
+
"absolutePath",
|
|
96
|
+
"relativeWorkspacePath",
|
|
97
|
+
"relativePath",
|
|
98
|
+
"filePath",
|
|
99
|
+
]) {
|
|
100
|
+
if (key in record) {
|
|
101
|
+
paths.push(...extractCursorPaths(record[key]));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return paths;
|
|
105
|
+
}
|
|
106
|
+
function collectCursorOpenFiles(blob) {
|
|
107
|
+
const paths = [
|
|
108
|
+
blob.context?.openFiles,
|
|
109
|
+
blob.openFiles,
|
|
110
|
+
blob.relevantFiles,
|
|
111
|
+
blob.recentlyViewedFiles,
|
|
112
|
+
blob.workspaceUris,
|
|
113
|
+
blob.attachedFolders,
|
|
114
|
+
blob.attachedFoldersNew,
|
|
115
|
+
].flatMap((value) => extractCursorPaths(value));
|
|
116
|
+
return Array.from(new Set(paths.filter(Boolean)));
|
|
117
|
+
}
|
|
118
|
+
function extractCursorBlocks(blob) {
|
|
119
|
+
const blocks = [];
|
|
120
|
+
const thinkingText = extractTextFragments(blob.thinking).join("\n\n");
|
|
121
|
+
pushUniqueTextBlock(blocks, "thinking", thinkingText);
|
|
122
|
+
const messageText = [
|
|
123
|
+
blob.text,
|
|
124
|
+
blob.content,
|
|
125
|
+
blob.message,
|
|
126
|
+
blob.markdown,
|
|
127
|
+
].find((value) => typeof value === "string" && value.trim().length > 0);
|
|
128
|
+
pushUniqueTextBlock(blocks, "text", messageText ?? null);
|
|
129
|
+
return blocks;
|
|
130
|
+
}
|
|
131
|
+
function mergeUsage(left, right) {
|
|
132
|
+
if (!left && !right)
|
|
133
|
+
return null;
|
|
134
|
+
return {
|
|
135
|
+
input_tokens: (left?.input_tokens ?? 0) + (right?.input_tokens ?? 0),
|
|
136
|
+
output_tokens: (left?.output_tokens ?? 0) + (right?.output_tokens ?? 0),
|
|
137
|
+
cache_read_input_tokens: null,
|
|
138
|
+
cache_creation_input_tokens: null,
|
|
139
|
+
reasoning_tokens: null,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function appendCursorTurn(turns, nextTurn) {
|
|
143
|
+
const previousTurn = turns[turns.length - 1];
|
|
144
|
+
if (!previousTurn || previousTurn.role !== nextTurn.role) {
|
|
145
|
+
turns.push(nextTurn);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const previousBubbleIds = Array.isArray(previousTurn.source_metadata.bubbleIds)
|
|
149
|
+
? previousTurn.source_metadata.bubbleIds
|
|
150
|
+
: [previousTurn.source_metadata.bubbleId].filter(Boolean);
|
|
151
|
+
turns[turns.length - 1] = {
|
|
152
|
+
...previousTurn,
|
|
153
|
+
content: [...previousTurn.content, ...nextTurn.content],
|
|
154
|
+
usage: mergeUsage(previousTurn.usage, nextTurn.usage),
|
|
155
|
+
model: previousTurn.model ?? nextTurn.model,
|
|
156
|
+
source_metadata: {
|
|
157
|
+
...previousTurn.source_metadata,
|
|
158
|
+
bubbleIds: [...previousBubbleIds, nextTurn.source_metadata.bubbleId].filter(Boolean),
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
2
162
|
export async function extractCursor(dbPath, sessionId, submittedBy = "unknown") {
|
|
3
163
|
const Database = (await import("better-sqlite3")).default;
|
|
4
164
|
const db = new Database(dbPath, { readonly: true });
|
|
@@ -9,52 +169,56 @@ export async function extractCursor(dbPath, sessionId, submittedBy = "unknown")
|
|
|
9
169
|
if (!composerRow)
|
|
10
170
|
throw new Error(`Session ${sessionId} not found in cursor DB`);
|
|
11
171
|
const composerData = JSON.parse(composerRow.value);
|
|
12
|
-
const headers = composerData.fullConversationHeadersOnly ?? [];
|
|
172
|
+
const headers = (composerData.fullConversationHeadersOnly ?? []);
|
|
13
173
|
const turns = [];
|
|
14
174
|
const openFiles = [];
|
|
175
|
+
let totalInputTokens = 0;
|
|
176
|
+
let totalOutputTokens = 0;
|
|
15
177
|
for (const header of headers) {
|
|
16
178
|
const bubbleId = header.bubbleId ?? header.id;
|
|
17
179
|
if (!bubbleId)
|
|
18
180
|
continue;
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
.get(`agentKv:blob:${bubbleId}`);
|
|
22
|
-
if (!blobRow)
|
|
181
|
+
const blob = readCursorBlob(db, sessionId, bubbleId);
|
|
182
|
+
if (!blob)
|
|
23
183
|
continue;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
184
|
+
const role = cursorRole(header, blob);
|
|
185
|
+
const tokenUsage = extractCursorTokenUsage(blob);
|
|
186
|
+
if (tokenUsage) {
|
|
187
|
+
totalInputTokens += tokenUsage.input_tokens;
|
|
188
|
+
totalOutputTokens += tokenUsage.output_tokens;
|
|
29
189
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
cache_creation_input_tokens: null,
|
|
36
|
-
reasoning_tokens: null,
|
|
37
|
-
}
|
|
38
|
-
: null;
|
|
39
|
-
turns.push({
|
|
190
|
+
openFiles.push(...collectCursorOpenFiles(blob));
|
|
191
|
+
const content = extractCursorBlocks(blob);
|
|
192
|
+
if (content.length === 0)
|
|
193
|
+
continue;
|
|
194
|
+
appendCursorTurn(turns, {
|
|
40
195
|
turn_id: bubbleId,
|
|
41
196
|
parent_turn_id: null,
|
|
42
197
|
role,
|
|
43
|
-
timestamp: blob.createdAt ?? header.createdAt
|
|
44
|
-
content
|
|
45
|
-
model: blob.model ?? null,
|
|
198
|
+
timestamp: normalizeTimestamp(blob.createdAt ?? header.createdAt),
|
|
199
|
+
content,
|
|
200
|
+
model: blob.model ?? blob.modelName ?? null,
|
|
46
201
|
usage: tokenUsage,
|
|
47
|
-
source_metadata: { bubbleId, type: blob.type },
|
|
202
|
+
source_metadata: { bubbleId, type: blob.type ?? header.type ?? null },
|
|
48
203
|
});
|
|
49
204
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
205
|
+
if (turns.length === 0) {
|
|
206
|
+
throw new Error(`Session ${sessionId} contained no readable conversation bubbles`);
|
|
207
|
+
}
|
|
208
|
+
const metrics = collectTraceMetrics(turns);
|
|
209
|
+
const startedAt = turns[0]?.timestamp ??
|
|
210
|
+
normalizeTimestamp(composerData.createdAt) ??
|
|
211
|
+
new Date().toISOString();
|
|
212
|
+
const endedAt = turns[turns.length - 1]?.timestamp ??
|
|
213
|
+
normalizeTimestamp(composerData.createdAt) ??
|
|
214
|
+
new Date().toISOString();
|
|
53
215
|
const partialTrace = {
|
|
54
216
|
schema_version: "1.0",
|
|
55
217
|
source_tool: "cursor",
|
|
56
218
|
source_session_id: sessionId,
|
|
57
|
-
source_version:
|
|
219
|
+
source_version: typeof composerData._v === "number" || typeof composerData._v === "string"
|
|
220
|
+
? String(composerData._v)
|
|
221
|
+
: null,
|
|
58
222
|
submitted_by: submittedBy,
|
|
59
223
|
submitted_at: new Date().toISOString(),
|
|
60
224
|
extracted_at: new Date().toISOString(),
|
|
@@ -65,24 +229,18 @@ export async function extractCursor(dbPath, sessionId, submittedBy = "unknown")
|
|
|
65
229
|
ended_at: endedAt,
|
|
66
230
|
turns,
|
|
67
231
|
turn_count: turns.length,
|
|
68
|
-
tool_call_count:
|
|
69
|
-
has_tool_calls:
|
|
70
|
-
has_thinking_blocks:
|
|
71
|
-
has_file_changes:
|
|
72
|
-
has_shell_commands:
|
|
73
|
-
total_input_tokens: null,
|
|
74
|
-
total_output_tokens: null,
|
|
232
|
+
tool_call_count: metrics.toolCallCount,
|
|
233
|
+
has_tool_calls: metrics.toolCallCount > 0,
|
|
234
|
+
has_thinking_blocks: metrics.hasThinkingBlocks,
|
|
235
|
+
has_file_changes: metrics.hasFileChanges,
|
|
236
|
+
has_shell_commands: metrics.hasShellCommands,
|
|
237
|
+
total_input_tokens: totalInputTokens || null,
|
|
238
|
+
total_output_tokens: totalOutputTokens || null,
|
|
75
239
|
total_cache_read_tokens: null,
|
|
76
240
|
content_fidelity: "chat_only",
|
|
77
|
-
env_state: {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
inferred_changed_files: null,
|
|
81
|
-
inferred_error_files: null,
|
|
82
|
-
shell_exit_codes: null,
|
|
83
|
-
open_files_in_editor: openFiles.length > 0 ? openFiles : null,
|
|
84
|
-
extraction_method: "passive",
|
|
85
|
-
},
|
|
241
|
+
env_state: createPassiveEnvState({
|
|
242
|
+
open_files_in_editor: openFiles.length > 0 ? Array.from(new Set(openFiles)) : null,
|
|
243
|
+
}),
|
|
86
244
|
score: null,
|
|
87
245
|
raw_r2_key: "",
|
|
88
246
|
normalized_r2_key: "",
|
|
@@ -92,8 +250,10 @@ export async function extractCursor(dbPath, sessionId, submittedBy = "unknown")
|
|
|
92
250
|
return { ...partialTrace, trace_id: traceId };
|
|
93
251
|
}
|
|
94
252
|
catch (err) {
|
|
95
|
-
db.close();
|
|
96
253
|
throw err;
|
|
97
254
|
}
|
|
255
|
+
finally {
|
|
256
|
+
db.close();
|
|
257
|
+
}
|
|
98
258
|
}
|
|
99
259
|
//# sourceMappingURL=cursor.js.map
|