codesesh 0.15.0 → 0.16.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 +1 -0
- package/dist/chunk-EWC6IODK.js +166 -0
- package/dist/chunk-EWC6IODK.js.map +1 -0
- package/dist/{chunk-NBCLV4CX.js → chunk-MWSJTNOW.js} +682 -356
- package/dist/chunk-MWSJTNOW.js.map +1 -0
- package/dist/{dist-5356XOFP.js → dist-AIDCOQZO.js} +20 -2
- package/dist/index.js +131 -239
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +2 -1
- package/dist/scan-refresh-worker.js.map +1 -1
- package/dist/search-index-worker.js +11 -2
- package/dist/search-index-worker.js.map +1 -1
- package/dist/smart-tag-worker.js +2 -1
- package/dist/smart-tag-worker.js.map +1 -1
- package/dist/web/assets/index-BpmbwB2_.js +113 -0
- package/dist/web/assets/index-Bxe686Vr.css +2 -0
- package/dist/web/assets/{syntax-C_RLNYQn.js → syntax-mZXQuVcd.js} +1 -1
- package/dist/web/assets/vendor-BVE7Fps8.js +41 -0
- package/dist/web/icon/agent/cursor.svg +1 -12
- package/dist/web/icon/agent/pi.svg +2 -2
- package/dist/web/index.html +55 -4
- package/package.json +1 -1
- package/dist/chunk-NBCLV4CX.js.map +0 -1
- package/dist/web/assets/index-B6p64k_Q.js +0 -113
- package/dist/web/assets/index-DiFr4_5-.css +0 -2
- package/dist/web/assets/vendor-CShgXaOi.js +0 -40
- /package/dist/{dist-5356XOFP.js.map → dist-AIDCOQZO.js.map} +0 -0
|
@@ -78,6 +78,7 @@ function getAgentInfoMap(sessionsByAgent) {
|
|
|
78
78
|
name: agent.name,
|
|
79
79
|
displayName: agent.displayName,
|
|
80
80
|
icon: registration.icon,
|
|
81
|
+
iconColored: registration.iconColored,
|
|
81
82
|
count: sessionsByAgent[agent.name] ?? 0
|
|
82
83
|
};
|
|
83
84
|
});
|
|
@@ -85,6 +86,23 @@ function getAgentInfoMap(sessionsByAgent) {
|
|
|
85
86
|
function getAgentByName(name) {
|
|
86
87
|
return registrations.find((registration) => registration.create().name === name);
|
|
87
88
|
}
|
|
89
|
+
var diagnostics = null;
|
|
90
|
+
function toSafeSink(sink) {
|
|
91
|
+
return {
|
|
92
|
+
warn(event, detail) {
|
|
93
|
+
try {
|
|
94
|
+
sink.warn(event, detail);
|
|
95
|
+
} catch {
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function setCoreDiagnostics(next) {
|
|
101
|
+
diagnostics = next ? toSafeSink(next) : null;
|
|
102
|
+
}
|
|
103
|
+
function getCoreDiagnostics() {
|
|
104
|
+
return diagnostics;
|
|
105
|
+
}
|
|
88
106
|
function parsedSession(session) {
|
|
89
107
|
return { status: "parsed", data: session };
|
|
90
108
|
}
|
|
@@ -117,7 +135,12 @@ var FileSystemSessionSource = class extends BaseAgent {
|
|
|
117
135
|
try {
|
|
118
136
|
const session = this.scanSessionSource(source.sourcePath, options);
|
|
119
137
|
if (session) sessions.push(session);
|
|
120
|
-
} catch {
|
|
138
|
+
} catch (error) {
|
|
139
|
+
getCoreDiagnostics()?.warn("agent.session_parse_failed", {
|
|
140
|
+
agentName: this.name,
|
|
141
|
+
sourcePath: source.sourcePath,
|
|
142
|
+
message: error instanceof Error ? error.message : String(error)
|
|
143
|
+
});
|
|
121
144
|
continue;
|
|
122
145
|
} finally {
|
|
123
146
|
options?.onProgress?.({
|
|
@@ -156,18 +179,20 @@ var FileSystemSessionSource = class extends BaseAgent {
|
|
|
156
179
|
return {
|
|
157
180
|
hasChanges: changedIdList.length > 0,
|
|
158
181
|
changedIds: changedIdList,
|
|
159
|
-
timestamp: Date.now()
|
|
182
|
+
timestamp: Date.now(),
|
|
183
|
+
refs: currentRefs
|
|
160
184
|
};
|
|
161
185
|
}
|
|
162
186
|
/**
|
|
163
187
|
* 增量扫描:对变更/新增源调用 scanSessionSource 重解析,
|
|
164
188
|
* 删除已消失的源,合并回 cachedSessions。
|
|
189
|
+
* refs 未传时回退为自行枚举,供独立调用方(如测试)沿用旧行为。
|
|
165
190
|
*/
|
|
166
|
-
incrementalScan(cachedSessions, changedIds) {
|
|
191
|
+
incrementalScan(cachedSessions, changedIds, refs) {
|
|
167
192
|
const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));
|
|
168
193
|
const changedSet = new Set(changedIds);
|
|
169
194
|
const currentIds = /* @__PURE__ */ new Set();
|
|
170
|
-
for (const ref of this.listSessionSources()) {
|
|
195
|
+
for (const ref of refs ?? this.listSessionSources()) {
|
|
171
196
|
currentIds.add(ref.sessionId);
|
|
172
197
|
if (!changedSet.has(ref.sessionId)) continue;
|
|
173
198
|
const head = this.scanSessionSource(ref.sourcePath);
|
|
@@ -283,14 +308,21 @@ function getZCodeDataPath() {
|
|
|
283
308
|
}
|
|
284
309
|
var READ_CHUNK_BYTES = 1 << 20;
|
|
285
310
|
function* parseJsonlLines(content) {
|
|
311
|
+
let total = 0;
|
|
312
|
+
let skipped = 0;
|
|
286
313
|
for (const line of content.split("\n")) {
|
|
287
314
|
const trimmed = line.trim();
|
|
288
315
|
if (!trimmed) continue;
|
|
316
|
+
total += 1;
|
|
289
317
|
try {
|
|
290
318
|
yield JSON.parse(trimmed);
|
|
291
319
|
} catch {
|
|
320
|
+
skipped += 1;
|
|
292
321
|
}
|
|
293
322
|
}
|
|
323
|
+
if (skipped > 0) {
|
|
324
|
+
getCoreDiagnostics()?.warn("agent.jsonl_lines_skipped", { skipped, total });
|
|
325
|
+
}
|
|
294
326
|
}
|
|
295
327
|
function* readJsonlFileLines(filePath, chunkBytes = READ_CHUNK_BYTES) {
|
|
296
328
|
const fd = openSync(filePath, "r");
|
|
@@ -315,12 +347,19 @@ function* readJsonlFileLines(filePath, chunkBytes = READ_CHUNK_BYTES) {
|
|
|
315
347
|
}
|
|
316
348
|
}
|
|
317
349
|
function* readJsonlFile(filePath) {
|
|
350
|
+
let total = 0;
|
|
351
|
+
let skipped = 0;
|
|
318
352
|
for (const line of readJsonlFileLines(filePath)) {
|
|
353
|
+
total += 1;
|
|
319
354
|
try {
|
|
320
355
|
yield JSON.parse(line);
|
|
321
356
|
} catch {
|
|
357
|
+
skipped += 1;
|
|
322
358
|
}
|
|
323
359
|
}
|
|
360
|
+
if (skipped > 0) {
|
|
361
|
+
getCoreDiagnostics()?.warn("agent.jsonl_lines_skipped", { skipped, total, filePath });
|
|
362
|
+
}
|
|
324
363
|
}
|
|
325
364
|
var INTERNAL_TAGS = [
|
|
326
365
|
"command-message",
|
|
@@ -794,6 +833,43 @@ function withEstimatedSessionCost(stats, model) {
|
|
|
794
833
|
function estimateTokenCost(model, tokens) {
|
|
795
834
|
return estimateCostForTokens(model, tokens)?.cost ?? null;
|
|
796
835
|
}
|
|
836
|
+
function asRecord(value) {
|
|
837
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
838
|
+
return value;
|
|
839
|
+
}
|
|
840
|
+
return void 0;
|
|
841
|
+
}
|
|
842
|
+
function asString(value) {
|
|
843
|
+
return typeof value === "string" ? value : void 0;
|
|
844
|
+
}
|
|
845
|
+
function asNumber(value) {
|
|
846
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
847
|
+
}
|
|
848
|
+
function asArray(value) {
|
|
849
|
+
return Array.isArray(value) ? value : void 0;
|
|
850
|
+
}
|
|
851
|
+
function safeParseJsonRecord(json) {
|
|
852
|
+
let raw;
|
|
853
|
+
try {
|
|
854
|
+
raw = JSON.parse(json);
|
|
855
|
+
} catch {
|
|
856
|
+
return void 0;
|
|
857
|
+
}
|
|
858
|
+
return asRecord(raw);
|
|
859
|
+
}
|
|
860
|
+
var reportedFieldMismatches = /* @__PURE__ */ new Set();
|
|
861
|
+
function reportFieldMismatch(agentName, field) {
|
|
862
|
+
const key = `${agentName}\0${field}`;
|
|
863
|
+
if (reportedFieldMismatches.has(key)) return;
|
|
864
|
+
reportedFieldMismatches.add(key);
|
|
865
|
+
getCoreDiagnostics()?.warn("agent.field_shape_mismatch", { agentName, field });
|
|
866
|
+
}
|
|
867
|
+
function narrowField(agent, field, value, narrow) {
|
|
868
|
+
if (value === void 0 || value === null) return void 0;
|
|
869
|
+
const result = narrow(value);
|
|
870
|
+
if (result === void 0) reportFieldMismatch(agent, field);
|
|
871
|
+
return result;
|
|
872
|
+
}
|
|
797
873
|
var TranscriptBuilder = class {
|
|
798
874
|
constructor(options = {}) {
|
|
799
875
|
this.options = options;
|
|
@@ -969,31 +1045,48 @@ var TranscriptBuilder = class {
|
|
|
969
1045
|
};
|
|
970
1046
|
var HEAD_INDEX_VERSION = "claudecode-head-v2";
|
|
971
1047
|
function parseTimestampMs(data) {
|
|
972
|
-
const raw =
|
|
973
|
-
|
|
1048
|
+
const raw = data["timestamp"];
|
|
1049
|
+
const value = asString(raw);
|
|
1050
|
+
if (value === void 0) {
|
|
1051
|
+
if (raw !== void 0 && raw !== null) reportFieldMismatch("claudecode", "timestamp");
|
|
1052
|
+
return 0;
|
|
1053
|
+
}
|
|
1054
|
+
const trimmed = value.trim();
|
|
1055
|
+
if (!trimmed) return 0;
|
|
974
1056
|
try {
|
|
975
|
-
return new Date(
|
|
1057
|
+
return new Date(trimmed.includes("Z") ? trimmed : trimmed + "Z").getTime();
|
|
976
1058
|
} catch {
|
|
977
1059
|
return 0;
|
|
978
1060
|
}
|
|
979
1061
|
}
|
|
980
|
-
function
|
|
981
|
-
|
|
1062
|
+
function readUsageNumber(usage, field) {
|
|
1063
|
+
const raw = usage[field];
|
|
1064
|
+
if (raw === void 0) return 0;
|
|
1065
|
+
const value = asNumber(raw);
|
|
1066
|
+
if (value === void 0) {
|
|
1067
|
+
reportFieldMismatch("claudecode", `message.usage.${field}`);
|
|
1068
|
+
return 0;
|
|
1069
|
+
}
|
|
1070
|
+
return value;
|
|
982
1071
|
}
|
|
983
1072
|
function extractClaudeUsage(data, msg) {
|
|
984
|
-
const
|
|
985
|
-
if (
|
|
986
|
-
const
|
|
1073
|
+
const rawUsage = msg["usage"];
|
|
1074
|
+
if (rawUsage === void 0 || rawUsage === null) return null;
|
|
1075
|
+
const usage = asRecord(rawUsage);
|
|
1076
|
+
if (!usage) {
|
|
1077
|
+
reportFieldMismatch("claudecode", "message.usage");
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
987
1080
|
const requestId = typeof data["requestId"] === "string" ? data["requestId"].trim() : "";
|
|
988
1081
|
const uuid = typeof data["uuid"] === "string" ? data["uuid"].trim() : "";
|
|
989
1082
|
const key = requestId || uuid;
|
|
990
1083
|
if (!key) return null;
|
|
991
1084
|
return {
|
|
992
1085
|
key,
|
|
993
|
-
input:
|
|
994
|
-
output:
|
|
995
|
-
cacheRead:
|
|
996
|
-
cacheCreate:
|
|
1086
|
+
input: readUsageNumber(usage, "input_tokens"),
|
|
1087
|
+
output: readUsageNumber(usage, "output_tokens"),
|
|
1088
|
+
cacheRead: readUsageNumber(usage, "cache_read_input_tokens"),
|
|
1089
|
+
cacheCreate: readUsageNumber(usage, "cache_creation_input_tokens")
|
|
997
1090
|
};
|
|
998
1091
|
}
|
|
999
1092
|
var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
@@ -1025,17 +1118,20 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1025
1118
|
if (!this.basePath) return [];
|
|
1026
1119
|
const refs = [];
|
|
1027
1120
|
for (const projectDir of this.listProjectDirs()) {
|
|
1121
|
+
const indexPath = this.getSessionsIndexPath(projectDir);
|
|
1028
1122
|
for (const file of this.listJsonlFiles(projectDir)) {
|
|
1123
|
+
let stat;
|
|
1029
1124
|
try {
|
|
1030
|
-
|
|
1125
|
+
stat = statSync2(file);
|
|
1031
1126
|
} catch {
|
|
1032
1127
|
continue;
|
|
1033
1128
|
}
|
|
1129
|
+
if (!matchesScanWindow(stat.mtimeMs, options)) continue;
|
|
1034
1130
|
const sessionId = basename2(file, ".jsonl");
|
|
1035
1131
|
refs.push({
|
|
1036
1132
|
sessionId,
|
|
1037
1133
|
sourcePath: file,
|
|
1038
|
-
fingerprint: this.sourceFingerprint(
|
|
1134
|
+
fingerprint: this.sourceFingerprint(stat, indexPath)
|
|
1039
1135
|
});
|
|
1040
1136
|
}
|
|
1041
1137
|
}
|
|
@@ -1098,12 +1194,13 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1098
1194
|
}
|
|
1099
1195
|
buildSessionMeta(head, file, projectDir) {
|
|
1100
1196
|
const indexPath = this.getSessionsIndexPath(projectDir);
|
|
1197
|
+
const stat = statSync2(file);
|
|
1101
1198
|
return {
|
|
1102
1199
|
id: head.id,
|
|
1103
1200
|
title: head.title,
|
|
1104
1201
|
sourcePath: file,
|
|
1105
|
-
sourceFingerprint: this.sourceFingerprint(
|
|
1106
|
-
sourceMtimeMs:
|
|
1202
|
+
sourceFingerprint: this.sourceFingerprint(stat, indexPath),
|
|
1203
|
+
sourceMtimeMs: stat.mtimeMs,
|
|
1107
1204
|
indexPath: existsSync4(indexPath) ? indexPath : null,
|
|
1108
1205
|
indexMtimeMs: this.getFileMtimeMs(indexPath),
|
|
1109
1206
|
headIndexVersion: HEAD_INDEX_VERSION,
|
|
@@ -1114,9 +1211,8 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1114
1211
|
updatedAt: head.time_updated ?? head.time_created
|
|
1115
1212
|
};
|
|
1116
1213
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
const indexPath = this.getSessionsIndexPath(projectDir);
|
|
1214
|
+
/** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */
|
|
1215
|
+
sourceFingerprint(stat, indexPath) {
|
|
1120
1216
|
return JSON.stringify([
|
|
1121
1217
|
HEAD_INDEX_VERSION,
|
|
1122
1218
|
stat.mtimeMs,
|
|
@@ -1188,7 +1284,8 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1188
1284
|
let totalCost = 0;
|
|
1189
1285
|
const modelUsageMap = {};
|
|
1190
1286
|
const countedUsageKeys = /* @__PURE__ */ new Set();
|
|
1191
|
-
|
|
1287
|
+
let messageTitle = null;
|
|
1288
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
1192
1289
|
try {
|
|
1193
1290
|
const data = JSON.parse(line);
|
|
1194
1291
|
if (isInternalEventType(data["type"])) continue;
|
|
@@ -1197,15 +1294,25 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1197
1294
|
if (!cwd && data["cwd"] && typeof data["cwd"] === "string") {
|
|
1198
1295
|
cwd = data["cwd"];
|
|
1199
1296
|
}
|
|
1200
|
-
const msg = data["message"];
|
|
1201
|
-
if (msg &&
|
|
1202
|
-
|
|
1203
|
-
|
|
1297
|
+
const msg = asRecord(data["message"]);
|
|
1298
|
+
if (!msg && data["message"] !== void 0 && data["message"] !== null) {
|
|
1299
|
+
reportFieldMismatch("claudecode", "message");
|
|
1300
|
+
}
|
|
1301
|
+
if (msg) {
|
|
1302
|
+
const role = asString(msg["role"]);
|
|
1303
|
+
if (msg["role"] !== void 0 && role === void 0) {
|
|
1304
|
+
reportFieldMismatch("claudecode", "message.role");
|
|
1305
|
+
}
|
|
1306
|
+
if (role?.trim()) {
|
|
1204
1307
|
messageCount++;
|
|
1205
1308
|
}
|
|
1206
1309
|
if (!model) {
|
|
1207
|
-
const m = msg["model"];
|
|
1208
|
-
if (
|
|
1310
|
+
const m = asString(msg["model"]);
|
|
1311
|
+
if (m?.trim()) model = m.trim();
|
|
1312
|
+
}
|
|
1313
|
+
if (messageTitle === null && lineIndex < 20 && role === "user") {
|
|
1314
|
+
const candidate = this.extractUserMessageTitle(msg["content"]);
|
|
1315
|
+
if (candidate) messageTitle = candidate;
|
|
1209
1316
|
}
|
|
1210
1317
|
if (role === "assistant") {
|
|
1211
1318
|
const usage = extractClaudeUsage(data, msg);
|
|
@@ -1219,8 +1326,8 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1219
1326
|
totalOutputTokens += outputTokens;
|
|
1220
1327
|
totalCacheReadTokens += cacheRead;
|
|
1221
1328
|
totalCacheCreateTokens += cacheCreate;
|
|
1222
|
-
const m = msg["model"];
|
|
1223
|
-
if (
|
|
1329
|
+
const m = asString(msg["model"]);
|
|
1330
|
+
if (m?.trim()) {
|
|
1224
1331
|
const name = m.trim();
|
|
1225
1332
|
const msgTotal = inputTokens + cacheRead + cacheCreate + outputTokens;
|
|
1226
1333
|
modelUsageMap[name] = (modelUsageMap[name] ?? 0) + msgTotal;
|
|
@@ -1239,7 +1346,6 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1239
1346
|
}
|
|
1240
1347
|
}
|
|
1241
1348
|
const directory = cwd ?? projectDir;
|
|
1242
|
-
const messageTitle = this.extractTitle(lines);
|
|
1243
1349
|
const directoryTitle = basenameTitle(directory) || basenameTitle(projectDir);
|
|
1244
1350
|
const title = resolveSessionTitle(explicitTitle, messageTitle, directoryTitle);
|
|
1245
1351
|
const hasModelUsage = Object.keys(modelUsageMap).length > 0;
|
|
@@ -1263,27 +1369,20 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1263
1369
|
model_usage: hasModelUsage ? modelUsageMap : void 0
|
|
1264
1370
|
});
|
|
1265
1371
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
if (Array.isArray(content)) {
|
|
1281
|
-
const texts = content.filter((item) => typeof item === "object" && item !== null && "text" in item).map((item) => String(item["text"] ?? "")).join(" ");
|
|
1282
|
-
const title = normalizeTitleText(texts);
|
|
1283
|
-
if (title) return title;
|
|
1284
|
-
}
|
|
1285
|
-
} catch {
|
|
1286
|
-
}
|
|
1372
|
+
/** Mirrors the title-candidate extraction previously done in a second JSON.parse pass. */
|
|
1373
|
+
extractUserMessageTitle(content) {
|
|
1374
|
+
if (!content) return null;
|
|
1375
|
+
if (typeof content === "string") {
|
|
1376
|
+
const title = normalizeTitleText(content);
|
|
1377
|
+
return title || null;
|
|
1378
|
+
}
|
|
1379
|
+
if (Array.isArray(content)) {
|
|
1380
|
+
const texts = content.filter((item) => {
|
|
1381
|
+
const record = asRecord(item);
|
|
1382
|
+
return record !== void 0 && "text" in record;
|
|
1383
|
+
}).map((item) => String(item["text"] ?? "")).join(" ");
|
|
1384
|
+
const title = normalizeTitleText(texts);
|
|
1385
|
+
return title || null;
|
|
1287
1386
|
}
|
|
1288
1387
|
return null;
|
|
1289
1388
|
}
|
|
@@ -1301,56 +1400,54 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1301
1400
|
}
|
|
1302
1401
|
}
|
|
1303
1402
|
convertAssistantRecord(data, builder, assistantUuidToToolCalls, countedUsageKeys) {
|
|
1304
|
-
const msg = data["message"] ?? {};
|
|
1403
|
+
const msg = asRecord(data["message"]) ?? {};
|
|
1305
1404
|
const timestampMs = parseTimestampMs(data);
|
|
1306
|
-
const rawContent = msg["content"] ?? [];
|
|
1405
|
+
const rawContent = asArray(msg["content"]) ?? [];
|
|
1307
1406
|
const uuid = String(data["uuid"] ?? "");
|
|
1308
1407
|
const toolCallIds = [];
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
this.applyAssistantMetadata(message2, data, msg, countedUsageKeys);
|
|
1323
|
-
}
|
|
1324
|
-
continue;
|
|
1325
|
-
}
|
|
1326
|
-
if (partType === "text") {
|
|
1327
|
-
const text = cleanInternalText(String(part["text"] ?? ""));
|
|
1328
|
-
if (text) {
|
|
1329
|
-
const message2 = builder.appendAssistantPart(
|
|
1330
|
-
this.buildTextPart(text, timestampMs),
|
|
1331
|
-
{
|
|
1332
|
-
id: uuid,
|
|
1333
|
-
timestampMs,
|
|
1334
|
-
agent: "claude"
|
|
1335
|
-
},
|
|
1336
|
-
{ deduplicateTail: true }
|
|
1337
|
-
);
|
|
1338
|
-
this.applyAssistantMetadata(message2, data, msg, countedUsageKeys);
|
|
1339
|
-
}
|
|
1340
|
-
continue;
|
|
1408
|
+
for (const item of rawContent) {
|
|
1409
|
+
const part = asRecord(item);
|
|
1410
|
+
if (!part) continue;
|
|
1411
|
+
const partType = String(part["type"] ?? "");
|
|
1412
|
+
if (partType === "thinking") {
|
|
1413
|
+
const text = cleanInternalText(String(part["thinking"] ?? ""));
|
|
1414
|
+
if (text) {
|
|
1415
|
+
const message2 = builder.appendAssistantPart(
|
|
1416
|
+
this.buildReasoningPart(text, timestampMs),
|
|
1417
|
+
{ id: uuid, timestampMs, agent: "claude" },
|
|
1418
|
+
{ deduplicateTail: true }
|
|
1419
|
+
);
|
|
1420
|
+
this.applyAssistantMetadata(message2, data, msg, countedUsageKeys);
|
|
1341
1421
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
const
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1422
|
+
continue;
|
|
1423
|
+
}
|
|
1424
|
+
if (partType === "text") {
|
|
1425
|
+
const text = cleanInternalText(String(part["text"] ?? ""));
|
|
1426
|
+
if (text) {
|
|
1427
|
+
const message2 = builder.appendAssistantPart(
|
|
1428
|
+
this.buildTextPart(text, timestampMs),
|
|
1429
|
+
{
|
|
1430
|
+
id: uuid,
|
|
1431
|
+
timestampMs,
|
|
1432
|
+
agent: "claude"
|
|
1433
|
+
},
|
|
1434
|
+
{ deduplicateTail: true }
|
|
1435
|
+
);
|
|
1436
|
+
this.applyAssistantMetadata(message2, data, msg, countedUsageKeys);
|
|
1353
1437
|
}
|
|
1438
|
+
continue;
|
|
1439
|
+
}
|
|
1440
|
+
if (partType !== "tool_use") continue;
|
|
1441
|
+
const toolCallId = String(part["id"] ?? "").trim();
|
|
1442
|
+
const toolPart = this.buildToolPart(part, timestampMs);
|
|
1443
|
+
const message = builder.appendToolCall(
|
|
1444
|
+
toolPart,
|
|
1445
|
+
{ id: uuid, timestampMs, agent: "claude" },
|
|
1446
|
+
{ modeOnCreate: "tool" }
|
|
1447
|
+
);
|
|
1448
|
+
this.applyAssistantMetadata(message, data, msg, countedUsageKeys);
|
|
1449
|
+
if (toolCallId) {
|
|
1450
|
+
toolCallIds.push(toolCallId);
|
|
1354
1451
|
}
|
|
1355
1452
|
}
|
|
1356
1453
|
if (toolCallIds.length > 0) {
|
|
@@ -1358,7 +1455,7 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1358
1455
|
}
|
|
1359
1456
|
}
|
|
1360
1457
|
convertUserRecord(data, builder, assistantUuidToToolCalls) {
|
|
1361
|
-
const msg = data["message"] ?? {};
|
|
1458
|
+
const msg = asRecord(data["message"]) ?? {};
|
|
1362
1459
|
const timestampMs = parseTimestampMs(data);
|
|
1363
1460
|
const content = msg["content"] ?? "";
|
|
1364
1461
|
const uuid = String(data["uuid"] ?? "");
|
|
@@ -1378,9 +1475,8 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1378
1475
|
const visibleParts = this.normalizeUserTextParts(content, timestampMs);
|
|
1379
1476
|
const toolStateUpdates = this.extractToolStateUpdates(data["toolUseResult"]);
|
|
1380
1477
|
for (const item of content) {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
if (ci["type"] !== "tool_result") continue;
|
|
1478
|
+
const ci = asRecord(item);
|
|
1479
|
+
if (!ci || ci["type"] !== "tool_result") continue;
|
|
1384
1480
|
const toolCallId = this.resolveToolCallId(data, ci, assistantUuidToToolCalls);
|
|
1385
1481
|
const outputParts = this.normalizeClaudeToolOutput(ci["content"], timestampMs);
|
|
1386
1482
|
if (this.backfillToolOutput(builder, toolCallId, outputParts, toolStateUpdates)) {
|
|
@@ -1401,7 +1497,7 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1401
1497
|
}
|
|
1402
1498
|
convertToolResultRecord(data, builder) {
|
|
1403
1499
|
const timestampMs = parseTimestampMs(data);
|
|
1404
|
-
const msg = data["message"] ?? {};
|
|
1500
|
+
const msg = asRecord(data["message"]) ?? {};
|
|
1405
1501
|
const outputParts = this.normalizeClaudeToolOutput(msg["content"], timestampMs);
|
|
1406
1502
|
const uuid = String(data["uuid"] ?? "");
|
|
1407
1503
|
const fallback = this.buildFallbackToolMessage({
|
|
@@ -1463,8 +1559,8 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1463
1559
|
if (!Array.isArray(content)) return [];
|
|
1464
1560
|
const parts = [];
|
|
1465
1561
|
for (const item of content) {
|
|
1466
|
-
|
|
1467
|
-
|
|
1562
|
+
const ci = asRecord(item);
|
|
1563
|
+
if (ci) {
|
|
1468
1564
|
if (ci["type"] === "tool_result") continue;
|
|
1469
1565
|
const text = cleanInternalText(String(ci["text"] ?? ""));
|
|
1470
1566
|
if (text) parts.push(this.buildTextPart(text, timestampMs));
|
|
@@ -1484,12 +1580,13 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1484
1580
|
if (Array.isArray(content)) {
|
|
1485
1581
|
const parts = [];
|
|
1486
1582
|
for (const item of content) {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const
|
|
1490
|
-
if (itemRecord["type"] === "image" &&
|
|
1491
|
-
const
|
|
1492
|
-
const
|
|
1583
|
+
const itemRecord = asRecord(item);
|
|
1584
|
+
if (itemRecord) {
|
|
1585
|
+
const rawSource = itemRecord["source"];
|
|
1586
|
+
if (itemRecord["type"] === "image" && rawSource) {
|
|
1587
|
+
const source = asRecord(rawSource);
|
|
1588
|
+
const data = asString(source?.["data"]) ?? "";
|
|
1589
|
+
const mimeType = asString(source?.["media_type"]) ?? "";
|
|
1493
1590
|
if (data && mimeType.startsWith("image/")) {
|
|
1494
1591
|
parts.push({ type: "image", data, mime_type: mimeType, time_created: timestampMs });
|
|
1495
1592
|
}
|
|
@@ -1533,8 +1630,8 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1533
1630
|
return "";
|
|
1534
1631
|
}
|
|
1535
1632
|
extractToolStateUpdates(toolUseResult) {
|
|
1536
|
-
|
|
1537
|
-
|
|
1633
|
+
const result = asRecord(toolUseResult);
|
|
1634
|
+
if (!result) return {};
|
|
1538
1635
|
const updates = {};
|
|
1539
1636
|
const success = result["success"];
|
|
1540
1637
|
if (typeof success === "boolean") {
|
|
@@ -1558,11 +1655,19 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1558
1655
|
}
|
|
1559
1656
|
};
|
|
1560
1657
|
var DatabaseConstructor = null;
|
|
1658
|
+
var loadErrorMessage = null;
|
|
1561
1659
|
try {
|
|
1562
1660
|
const require2 = createRequire(import.meta.url);
|
|
1563
1661
|
const mod = require2("better-sqlite3");
|
|
1564
1662
|
DatabaseConstructor = typeof mod === "function" ? mod : mod.default;
|
|
1565
|
-
} catch {
|
|
1663
|
+
} catch (error) {
|
|
1664
|
+
loadErrorMessage = error instanceof Error ? error.message : String(error);
|
|
1665
|
+
}
|
|
1666
|
+
var unavailableReported = false;
|
|
1667
|
+
function reportUnavailableOnce() {
|
|
1668
|
+
if (unavailableReported) return;
|
|
1669
|
+
unavailableReported = true;
|
|
1670
|
+
getCoreDiagnostics()?.warn("sqlite.unavailable", { message: loadErrorMessage });
|
|
1566
1671
|
}
|
|
1567
1672
|
function quoteIdentifier(value) {
|
|
1568
1673
|
return `"${value.replaceAll('"', '""')}"`;
|
|
@@ -1657,16 +1762,27 @@ function runSchemaMigrations(db, options) {
|
|
|
1657
1762
|
return backups;
|
|
1658
1763
|
}
|
|
1659
1764
|
function openDbReadOnly(dbPath) {
|
|
1660
|
-
if (!DatabaseConstructor)
|
|
1765
|
+
if (!DatabaseConstructor) {
|
|
1766
|
+
reportUnavailableOnce();
|
|
1767
|
+
return null;
|
|
1768
|
+
}
|
|
1661
1769
|
try {
|
|
1662
1770
|
const db = DatabaseConstructor(dbPath, { readonly: true });
|
|
1663
1771
|
return db;
|
|
1664
|
-
} catch {
|
|
1772
|
+
} catch (error) {
|
|
1773
|
+
getCoreDiagnostics()?.warn("sqlite.open_failed", {
|
|
1774
|
+
dbPath,
|
|
1775
|
+
readonly: true,
|
|
1776
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1777
|
+
});
|
|
1665
1778
|
return null;
|
|
1666
1779
|
}
|
|
1667
1780
|
}
|
|
1668
1781
|
function openDb(dbPath) {
|
|
1669
|
-
if (!DatabaseConstructor)
|
|
1782
|
+
if (!DatabaseConstructor) {
|
|
1783
|
+
reportUnavailableOnce();
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1670
1786
|
try {
|
|
1671
1787
|
mkdirSync2(dirname2(dbPath), { recursive: true });
|
|
1672
1788
|
const db = DatabaseConstructor(dbPath);
|
|
@@ -1674,16 +1790,42 @@ function openDb(dbPath) {
|
|
|
1674
1790
|
db.pragma("journal_mode = WAL");
|
|
1675
1791
|
db.pragma("synchronous = NORMAL");
|
|
1676
1792
|
db.pragma("foreign_keys = ON");
|
|
1793
|
+
db.pragma("busy_timeout = 5000");
|
|
1677
1794
|
} catch {
|
|
1678
1795
|
}
|
|
1679
1796
|
return db;
|
|
1680
|
-
} catch {
|
|
1797
|
+
} catch (error) {
|
|
1798
|
+
getCoreDiagnostics()?.warn("sqlite.open_failed", {
|
|
1799
|
+
dbPath,
|
|
1800
|
+
readonly: false,
|
|
1801
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1802
|
+
});
|
|
1681
1803
|
return null;
|
|
1682
1804
|
}
|
|
1683
1805
|
}
|
|
1684
1806
|
function isSqliteAvailable() {
|
|
1685
1807
|
return DatabaseConstructor !== null;
|
|
1686
1808
|
}
|
|
1809
|
+
var MESSAGE_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool"]);
|
|
1810
|
+
function parseJsonRecord(raw, agentName, field) {
|
|
1811
|
+
const parsed = asRecord(JSON.parse(String(raw ?? "{}")));
|
|
1812
|
+
if (parsed) return parsed;
|
|
1813
|
+
reportFieldMismatch(agentName, field);
|
|
1814
|
+
return {};
|
|
1815
|
+
}
|
|
1816
|
+
function narrowMessageRole(value) {
|
|
1817
|
+
const role = asString(value);
|
|
1818
|
+
return role !== void 0 && MESSAGE_ROLES.has(role) ? role : void 0;
|
|
1819
|
+
}
|
|
1820
|
+
function parseMessageRole(value, agentName) {
|
|
1821
|
+
return narrowField(agentName, "message.role", value, narrowMessageRole) ?? "assistant";
|
|
1822
|
+
}
|
|
1823
|
+
function parseTokens(value, agentName) {
|
|
1824
|
+
return narrowField(agentName, "message.tokens", value, asRecord);
|
|
1825
|
+
}
|
|
1826
|
+
function parseModel(value, agentName) {
|
|
1827
|
+
return narrowField(agentName, "message.modelID", value, asString) ?? null;
|
|
1828
|
+
}
|
|
1687
1829
|
var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
1688
1830
|
constructor(config) {
|
|
1689
1831
|
super();
|
|
@@ -1815,7 +1957,7 @@ var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
|
1815
1957
|
).all(cutoffTime);
|
|
1816
1958
|
}
|
|
1817
1959
|
parsePartRow(partRow) {
|
|
1818
|
-
const partData =
|
|
1960
|
+
const partData = parseJsonRecord(partRow.data, this.name, "part.data");
|
|
1819
1961
|
const partType = String(partData.type ?? "");
|
|
1820
1962
|
if (isInternalEventType(partType)) return null;
|
|
1821
1963
|
if (partType === "text" || partType === "reasoning") {
|
|
@@ -1833,7 +1975,7 @@ var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
|
1833
1975
|
tool: String(partData.tool ?? ""),
|
|
1834
1976
|
callID: String(partData.callID ?? ""),
|
|
1835
1977
|
title: cleanInternalText(String(partData.title ?? "")),
|
|
1836
|
-
state: partData.state ?? {},
|
|
1978
|
+
state: asRecord(partData.state) ?? {},
|
|
1837
1979
|
time_created: Number(partRow.time_created ?? 0)
|
|
1838
1980
|
};
|
|
1839
1981
|
}
|
|
@@ -1865,7 +2007,7 @@ var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
|
1865
2007
|
for (const row of messageRows) {
|
|
1866
2008
|
const sessionId = String(row.session_id ?? "");
|
|
1867
2009
|
if (!sessionId) continue;
|
|
1868
|
-
const msgData =
|
|
2010
|
+
const msgData = parseJsonRecord(row.data, this.name, "message.data");
|
|
1869
2011
|
if (isInternalEventType(msgData.type)) continue;
|
|
1870
2012
|
const parts = partsByMessage.get(String(row.id ?? "")) ?? [];
|
|
1871
2013
|
if (parts.length === 0) continue;
|
|
@@ -1883,10 +2025,10 @@ var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
|
1883
2025
|
contexts.set(sessionId, context);
|
|
1884
2026
|
}
|
|
1885
2027
|
const cost = Number(msgData.cost ?? 0);
|
|
1886
|
-
const tokens = msgData.tokens;
|
|
2028
|
+
const tokens = parseTokens(msgData.tokens, this.name);
|
|
1887
2029
|
const inputTokens = Number(tokens?.input ?? 0);
|
|
1888
2030
|
const outputTokens = Number(tokens?.output ?? 0);
|
|
1889
|
-
const model = msgData.modelID
|
|
2031
|
+
const model = parseModel(msgData.modelID, this.name);
|
|
1890
2032
|
const estimatedCost = cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });
|
|
1891
2033
|
if (estimatedCost !== null) context.stats.cost_source = "estimated";
|
|
1892
2034
|
context.stats.total_cost += cost || estimatedCost || 0;
|
|
@@ -1940,24 +2082,24 @@ var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
|
1940
2082
|
let hasEstimatedCost = false;
|
|
1941
2083
|
const msgRows = db.prepare("SELECT * FROM message WHERE session_id = ? ORDER BY time_created ASC").all(sessionId);
|
|
1942
2084
|
for (const msgRow of msgRows) {
|
|
1943
|
-
const msgData =
|
|
2085
|
+
const msgData = parseJsonRecord(msgRow.data, this.name, "message.data");
|
|
1944
2086
|
if (isInternalEventType(msgData.type)) continue;
|
|
1945
2087
|
const cost = Number(msgData.cost ?? 0);
|
|
1946
|
-
const tokens = msgData.tokens;
|
|
2088
|
+
const tokens = parseTokens(msgData.tokens, this.name);
|
|
1947
2089
|
const inputTokens = Number(tokens?.input ?? 0);
|
|
1948
2090
|
const outputTokens = Number(tokens?.output ?? 0);
|
|
1949
|
-
const model = msgData.modelID
|
|
2091
|
+
const model = parseModel(msgData.modelID, this.name);
|
|
1950
2092
|
const estimatedCost = cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });
|
|
1951
2093
|
const resolvedCost = cost || estimatedCost || 0;
|
|
1952
2094
|
const parts = this.readMessageParts(db, msgRow.id);
|
|
1953
2095
|
if (parts.length === 0) continue;
|
|
1954
2096
|
messages.push({
|
|
1955
2097
|
id: String(msgRow.id ?? ""),
|
|
1956
|
-
role:
|
|
1957
|
-
agent: msgData.agent ?? null,
|
|
1958
|
-
mode: msgData.mode ?? null,
|
|
2098
|
+
role: parseMessageRole(msgData.role, this.name),
|
|
2099
|
+
agent: asString(msgData.agent) ?? null,
|
|
2100
|
+
mode: asString(msgData.mode) ?? null,
|
|
1959
2101
|
model,
|
|
1960
|
-
provider: msgData.providerID ?? null,
|
|
2102
|
+
provider: asString(msgData.providerID) ?? null,
|
|
1961
2103
|
time_created: Number(msgRow.time_created ?? 0),
|
|
1962
2104
|
tokens: tokens ? { input: inputTokens, output: outputTokens } : void 0,
|
|
1963
2105
|
cost: resolvedCost,
|
|
@@ -1982,7 +2124,7 @@ var OpenCodeSqliteAgent = class extends DatabaseSessionSource {
|
|
|
1982
2124
|
title,
|
|
1983
2125
|
slug,
|
|
1984
2126
|
directory,
|
|
1985
|
-
version: sessionRow.version ?? void 0,
|
|
2127
|
+
version: asString(sessionRow.version) ?? void 0,
|
|
1986
2128
|
time_created: timeCreated,
|
|
1987
2129
|
time_updated: timeUpdated,
|
|
1988
2130
|
summary_files: sessionRow.summary_files ?? void 0,
|
|
@@ -2026,6 +2168,15 @@ var KIMI_IGNORED_TOOLS = /* @__PURE__ */ new Set(["SetTodoList"]);
|
|
|
2026
2168
|
function mapToolTitle(toolName) {
|
|
2027
2169
|
return KIMI_TOOL_TITLE_MAP[toolName] ?? toolName;
|
|
2028
2170
|
}
|
|
2171
|
+
function readWireMtime(record) {
|
|
2172
|
+
return narrowField("kimi", "session.wire_mtime", record.wire_mtime, asNumber) ?? null;
|
|
2173
|
+
}
|
|
2174
|
+
function readWireTimestamp(record) {
|
|
2175
|
+
return narrowField("kimi", "wire.timestamp", record.timestamp, asNumber) ?? 0;
|
|
2176
|
+
}
|
|
2177
|
+
function extractTokenField(usage, field) {
|
|
2178
|
+
return narrowField("kimi", `usage.${field}`, usage[field], asNumber) ?? 0;
|
|
2179
|
+
}
|
|
2029
2180
|
function normalizeToolArguments(raw) {
|
|
2030
2181
|
if (typeof raw === "string") {
|
|
2031
2182
|
try {
|
|
@@ -2044,8 +2195,9 @@ function normalizeToolOutputParts(content, timestampMs) {
|
|
|
2044
2195
|
if (Array.isArray(content)) {
|
|
2045
2196
|
const parts = [];
|
|
2046
2197
|
for (const item of content) {
|
|
2047
|
-
|
|
2048
|
-
|
|
2198
|
+
const record = asRecord(item);
|
|
2199
|
+
if (record && "text" in record) {
|
|
2200
|
+
const text2 = String(record.text ?? "");
|
|
2049
2201
|
const cleaned = cleanInternalText(text2);
|
|
2050
2202
|
if (cleaned) parts.push({ type: "text", text: cleaned, time_created: timestampMs });
|
|
2051
2203
|
} else if (typeof item === "string") {
|
|
@@ -2077,10 +2229,8 @@ function kimiContentText(content) {
|
|
|
2077
2229
|
if (!Array.isArray(content)) return "";
|
|
2078
2230
|
return content.map((item) => {
|
|
2079
2231
|
if (typeof item === "string") return item;
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
return String(record.text ?? record.content ?? "");
|
|
2083
|
-
}
|
|
2232
|
+
const record = asRecord(item);
|
|
2233
|
+
if (record) return String(record.text ?? record.content ?? "");
|
|
2084
2234
|
return "";
|
|
2085
2235
|
}).join(" ");
|
|
2086
2236
|
}
|
|
@@ -2096,9 +2246,9 @@ function extractFirstUserTitle(contextFile, wireFile) {
|
|
|
2096
2246
|
if (wireFile && existsSync6(wireFile)) {
|
|
2097
2247
|
const content = readFileSync3(wireFile, "utf-8");
|
|
2098
2248
|
for (const record of parseJsonlLines(content)) {
|
|
2099
|
-
const message = record.message ?? {};
|
|
2249
|
+
const message = asRecord(record.message) ?? {};
|
|
2100
2250
|
if (message.type !== "TurnBegin") continue;
|
|
2101
|
-
const payload = message.payload ?? {};
|
|
2251
|
+
const payload = asRecord(message.payload) ?? {};
|
|
2102
2252
|
const userInput = payload.user_input;
|
|
2103
2253
|
if (!Array.isArray(userInput)) continue;
|
|
2104
2254
|
const title = normalizeTitleText(kimiContentText(userInput));
|
|
@@ -2128,12 +2278,12 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2128
2278
|
}
|
|
2129
2279
|
if (!existsSync6(configPath)) return;
|
|
2130
2280
|
try {
|
|
2131
|
-
const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
2132
|
-
const workDirs = raw?.work_dirs;
|
|
2133
|
-
if (!
|
|
2281
|
+
const raw = asRecord(JSON.parse(readFileSync3(configPath, "utf-8")));
|
|
2282
|
+
const workDirs = asArray(raw?.work_dirs);
|
|
2283
|
+
if (!workDirs) return;
|
|
2134
2284
|
for (const wd of workDirs) {
|
|
2135
|
-
const path2 = wd
|
|
2136
|
-
if (
|
|
2285
|
+
const path2 = asString(asRecord(wd)?.path);
|
|
2286
|
+
if (!path2) continue;
|
|
2137
2287
|
const hash = createHash("md5").update(path2).digest("hex");
|
|
2138
2288
|
this.projectMap.set(hash, path2);
|
|
2139
2289
|
}
|
|
@@ -2192,14 +2342,14 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2192
2342
|
let wireMtime = null;
|
|
2193
2343
|
let metaFile = "";
|
|
2194
2344
|
if (existsSync6(statePath)) {
|
|
2195
|
-
const state = JSON.parse(readFileSync3(statePath, "utf-8"));
|
|
2345
|
+
const state = asRecord(JSON.parse(readFileSync3(statePath, "utf-8"))) ?? {};
|
|
2196
2346
|
title = String(state.custom_title ?? "");
|
|
2197
|
-
wireMtime =
|
|
2347
|
+
wireMtime = readWireMtime(state);
|
|
2198
2348
|
metaFile = statePath;
|
|
2199
2349
|
} else if (existsSync6(metaPath)) {
|
|
2200
|
-
const meta = JSON.parse(readFileSync3(metaPath, "utf-8"));
|
|
2350
|
+
const meta = asRecord(JSON.parse(readFileSync3(metaPath, "utf-8"))) ?? {};
|
|
2201
2351
|
title = String(meta.title ?? "");
|
|
2202
|
-
wireMtime =
|
|
2352
|
+
wireMtime = readWireMtime(meta);
|
|
2203
2353
|
metaFile = metaPath;
|
|
2204
2354
|
}
|
|
2205
2355
|
const cwd = this.projectMap.get(projectHash) || "";
|
|
@@ -2328,16 +2478,15 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2328
2478
|
for (const record of parseJsonlLines(content)) {
|
|
2329
2479
|
seq++;
|
|
2330
2480
|
try {
|
|
2331
|
-
const message = record.message ?? {};
|
|
2332
|
-
const msgType =
|
|
2481
|
+
const message = asRecord(record.message) ?? {};
|
|
2482
|
+
const msgType = asString(message.type) ?? "";
|
|
2333
2483
|
if (isInternalEventType(msgType)) continue;
|
|
2334
|
-
const payload = message.payload ?? {};
|
|
2335
|
-
const
|
|
2336
|
-
const
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
const
|
|
2340
|
-
const outputTokens = Number(usage["output_tokens"] ?? 0);
|
|
2484
|
+
const payload = asRecord(message.payload) ?? {};
|
|
2485
|
+
const timestampMs = Math.floor(readWireTimestamp(record) * 1e3);
|
|
2486
|
+
const usage = asRecord(message["usage"]);
|
|
2487
|
+
if (usage) {
|
|
2488
|
+
const inputTokens = extractTokenField(usage, "input_tokens");
|
|
2489
|
+
const outputTokens = extractTokenField(usage, "output_tokens");
|
|
2341
2490
|
if (inputTokens || outputTokens) {
|
|
2342
2491
|
const tokens = { input: inputTokens, output: outputTokens };
|
|
2343
2492
|
const cost = estimateTokenCost(this.defaultModel, tokens);
|
|
@@ -2389,7 +2538,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2389
2538
|
continue;
|
|
2390
2539
|
}
|
|
2391
2540
|
if (msgType === "ToolCall") {
|
|
2392
|
-
const function_ = payload.function;
|
|
2541
|
+
const function_ = asRecord(payload.function);
|
|
2393
2542
|
const toolName = String(function_?.name ?? "").trim();
|
|
2394
2543
|
const callId = String(payload.id ?? "").trim();
|
|
2395
2544
|
if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {
|
|
@@ -2475,8 +2624,8 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2475
2624
|
const content = record.content;
|
|
2476
2625
|
if (Array.isArray(content)) {
|
|
2477
2626
|
for (const item of content) {
|
|
2478
|
-
|
|
2479
|
-
|
|
2627
|
+
const ci = asRecord(item);
|
|
2628
|
+
if (!ci) continue;
|
|
2480
2629
|
const partType = String(ci.type ?? "");
|
|
2481
2630
|
if (partType === "think") {
|
|
2482
2631
|
const text = cleanInternalText(String(ci.think ?? ""));
|
|
@@ -2487,15 +2636,14 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2487
2636
|
}
|
|
2488
2637
|
}
|
|
2489
2638
|
}
|
|
2490
|
-
const toolCalls = record.tool_calls;
|
|
2491
|
-
if (
|
|
2639
|
+
const toolCalls = asArray(record.tool_calls);
|
|
2640
|
+
if (toolCalls) {
|
|
2492
2641
|
for (const tc of toolCalls) {
|
|
2493
|
-
|
|
2494
|
-
const
|
|
2495
|
-
const function_ = tcRecord.function;
|
|
2642
|
+
const tcRecord = asRecord(tc);
|
|
2643
|
+
const function_ = asRecord(tcRecord?.function);
|
|
2496
2644
|
if (!function_) continue;
|
|
2497
2645
|
const toolName = String(function_.name ?? "").trim();
|
|
2498
|
-
const callId = String(tcRecord
|
|
2646
|
+
const callId = String(tcRecord?.id ?? "").trim();
|
|
2499
2647
|
if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {
|
|
2500
2648
|
ignoredToolCallIds.add(callId);
|
|
2501
2649
|
continue;
|
|
@@ -2560,11 +2708,11 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2560
2708
|
const content = readFileSync3(wirePath, "utf-8");
|
|
2561
2709
|
for (const line of content.split("\n").filter((l) => l.trim())) {
|
|
2562
2710
|
try {
|
|
2563
|
-
const data = JSON.parse(line);
|
|
2564
|
-
const tokenUsage = data
|
|
2711
|
+
const data = asRecord(JSON.parse(line));
|
|
2712
|
+
const tokenUsage = asRecord(asRecord(data?.message)?.usage);
|
|
2565
2713
|
if (!tokenUsage) continue;
|
|
2566
|
-
const inputTokens =
|
|
2567
|
-
const outputTokens =
|
|
2714
|
+
const inputTokens = extractTokenField(tokenUsage, "input_tokens");
|
|
2715
|
+
const outputTokens = extractTokenField(tokenUsage, "output_tokens");
|
|
2568
2716
|
stats.total_input_tokens += inputTokens;
|
|
2569
2717
|
stats.total_output_tokens += outputTokens;
|
|
2570
2718
|
const cost = estimateTokenCost(this.defaultModel, {
|
|
@@ -2584,10 +2732,14 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2584
2732
|
const rawContent = readFileSync3(rawPath, "utf-8");
|
|
2585
2733
|
for (const line of rawContent.split("\n").filter((l) => l.trim())) {
|
|
2586
2734
|
try {
|
|
2587
|
-
const data = JSON.parse(line);
|
|
2588
|
-
if (data
|
|
2589
|
-
|
|
2735
|
+
const data = asRecord(JSON.parse(line));
|
|
2736
|
+
if (data?.role !== "_usage") continue;
|
|
2737
|
+
const tokenCount = asNumber(data.token_count);
|
|
2738
|
+
if (tokenCount === void 0) {
|
|
2739
|
+
reportFieldMismatch("kimi", "usage.token_count");
|
|
2740
|
+
continue;
|
|
2590
2741
|
}
|
|
2742
|
+
stats.total_tokens = tokenCount;
|
|
2591
2743
|
} catch {
|
|
2592
2744
|
}
|
|
2593
2745
|
}
|
|
@@ -2917,6 +3069,19 @@ function extractCachedInputTokens(usage) {
|
|
|
2917
3069
|
if (!usage) return 0;
|
|
2918
3070
|
return Number(usage["cached_input_tokens"] ?? usage["cache_read_input_tokens"] ?? 0);
|
|
2919
3071
|
}
|
|
3072
|
+
function narrowRecordField(value, field) {
|
|
3073
|
+
return narrowField("codex", field, value, asRecord);
|
|
3074
|
+
}
|
|
3075
|
+
function extractPayload(data) {
|
|
3076
|
+
return narrowRecordField(data["payload"], "payload") ?? {};
|
|
3077
|
+
}
|
|
3078
|
+
function extractTokenUsage(payload) {
|
|
3079
|
+
const info = narrowRecordField(payload["info"], "token_count.info");
|
|
3080
|
+
return {
|
|
3081
|
+
totalUsage: info ? narrowRecordField(info["total_token_usage"], "token_count.total_token_usage") : void 0,
|
|
3082
|
+
lastUsage: info ? narrowRecordField(info["last_token_usage"], "token_count.last_token_usage") : void 0
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
2920
3085
|
function resolveToolIdentity(name, namespace) {
|
|
2921
3086
|
const mappedName = CODEX_TOOL_TITLE_MAP[name];
|
|
2922
3087
|
if (mappedName) return { tool: mappedName };
|
|
@@ -2956,11 +3121,8 @@ function flattenOutputText(output) {
|
|
|
2956
3121
|
if (Array.isArray(output)) {
|
|
2957
3122
|
return output.map((item) => {
|
|
2958
3123
|
if (typeof item === "string") return item;
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
if (typeof text === "string") return text;
|
|
2962
|
-
}
|
|
2963
|
-
return "";
|
|
3124
|
+
const record = asRecord(item);
|
|
3125
|
+
return record ? asString(record["text"]) ?? "" : "";
|
|
2964
3126
|
}).join("");
|
|
2965
3127
|
}
|
|
2966
3128
|
return "";
|
|
@@ -3071,10 +3233,10 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3071
3233
|
listSessionSources(options) {
|
|
3072
3234
|
if (!this.basePath) return [];
|
|
3073
3235
|
this.loadSessionIndex();
|
|
3074
|
-
return this.listRolloutFiles(options).map((file) => ({
|
|
3236
|
+
return this.listRolloutFiles(options).map(({ file, stat }) => ({
|
|
3075
3237
|
sessionId: extractSessionId(file),
|
|
3076
3238
|
sourcePath: file,
|
|
3077
|
-
fingerprint: this.sourceFingerprint(file)
|
|
3239
|
+
fingerprint: this.sourceFingerprint(file, stat)
|
|
3078
3240
|
}));
|
|
3079
3241
|
}
|
|
3080
3242
|
scanSessionSource(sourcePath, options) {
|
|
@@ -3105,20 +3267,18 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3105
3267
|
try {
|
|
3106
3268
|
const recordType = String(record["type"] ?? "");
|
|
3107
3269
|
if (recordType === "turn_context") {
|
|
3108
|
-
const payload = record
|
|
3270
|
+
const payload = extractPayload(record);
|
|
3109
3271
|
activeModel = extractModelName(payload["model"]) ?? activeModel;
|
|
3110
3272
|
}
|
|
3111
3273
|
pendingPlan = this.convertRecord(record, transcript, pendingPlan, activeModel);
|
|
3112
3274
|
if (recordType === "event_msg") {
|
|
3113
|
-
const payload = record
|
|
3275
|
+
const payload = extractPayload(record);
|
|
3114
3276
|
if (String(payload["type"] ?? "") === "token_count") {
|
|
3115
|
-
const
|
|
3116
|
-
const totalUsage = info?.["total_token_usage"];
|
|
3277
|
+
const { totalUsage, lastUsage } = extractTokenUsage(payload);
|
|
3117
3278
|
const cumulativeTotal = Number(totalUsage?.["total_tokens"] ?? 0);
|
|
3118
3279
|
if (cumulativeTotal > 0 && cumulativeTotal === prevCumulativeTotal) {
|
|
3119
3280
|
} else {
|
|
3120
3281
|
prevCumulativeTotal = cumulativeTotal;
|
|
3121
|
-
const lastUsage = info?.["last_token_usage"];
|
|
3122
3282
|
let inputTokens = 0;
|
|
3123
3283
|
let outputTokens = 0;
|
|
3124
3284
|
let reasoningTokens = 0;
|
|
@@ -3193,6 +3353,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3193
3353
|
return [];
|
|
3194
3354
|
}
|
|
3195
3355
|
}
|
|
3356
|
+
/** Stats each rollout file once during the walk; caller reuses it for the scan window check and the fingerprint. */
|
|
3196
3357
|
walkDirForRolloutFiles(dir, options) {
|
|
3197
3358
|
const files = [];
|
|
3198
3359
|
try {
|
|
@@ -3201,14 +3362,14 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3201
3362
|
if (entry.isDirectory()) {
|
|
3202
3363
|
files.push(...this.walkDirForRolloutFiles(fullPath, options));
|
|
3203
3364
|
} else if (entry.name.endsWith(".jsonl") && entry.name.startsWith("rollout-")) {
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
}
|
|
3365
|
+
let stat;
|
|
3366
|
+
try {
|
|
3367
|
+
stat = statSync4(fullPath);
|
|
3368
|
+
} catch {
|
|
3369
|
+
continue;
|
|
3210
3370
|
}
|
|
3211
|
-
|
|
3371
|
+
if (!matchesScanWindow(stat.mtimeMs, options)) continue;
|
|
3372
|
+
files.push({ file: fullPath, stat });
|
|
3212
3373
|
}
|
|
3213
3374
|
}
|
|
3214
3375
|
} catch {
|
|
@@ -3217,12 +3378,13 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3217
3378
|
}
|
|
3218
3379
|
buildSessionMeta(head, file) {
|
|
3219
3380
|
const indexPath = this.getSessionIndexPath();
|
|
3381
|
+
const stat = statSync4(file);
|
|
3220
3382
|
return {
|
|
3221
3383
|
id: head.id,
|
|
3222
3384
|
title: head.title,
|
|
3223
3385
|
sourcePath: file,
|
|
3224
|
-
sourceFingerprint: this.sourceFingerprint(file),
|
|
3225
|
-
sourceMtimeMs:
|
|
3386
|
+
sourceFingerprint: this.sourceFingerprint(file, stat),
|
|
3387
|
+
sourceMtimeMs: stat.mtimeMs,
|
|
3226
3388
|
indexPath: existsSync7(indexPath) ? indexPath : null,
|
|
3227
3389
|
indexMtimeMs: this.getFileMtimeMs(indexPath),
|
|
3228
3390
|
headIndexVersion: HEAD_INDEX_VERSION2,
|
|
@@ -3234,8 +3396,8 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3234
3396
|
updatedAt: head.time_updated ?? head.time_created
|
|
3235
3397
|
};
|
|
3236
3398
|
}
|
|
3237
|
-
|
|
3238
|
-
|
|
3399
|
+
/** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */
|
|
3400
|
+
sourceFingerprint(file, stat) {
|
|
3239
3401
|
const sessionId = extractSessionId(file);
|
|
3240
3402
|
return JSON.stringify([
|
|
3241
3403
|
HEAD_INDEX_VERSION2,
|
|
@@ -3302,7 +3464,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3302
3464
|
let firstPayload = {};
|
|
3303
3465
|
let createdAt = 0;
|
|
3304
3466
|
let lineCount = 0;
|
|
3305
|
-
|
|
3467
|
+
let messageTitle = null;
|
|
3306
3468
|
let updatedAt = 0;
|
|
3307
3469
|
let messageCount = 0;
|
|
3308
3470
|
let model = null;
|
|
@@ -3328,20 +3490,23 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3328
3490
|
} catch {
|
|
3329
3491
|
return skippedSession("malformed first record");
|
|
3330
3492
|
}
|
|
3331
|
-
firstPayload = firstRecord
|
|
3493
|
+
firstPayload = extractPayload(firstRecord);
|
|
3332
3494
|
createdAt = parseTimestampMs2(firstRecord) || parseTimestampMs2(firstPayload) || statSync4(filePath).mtimeMs;
|
|
3333
3495
|
updatedAt = createdAt;
|
|
3334
3496
|
}
|
|
3335
|
-
if (titleLines.length < 20) titleLines.push(line);
|
|
3336
3497
|
try {
|
|
3337
3498
|
const data = JSON.parse(line);
|
|
3338
3499
|
const recordType = String(data["type"] ?? "");
|
|
3339
|
-
const payload = data
|
|
3500
|
+
const payload = extractPayload(data);
|
|
3340
3501
|
const payloadType = String(payload["type"] ?? "");
|
|
3341
3502
|
if (isInternalEventType2(recordType) || isInternalEventType2(payloadType)) continue;
|
|
3342
3503
|
hasNonInternalRecord = true;
|
|
3343
|
-
const recordTs = parseTimestampMs2(data) || parseTimestampMs2(
|
|
3504
|
+
const recordTs = parseTimestampMs2(data) || parseTimestampMs2(payload);
|
|
3344
3505
|
if (recordTs > updatedAt) updatedAt = recordTs;
|
|
3506
|
+
if (messageTitle === null && lineCount <= 20) {
|
|
3507
|
+
const candidate = this.extractCodexRecordTitle(data);
|
|
3508
|
+
if (candidate) messageTitle = candidate;
|
|
3509
|
+
}
|
|
3345
3510
|
if (recordType === "session_meta" || recordType === "turn_context") {
|
|
3346
3511
|
const nextModel = extractModelName(payload["model"]);
|
|
3347
3512
|
if (nextModel) {
|
|
@@ -3356,7 +3521,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3356
3521
|
if (COUNTED_TYPES.has(pType)) {
|
|
3357
3522
|
messageCount++;
|
|
3358
3523
|
}
|
|
3359
|
-
const info = p["info"];
|
|
3524
|
+
const info = narrowRecordField(p["info"], "response_item.info");
|
|
3360
3525
|
const m = info?.["model"] ?? p["model"];
|
|
3361
3526
|
if (typeof m === "string" && m.trim()) {
|
|
3362
3527
|
activeModel = m.trim();
|
|
@@ -3364,14 +3529,11 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3364
3529
|
}
|
|
3365
3530
|
}
|
|
3366
3531
|
if (recordType === "event_msg") {
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
const info = p["info"];
|
|
3370
|
-
const totalUsage = info?.["total_token_usage"];
|
|
3532
|
+
if (String(payload["type"] ?? "") === "token_count") {
|
|
3533
|
+
const { totalUsage, lastUsage } = extractTokenUsage(payload);
|
|
3371
3534
|
const cumulativeTotal = Number(totalUsage?.["total_tokens"] ?? 0);
|
|
3372
3535
|
if (cumulativeTotal > 0 && cumulativeTotal !== scanPrevCumulativeTotal) {
|
|
3373
3536
|
scanPrevCumulativeTotal = cumulativeTotal;
|
|
3374
|
-
const lastUsage = info?.["last_token_usage"];
|
|
3375
3537
|
let inputTokens = 0;
|
|
3376
3538
|
let outputTokens = 0;
|
|
3377
3539
|
let reasoningTokens = 0;
|
|
@@ -3416,7 +3578,6 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3416
3578
|
if (lineCount === 0) return skippedSession("empty file");
|
|
3417
3579
|
if (!hasNonInternalRecord) return filteredSession("internal events only");
|
|
3418
3580
|
const indexTitle = this.getTitleForSession(sessionId);
|
|
3419
|
-
const messageTitle = this.extractTitleFromLines(titleLines);
|
|
3420
3581
|
const directory = firstPayload["cwd"] ? String(firstPayload["cwd"]) : "";
|
|
3421
3582
|
const title = resolveSessionTitle(indexTitle, messageTitle, basenameTitle(directory || null));
|
|
3422
3583
|
return parsedSession({
|
|
@@ -3451,7 +3612,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3451
3612
|
} catch {
|
|
3452
3613
|
return skippedSession("malformed first record");
|
|
3453
3614
|
}
|
|
3454
|
-
const payload = firstRecord
|
|
3615
|
+
const payload = extractPayload(firstRecord);
|
|
3455
3616
|
const stat = statSync4(filePath);
|
|
3456
3617
|
const createdAt = parseTimestampMs2(firstRecord) || parseTimestampMs2(payload) || stat.mtimeMs;
|
|
3457
3618
|
const indexTitle = this.getTitleForSession(sessionId);
|
|
@@ -3474,31 +3635,42 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3474
3635
|
}
|
|
3475
3636
|
});
|
|
3476
3637
|
}
|
|
3638
|
+
/** Fast path only: parses each of the first 20 lines to find a title (no full stats pass available). */
|
|
3477
3639
|
extractTitleFromLines(lines) {
|
|
3478
3640
|
for (const line of lines.slice(0, 20)) {
|
|
3479
3641
|
try {
|
|
3480
|
-
const
|
|
3481
|
-
const recordType = String(data["type"] ?? "");
|
|
3482
|
-
if (recordType !== "response_item" || isInternalEventType2(recordType)) continue;
|
|
3483
|
-
const payload = data["payload"] ?? {};
|
|
3484
|
-
const pType = String(payload["type"] ?? "");
|
|
3485
|
-
if (pType !== "message" || isInternalEventType2(pType)) continue;
|
|
3486
|
-
if (String(payload["role"] ?? "") !== "user") continue;
|
|
3487
|
-
const content = payload["content"];
|
|
3488
|
-
let text = null;
|
|
3489
|
-
if (Array.isArray(content)) {
|
|
3490
|
-
text = content.filter((item) => typeof item === "object" && item !== null && "text" in item).map((item) => String(item["text"] ?? "")).join(" ");
|
|
3491
|
-
} else if (typeof content === "string") {
|
|
3492
|
-
text = content;
|
|
3493
|
-
}
|
|
3494
|
-
if (!text || isDeveloperLikeUserMessage(text)) continue;
|
|
3495
|
-
const title = normalizeTitleText(text);
|
|
3642
|
+
const title = this.extractCodexRecordTitle(JSON.parse(line));
|
|
3496
3643
|
if (title) return title;
|
|
3497
3644
|
} catch {
|
|
3498
3645
|
}
|
|
3499
3646
|
}
|
|
3500
3647
|
return null;
|
|
3501
3648
|
}
|
|
3649
|
+
/**
|
|
3650
|
+
* Title candidate from a single already-parsed record, if it's a visible
|
|
3651
|
+
* user message. Shared by the main streaming pass (which parses every line
|
|
3652
|
+
* once) and the fast path's extractTitleFromLines().
|
|
3653
|
+
*/
|
|
3654
|
+
extractCodexRecordTitle(data) {
|
|
3655
|
+
const recordType = String(data["type"] ?? "");
|
|
3656
|
+
if (recordType !== "response_item" || isInternalEventType2(recordType)) return null;
|
|
3657
|
+
const payload = extractPayload(data);
|
|
3658
|
+
const pType = String(payload["type"] ?? "");
|
|
3659
|
+
if (pType !== "message" || isInternalEventType2(pType)) return null;
|
|
3660
|
+
if (String(payload["role"] ?? "") !== "user") return null;
|
|
3661
|
+
const content = payload["content"];
|
|
3662
|
+
let text = null;
|
|
3663
|
+
if (Array.isArray(content)) {
|
|
3664
|
+
text = content.map((item) => {
|
|
3665
|
+
const record = asRecord(item);
|
|
3666
|
+
return record ? String(record["text"] ?? "") : "";
|
|
3667
|
+
}).join(" ");
|
|
3668
|
+
} else if (typeof content === "string") {
|
|
3669
|
+
text = content;
|
|
3670
|
+
}
|
|
3671
|
+
if (!text || isDeveloperLikeUserMessage(text)) return null;
|
|
3672
|
+
return normalizeTitleText(text) || null;
|
|
3673
|
+
}
|
|
3502
3674
|
// ---- Record conversion ----
|
|
3503
3675
|
convertRecord(data, transcript, pendingPlan, activeModel) {
|
|
3504
3676
|
const recordType = String(data["type"] ?? "");
|
|
@@ -3507,7 +3679,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3507
3679
|
return pendingPlan;
|
|
3508
3680
|
}
|
|
3509
3681
|
if (recordType !== "response_item") return pendingPlan;
|
|
3510
|
-
const payload = data
|
|
3682
|
+
const payload = extractPayload(data);
|
|
3511
3683
|
const payloadType = String(payload["type"] ?? "");
|
|
3512
3684
|
if (isInternalEventType2(payloadType)) return pendingPlan;
|
|
3513
3685
|
const timestampMs = parseTimestampMs2(data) || parseTimestampMs2(payload);
|
|
@@ -3552,8 +3724,8 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3552
3724
|
if (!Array.isArray(content)) return pendingPlan;
|
|
3553
3725
|
const textParts = [];
|
|
3554
3726
|
for (const item of content) {
|
|
3555
|
-
|
|
3556
|
-
|
|
3727
|
+
const ci = asRecord(item);
|
|
3728
|
+
if (!ci) continue;
|
|
3557
3729
|
if (String(ci["type"] ?? "") === "output_text") {
|
|
3558
3730
|
const text = String(ci["text"] ?? "");
|
|
3559
3731
|
if (text.trim()) textParts.push(text);
|
|
@@ -3586,9 +3758,11 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3586
3758
|
// ---- User message ----
|
|
3587
3759
|
convertUserMessage(payload, transcript, timestampMs, pendingPlan) {
|
|
3588
3760
|
const content = payload["content"];
|
|
3589
|
-
const text = Array.isArray(content) ? content.map(
|
|
3590
|
-
|
|
3591
|
-
|
|
3761
|
+
const text = Array.isArray(content) ? content.map((c) => {
|
|
3762
|
+
if (Array.isArray(c)) return "";
|
|
3763
|
+
const record = asRecord(c);
|
|
3764
|
+
return record ? String(record["text"] ?? "") : String(c ?? "");
|
|
3765
|
+
}).join(" ") : String(content ?? "");
|
|
3592
3766
|
const visibleText = cleanInternalText(text);
|
|
3593
3767
|
if (!visibleText) return pendingPlan;
|
|
3594
3768
|
if (isDeveloperLikeUserMessage(visibleText)) return pendingPlan;
|
|
@@ -3604,8 +3778,13 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3604
3778
|
}
|
|
3605
3779
|
const subagentMatch = visibleText.match(SUBAGENT_NOTIFICATION_PATTERN);
|
|
3606
3780
|
if (subagentMatch) {
|
|
3781
|
+
let notifPayload;
|
|
3607
3782
|
try {
|
|
3608
|
-
|
|
3783
|
+
notifPayload = asRecord(JSON.parse(subagentMatch[1]));
|
|
3784
|
+
} catch {
|
|
3785
|
+
notifPayload = void 0;
|
|
3786
|
+
}
|
|
3787
|
+
if (notifPayload) {
|
|
3609
3788
|
const agentId = String(notifPayload["agent_id"] ?? "");
|
|
3610
3789
|
const nickname = String(notifPayload["nickname"] ?? "");
|
|
3611
3790
|
const completedText = String(notifPayload["completed"] ?? "");
|
|
@@ -3625,7 +3804,6 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3625
3804
|
});
|
|
3626
3805
|
transcript.beginTurn();
|
|
3627
3806
|
return pendingPlan;
|
|
3628
|
-
} catch {
|
|
3629
3807
|
}
|
|
3630
3808
|
}
|
|
3631
3809
|
transcript.appendMessage({
|
|
@@ -3642,12 +3820,11 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3642
3820
|
if (!Array.isArray(summary)) return;
|
|
3643
3821
|
const texts = [];
|
|
3644
3822
|
for (const item of summary) {
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
}
|
|
3823
|
+
const ci = asRecord(item);
|
|
3824
|
+
if (!ci) continue;
|
|
3825
|
+
if (String(ci["type"] ?? "") === "summary_text") {
|
|
3826
|
+
const text = String(ci["text"] ?? "");
|
|
3827
|
+
if (text.trim()) texts.push(text);
|
|
3651
3828
|
}
|
|
3652
3829
|
}
|
|
3653
3830
|
if (texts.length === 0) return;
|
|
@@ -3839,6 +4016,106 @@ var PerfTracer = class {
|
|
|
3839
4016
|
}
|
|
3840
4017
|
};
|
|
3841
4018
|
var perf = new PerfTracer();
|
|
4019
|
+
function narrowString(field, value) {
|
|
4020
|
+
return narrowField("cursor", field, value, asString);
|
|
4021
|
+
}
|
|
4022
|
+
function narrowNumber(field, value) {
|
|
4023
|
+
return narrowField("cursor", field, value, asNumber);
|
|
4024
|
+
}
|
|
4025
|
+
function parseSubagentInfos(value) {
|
|
4026
|
+
const arr = asArray(value);
|
|
4027
|
+
if (arr === void 0) return void 0;
|
|
4028
|
+
const infos = [];
|
|
4029
|
+
for (const item of arr) {
|
|
4030
|
+
const record = asRecord(item);
|
|
4031
|
+
if (!record) continue;
|
|
4032
|
+
infos.push({
|
|
4033
|
+
id: narrowString("subagentInfo.id", record.id),
|
|
4034
|
+
composerId: narrowString("subagentInfo.composerId", record.composerId),
|
|
4035
|
+
title: narrowString("subagentInfo.title", record.title),
|
|
4036
|
+
nickname: narrowString("subagentInfo.nickname", record.nickname)
|
|
4037
|
+
});
|
|
4038
|
+
}
|
|
4039
|
+
return infos;
|
|
4040
|
+
}
|
|
4041
|
+
function parseChatMessages(value) {
|
|
4042
|
+
const arr = asArray(value);
|
|
4043
|
+
if (arr === void 0) return void 0;
|
|
4044
|
+
const messages = [];
|
|
4045
|
+
for (const item of arr) {
|
|
4046
|
+
const record = asRecord(item);
|
|
4047
|
+
if (!record) continue;
|
|
4048
|
+
const role = narrowString("chatMessage.role", record.role);
|
|
4049
|
+
if (role === void 0) continue;
|
|
4050
|
+
messages.push({ ...record, role, text: narrowString("chatMessage.text", record.text) });
|
|
4051
|
+
}
|
|
4052
|
+
return messages;
|
|
4053
|
+
}
|
|
4054
|
+
function parseComposerRow(value) {
|
|
4055
|
+
const record = safeParseJsonRecord(value);
|
|
4056
|
+
if (!record) return null;
|
|
4057
|
+
const modelConfig = asRecord(record.modelConfig);
|
|
4058
|
+
return {
|
|
4059
|
+
id: narrowString("composer.id", record.id),
|
|
4060
|
+
composerId: narrowString("composer.composerId", record.composerId),
|
|
4061
|
+
text: narrowString("composer.text", record.text),
|
|
4062
|
+
name: narrowString("composer.name", record.name),
|
|
4063
|
+
title: narrowString("composer.title", record.title),
|
|
4064
|
+
createdAt: narrowNumber("composer.createdAt", record.createdAt),
|
|
4065
|
+
updatedAt: narrowNumber("composer.updatedAt", record.updatedAt),
|
|
4066
|
+
lastSendTime: narrowNumber("composer.lastSendTime", record.lastSendTime),
|
|
4067
|
+
lastUpdatedAt: narrowNumber("composer.lastUpdatedAt", record.lastUpdatedAt),
|
|
4068
|
+
model: narrowString("composer.model", record.model),
|
|
4069
|
+
modelConfig: modelConfig ? { modelName: narrowString("composer.modelConfig.modelName", modelConfig.modelName) } : void 0,
|
|
4070
|
+
inputTokenCount: narrowNumber("composer.inputTokenCount", record.inputTokenCount),
|
|
4071
|
+
outputTokenCount: narrowNumber("composer.outputTokenCount", record.outputTokenCount),
|
|
4072
|
+
subagentInfos: parseSubagentInfos(record.subagentInfos),
|
|
4073
|
+
chatMessages: parseChatMessages(record.chatMessages)
|
|
4074
|
+
};
|
|
4075
|
+
}
|
|
4076
|
+
function parseBubbleRow(value) {
|
|
4077
|
+
const record = safeParseJsonRecord(value);
|
|
4078
|
+
if (!record) return null;
|
|
4079
|
+
const timingInfo = asRecord(record.timingInfo);
|
|
4080
|
+
const tokenCount = asRecord(record.tokenCount);
|
|
4081
|
+
const modelInfo = asRecord(record.modelInfo);
|
|
4082
|
+
const toolFormerData = asRecord(record.toolFormerData);
|
|
4083
|
+
return {
|
|
4084
|
+
...record,
|
|
4085
|
+
id: narrowString("bubble.id", record.id),
|
|
4086
|
+
composerId: narrowString("bubble.composerId", record.composerId),
|
|
4087
|
+
chatMessages: parseChatMessages(record.chatMessages),
|
|
4088
|
+
type: narrowNumber("bubble.type", record.type),
|
|
4089
|
+
text: narrowString("bubble.text", record.text),
|
|
4090
|
+
requestId: narrowString("bubble.requestId", record.requestId),
|
|
4091
|
+
createdAt: narrowNumber("bubble.createdAt", record.createdAt),
|
|
4092
|
+
timestamp: narrowNumber("bubble.timestamp", record.timestamp),
|
|
4093
|
+
timingInfo: timingInfo ? {
|
|
4094
|
+
clientRpcSendTime: narrowNumber(
|
|
4095
|
+
"bubble.timingInfo.clientRpcSendTime",
|
|
4096
|
+
timingInfo.clientRpcSendTime
|
|
4097
|
+
),
|
|
4098
|
+
clientSettleTime: narrowNumber(
|
|
4099
|
+
"bubble.timingInfo.clientSettleTime",
|
|
4100
|
+
timingInfo.clientSettleTime
|
|
4101
|
+
),
|
|
4102
|
+
clientEndTime: narrowNumber("bubble.timingInfo.clientEndTime", timingInfo.clientEndTime)
|
|
4103
|
+
} : void 0,
|
|
4104
|
+
tokenCount: tokenCount ? {
|
|
4105
|
+
inputTokens: narrowNumber("bubble.tokenCount.inputTokens", tokenCount.inputTokens),
|
|
4106
|
+
outputTokens: narrowNumber("bubble.tokenCount.outputTokens", tokenCount.outputTokens)
|
|
4107
|
+
} : void 0,
|
|
4108
|
+
modelInfo: modelInfo ? { modelName: narrowString("bubble.modelInfo.modelName", modelInfo.modelName) } : void 0,
|
|
4109
|
+
toolFormerData: toolFormerData ? {
|
|
4110
|
+
name: narrowString("bubble.toolFormerData.name", toolFormerData.name),
|
|
4111
|
+
toolCallId: narrowString("bubble.toolFormerData.toolCallId", toolFormerData.toolCallId),
|
|
4112
|
+
status: narrowString("bubble.toolFormerData.status", toolFormerData.status),
|
|
4113
|
+
params: toolFormerData.params,
|
|
4114
|
+
result: toolFormerData.result,
|
|
4115
|
+
additionalData: asRecord(toolFormerData.additionalData)
|
|
4116
|
+
} : void 0
|
|
4117
|
+
};
|
|
4118
|
+
}
|
|
3842
4119
|
var CURSOR_TOOL_TITLE_MAP = {
|
|
3843
4120
|
read_file_v2: "read",
|
|
3844
4121
|
edit_file_v2: "edit",
|
|
@@ -3859,9 +4136,8 @@ function normalizeToolOutputParts2(output, timestampMs) {
|
|
|
3859
4136
|
const parts = [];
|
|
3860
4137
|
for (const item of output) {
|
|
3861
4138
|
if (typeof item === "object" && item !== null) {
|
|
3862
|
-
const
|
|
3863
|
-
|
|
3864
|
-
);
|
|
4139
|
+
const record = asRecord(item);
|
|
4140
|
+
const text2 = String(record?.text ?? record?.content ?? "");
|
|
3865
4141
|
const cleaned = cleanInternalText(text2);
|
|
3866
4142
|
if (cleaned) parts.push({ type: "text", text: cleaned, time_created: timestampMs });
|
|
3867
4143
|
} else if (typeof item === "string") {
|
|
@@ -3901,9 +4177,9 @@ function buildToolState(action) {
|
|
|
3901
4177
|
}
|
|
3902
4178
|
if (!state.status) {
|
|
3903
4179
|
if (typeof action.output === "object" && action.output !== null) {
|
|
3904
|
-
const out = action.output;
|
|
3905
|
-
if (out
|
|
3906
|
-
else if (out
|
|
4180
|
+
const out = asRecord(action.output);
|
|
4181
|
+
if (out?.success === true) state.status = "completed";
|
|
4182
|
+
else if (out?.success === false) state.status = "error";
|
|
3907
4183
|
else state.status = "completed";
|
|
3908
4184
|
} else if (action.output != null) {
|
|
3909
4185
|
state.status = "completed";
|
|
@@ -3992,8 +4268,8 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
3992
4268
|
if (!existsSync8(wsJsonPath)) continue;
|
|
3993
4269
|
let workspacePath;
|
|
3994
4270
|
try {
|
|
3995
|
-
const data = JSON.parse(readFileSync5(wsJsonPath, "utf-8"));
|
|
3996
|
-
const uri =
|
|
4271
|
+
const data = asRecord(JSON.parse(readFileSync5(wsJsonPath, "utf-8")));
|
|
4272
|
+
const uri = narrowString("workspaceJson.folder", data?.folder) ?? narrowString("workspaceJson.workspace", data?.workspace) ?? "";
|
|
3997
4273
|
if (!uri) continue;
|
|
3998
4274
|
workspacePath = normalize(decodeURIComponent(uri.replace(/^file:\/\//, "")));
|
|
3999
4275
|
} catch {
|
|
@@ -4007,16 +4283,11 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4007
4283
|
const row = wsDb.prepare("SELECT value FROM ItemTable WHERE key = 'composer.composerData'").get();
|
|
4008
4284
|
if (!row?.value) continue;
|
|
4009
4285
|
const parsed = JSON.parse(row.value);
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
} else {
|
|
4016
|
-
continue;
|
|
4017
|
-
}
|
|
4018
|
-
for (const c of composers) {
|
|
4019
|
-
const id = c.composerId ?? c.id;
|
|
4286
|
+
const composers = asArray(asRecord(parsed)?.allComposers) ?? asArray(parsed) ?? [];
|
|
4287
|
+
for (const item of composers) {
|
|
4288
|
+
const composer = asRecord(item);
|
|
4289
|
+
if (!composer) continue;
|
|
4290
|
+
const id = narrowString("workspaceComposer.composerId", composer.composerId) ?? narrowString("workspaceComposer.id", composer.id);
|
|
4020
4291
|
if (id) map.set(id, workspacePath);
|
|
4021
4292
|
}
|
|
4022
4293
|
} catch {
|
|
@@ -4047,8 +4318,8 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4047
4318
|
let processed = 0;
|
|
4048
4319
|
for (const row of rows) {
|
|
4049
4320
|
try {
|
|
4050
|
-
const composer =
|
|
4051
|
-
if (!composer.id && !composer.composerId) continue;
|
|
4321
|
+
const composer = parseComposerRow(row.value);
|
|
4322
|
+
if (!composer || !composer.id && !composer.composerId) continue;
|
|
4052
4323
|
const composerId = composer.id || composer.composerId || "";
|
|
4053
4324
|
const createdAt = composer.createdAt ?? 0;
|
|
4054
4325
|
const updatedAt = composer.updatedAt ?? composer.lastUpdatedAt ?? composer.lastSendTime ?? createdAt;
|
|
@@ -4249,8 +4520,8 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4249
4520
|
const rows = db.prepare("SELECT value FROM cursorDiskKV WHERE key LIKE ? ORDER BY key").all(`bubbleId:${composerId}:%`);
|
|
4250
4521
|
for (const row of rows) {
|
|
4251
4522
|
try {
|
|
4252
|
-
const bubble =
|
|
4253
|
-
if (bubble
|
|
4523
|
+
const bubble = parseBubbleRow(row.value);
|
|
4524
|
+
if (bubble?.requestId?.trim()) {
|
|
4254
4525
|
return bubble.requestId.trim();
|
|
4255
4526
|
}
|
|
4256
4527
|
} catch {
|
|
@@ -4266,8 +4537,8 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4266
4537
|
const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' AND value LIKE ?").all(`%"requestId":"${requestId}"%`);
|
|
4267
4538
|
for (const row of rows) {
|
|
4268
4539
|
try {
|
|
4269
|
-
const bubble =
|
|
4270
|
-
if (bubble
|
|
4540
|
+
const bubble = parseBubbleRow(row.value);
|
|
4541
|
+
if (bubble?.requestId === requestId) {
|
|
4271
4542
|
const keyParts = row.key.split(":");
|
|
4272
4543
|
if (keyParts.length >= 2 && keyParts[1]) {
|
|
4273
4544
|
return keyParts[1];
|
|
@@ -4293,8 +4564,8 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4293
4564
|
let count = 0;
|
|
4294
4565
|
for (const row of rows) {
|
|
4295
4566
|
try {
|
|
4296
|
-
const bubble =
|
|
4297
|
-
if (bubble
|
|
4567
|
+
const bubble = parseBubbleRow(row.value);
|
|
4568
|
+
if (bubble?.type === 1 || bubble?.type === 2) {
|
|
4298
4569
|
count++;
|
|
4299
4570
|
}
|
|
4300
4571
|
} catch {
|
|
@@ -4314,8 +4585,8 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4314
4585
|
let messageIndex = 0;
|
|
4315
4586
|
for (const row of rows) {
|
|
4316
4587
|
try {
|
|
4317
|
-
const bubble =
|
|
4318
|
-
if (isInternalBubble(bubble)) continue;
|
|
4588
|
+
const bubble = parseBubbleRow(row.value);
|
|
4589
|
+
if (!bubble || isInternalBubble(bubble)) continue;
|
|
4319
4590
|
const bubbleId = row.key.split(":").pop() || String(messageIndex);
|
|
4320
4591
|
const role = bubble.type === 2 ? "assistant" : "user";
|
|
4321
4592
|
let timestampMs = 0;
|
|
@@ -4404,7 +4675,7 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4404
4675
|
}
|
|
4405
4676
|
}
|
|
4406
4677
|
if (toolName === "create_plan") {
|
|
4407
|
-
const planText =
|
|
4678
|
+
const planText = asRecord(state.input)?.plan;
|
|
4408
4679
|
return {
|
|
4409
4680
|
type: "plan",
|
|
4410
4681
|
title: "Plan",
|
|
@@ -4426,20 +4697,12 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4426
4697
|
loadComposer(db, sessionId) {
|
|
4427
4698
|
const row = db.prepare("SELECT value FROM cursorDiskKV WHERE key = ?").get(`composerData:${sessionId}`);
|
|
4428
4699
|
if (!row) return null;
|
|
4429
|
-
|
|
4430
|
-
return JSON.parse(row.value);
|
|
4431
|
-
} catch {
|
|
4432
|
-
return null;
|
|
4433
|
-
}
|
|
4700
|
+
return parseComposerRow(row.value);
|
|
4434
4701
|
}
|
|
4435
4702
|
loadBubble(db, sessionId) {
|
|
4436
4703
|
const row = db.prepare("SELECT value FROM cursorDiskKV WHERE key = ?").get(`bubble:${sessionId}`);
|
|
4437
4704
|
if (!row) return null;
|
|
4438
|
-
|
|
4439
|
-
return JSON.parse(row.value);
|
|
4440
|
-
} catch {
|
|
4441
|
-
return null;
|
|
4442
|
-
}
|
|
4705
|
+
return parseBubbleRow(row.value);
|
|
4443
4706
|
}
|
|
4444
4707
|
appendSubagentMessages(db, composer, messages) {
|
|
4445
4708
|
const subagentInfos = composer.subagentInfos;
|
|
@@ -4493,6 +4756,17 @@ function parseTimestampMs3(value) {
|
|
|
4493
4756
|
const ts = Date.parse(text);
|
|
4494
4757
|
return Number.isNaN(ts) ? 0 : ts;
|
|
4495
4758
|
}
|
|
4759
|
+
function narrowPiField(field, value, narrow) {
|
|
4760
|
+
return narrowField("pi", field, value, narrow);
|
|
4761
|
+
}
|
|
4762
|
+
function narrowTimestampMs(field, value) {
|
|
4763
|
+
const shaped = narrowPiField(
|
|
4764
|
+
field,
|
|
4765
|
+
value,
|
|
4766
|
+
(v) => typeof v === "number" || typeof v === "string" ? v : void 0
|
|
4767
|
+
);
|
|
4768
|
+
return shaped === void 0 ? 0 : parseTimestampMs3(shaped);
|
|
4769
|
+
}
|
|
4496
4770
|
function extractSessionIdFromFilename(filePath) {
|
|
4497
4771
|
const stem = basename6(filePath, ".jsonl");
|
|
4498
4772
|
const underscore = stem.indexOf("_");
|
|
@@ -4516,7 +4790,7 @@ function normalizeTextParts(content, timestampMs) {
|
|
|
4516
4790
|
return text ? [{ type: "text", text, time_created: timestampMs }] : [];
|
|
4517
4791
|
}
|
|
4518
4792
|
function getEntryTimestamp(entry) {
|
|
4519
|
-
return
|
|
4793
|
+
return narrowTimestampMs("entry.timestamp", entry["timestamp"]);
|
|
4520
4794
|
}
|
|
4521
4795
|
function chooseLeafEntry(entries) {
|
|
4522
4796
|
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
@@ -4560,10 +4834,10 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4560
4834
|
}
|
|
4561
4835
|
listSessionSources(options) {
|
|
4562
4836
|
if (!this.basePath) return [];
|
|
4563
|
-
return this.
|
|
4837
|
+
return this.walkJsonlFiles(this.basePath, options).map(({ file, stat }) => ({
|
|
4564
4838
|
sessionId: extractSessionIdFromFilename(file),
|
|
4565
4839
|
sourcePath: file,
|
|
4566
|
-
fingerprint: this.sourceFingerprint(
|
|
4840
|
+
fingerprint: this.sourceFingerprint(stat)
|
|
4567
4841
|
}));
|
|
4568
4842
|
}
|
|
4569
4843
|
scanSessionSource(sourcePath) {
|
|
@@ -4600,8 +4874,9 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4600
4874
|
}
|
|
4601
4875
|
listSessionFiles(options) {
|
|
4602
4876
|
if (!this.basePath) return [];
|
|
4603
|
-
return this.walkJsonlFiles(this.basePath, options);
|
|
4877
|
+
return this.walkJsonlFiles(this.basePath, options).map(({ file }) => file);
|
|
4604
4878
|
}
|
|
4879
|
+
/** Stats each file once during the walk; caller reuses it for both the scan window check and the fingerprint. */
|
|
4605
4880
|
walkJsonlFiles(dir, options) {
|
|
4606
4881
|
const files = [];
|
|
4607
4882
|
try {
|
|
@@ -4612,20 +4887,27 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4612
4887
|
continue;
|
|
4613
4888
|
}
|
|
4614
4889
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
4615
|
-
|
|
4616
|
-
|
|
4890
|
+
let stat;
|
|
4891
|
+
try {
|
|
4892
|
+
stat = statSync6(fullPath);
|
|
4893
|
+
} catch {
|
|
4894
|
+
continue;
|
|
4895
|
+
}
|
|
4896
|
+
if (!matchesScanWindow(stat.mtimeMs, options)) continue;
|
|
4897
|
+
files.push({ file: fullPath, stat });
|
|
4617
4898
|
}
|
|
4618
4899
|
} catch {
|
|
4619
4900
|
}
|
|
4620
4901
|
return files;
|
|
4621
4902
|
}
|
|
4622
4903
|
buildSessionMeta(head, file) {
|
|
4904
|
+
const stat = statSync6(file);
|
|
4623
4905
|
return {
|
|
4624
4906
|
id: head.id,
|
|
4625
4907
|
title: head.title,
|
|
4626
4908
|
sourcePath: file,
|
|
4627
|
-
sourceFingerprint: this.sourceFingerprint(
|
|
4628
|
-
sourceMtimeMs:
|
|
4909
|
+
sourceFingerprint: this.sourceFingerprint(stat),
|
|
4910
|
+
sourceMtimeMs: stat.mtimeMs,
|
|
4629
4911
|
headIndexVersion: HEAD_INDEX_VERSION3,
|
|
4630
4912
|
parserVersion: PARSER_VERSION2,
|
|
4631
4913
|
directory: head.directory,
|
|
@@ -4634,8 +4916,8 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4634
4916
|
updatedAt: head.time_updated ?? head.time_created
|
|
4635
4917
|
};
|
|
4636
4918
|
}
|
|
4637
|
-
|
|
4638
|
-
|
|
4919
|
+
/** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */
|
|
4920
|
+
sourceFingerprint(stat) {
|
|
4639
4921
|
return JSON.stringify([HEAD_INDEX_VERSION3, PARSER_VERSION2, stat.mtimeMs, stat.size]);
|
|
4640
4922
|
}
|
|
4641
4923
|
parseSessionHeadResult(filePath) {
|
|
@@ -4675,7 +4957,7 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4675
4957
|
if (!sessionId) throw new Error("missing session id");
|
|
4676
4958
|
const stat = statSync6(filePath);
|
|
4677
4959
|
const directory = String(header["cwd"] ?? "").trim() || basename6(filePath, ".jsonl");
|
|
4678
|
-
const createdAt =
|
|
4960
|
+
const createdAt = narrowTimestampMs("session.timestamp", header["timestamp"]) || stat.mtimeMs;
|
|
4679
4961
|
const updatedAt = pathEntries.reduce(
|
|
4680
4962
|
(max, entry) => Math.max(max, getEntryTimestamp(entry)),
|
|
4681
4963
|
createdAt
|
|
@@ -4718,8 +5000,8 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4718
5000
|
const timestampMs = getEntryTimestamp(entry);
|
|
4719
5001
|
const type = String(entry["type"] ?? "");
|
|
4720
5002
|
if (type === "message") {
|
|
4721
|
-
const message = entry["message"];
|
|
4722
|
-
if (!
|
|
5003
|
+
const message = narrowPiField("entry.message", entry["message"], asRecord);
|
|
5004
|
+
if (!message) continue;
|
|
4723
5005
|
const result2 = this.convertAgentMessage(entry, message, timestampMs, builder);
|
|
4724
5006
|
if (!result2) continue;
|
|
4725
5007
|
if (result2.message) builder.appendMessage(result2.message);
|
|
@@ -4743,8 +5025,8 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4743
5025
|
};
|
|
4744
5026
|
}
|
|
4745
5027
|
convertAgentMessage(entry, message, timestampMs, builder) {
|
|
4746
|
-
const id =
|
|
4747
|
-
const role =
|
|
5028
|
+
const id = narrowPiField("message.id", entry["id"], asString) ?? "";
|
|
5029
|
+
const role = narrowPiField("message.role", message["role"], asString) ?? "";
|
|
4748
5030
|
if (role === "user") {
|
|
4749
5031
|
const parts = normalizeTextParts(message["content"], timestampMs);
|
|
4750
5032
|
if (parts.length === 0) return null;
|
|
@@ -4883,7 +5165,7 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4883
5165
|
const text = cleanInternalText(rawText);
|
|
4884
5166
|
if (!text) return null;
|
|
4885
5167
|
return {
|
|
4886
|
-
id:
|
|
5168
|
+
id: narrowPiField("summary.id", entry["id"], asString) ?? "",
|
|
4887
5169
|
role: type === "custom_message" ? "user" : "assistant",
|
|
4888
5170
|
agent: type === "custom_message" ? void 0 : "pi",
|
|
4889
5171
|
timestampMs,
|
|
@@ -4891,14 +5173,12 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4891
5173
|
};
|
|
4892
5174
|
}
|
|
4893
5175
|
normalizeUsage(raw) {
|
|
4894
|
-
const usage =
|
|
4895
|
-
const inputTokens =
|
|
4896
|
-
const outputTokens =
|
|
4897
|
-
const cacheReadTokens =
|
|
4898
|
-
const cacheCreateTokens =
|
|
4899
|
-
const totalTokens =
|
|
4900
|
-
usage["totalTokens"] ?? inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens
|
|
4901
|
-
);
|
|
5176
|
+
const usage = narrowPiField("message.usage", raw, asRecord) ?? {};
|
|
5177
|
+
const inputTokens = narrowPiField("message.usage.input", usage["input"], asNumber) ?? 0;
|
|
5178
|
+
const outputTokens = narrowPiField("message.usage.output", usage["output"], asNumber) ?? 0;
|
|
5179
|
+
const cacheReadTokens = narrowPiField("message.usage.cacheRead", usage["cacheRead"], asNumber) ?? 0;
|
|
5180
|
+
const cacheCreateTokens = narrowPiField("message.usage.cacheWrite", usage["cacheWrite"], asNumber) ?? 0;
|
|
5181
|
+
const totalTokens = narrowPiField("message.usage.totalTokens", usage["totalTokens"], asNumber) ?? inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens;
|
|
4902
5182
|
const cost = isObject(usage["cost"]) ? Number(usage["cost"]["total"] ?? 0) : null;
|
|
4903
5183
|
return {
|
|
4904
5184
|
inputTokens: inputTokens + cacheReadTokens + cacheCreateTokens,
|
|
@@ -4940,6 +5220,7 @@ var ZCodeAgent = class extends OpenCodeSqliteAgent {
|
|
|
4940
5220
|
};
|
|
4941
5221
|
registerAgent({
|
|
4942
5222
|
icon: "/icon/agent/claudecode.svg",
|
|
5223
|
+
iconColored: true,
|
|
4943
5224
|
create: () => new ClaudeCodeAgent()
|
|
4944
5225
|
});
|
|
4945
5226
|
registerAgent({
|
|
@@ -5029,7 +5310,23 @@ function normalizeGitRemote(url) {
|
|
|
5029
5310
|
if (!value.includes("/")) return null;
|
|
5030
5311
|
return value.toLowerCase();
|
|
5031
5312
|
}
|
|
5313
|
+
var IDENTITY_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
5314
|
+
var identityCache = /* @__PURE__ */ new Map();
|
|
5315
|
+
function clearIdentityCache() {
|
|
5316
|
+
identityCache.clear();
|
|
5317
|
+
}
|
|
5032
5318
|
function computeIdentity(cwd, fs) {
|
|
5319
|
+
if (fs !== realFs) return resolveIdentity(cwd, fs);
|
|
5320
|
+
const key = cwd ?? "";
|
|
5321
|
+
const cached = identityCache.get(key);
|
|
5322
|
+
if (cached && Date.now() - cached.resolvedAt < IDENTITY_CACHE_TTL_MS) {
|
|
5323
|
+
return cached.identity;
|
|
5324
|
+
}
|
|
5325
|
+
const identity = resolveIdentity(cwd, fs);
|
|
5326
|
+
identityCache.set(key, { identity, resolvedAt: Date.now() });
|
|
5327
|
+
return identity;
|
|
5328
|
+
}
|
|
5329
|
+
function resolveIdentity(cwd, fs) {
|
|
5033
5330
|
if (!cwd) return loose();
|
|
5034
5331
|
const pathOps = getPathOps(cwd);
|
|
5035
5332
|
const absoluteCwd = pathOps.resolve(cwd);
|
|
@@ -5963,7 +6260,10 @@ function withCacheDb(fn) {
|
|
|
5963
6260
|
setSchemaEnsuredPath(cachePath);
|
|
5964
6261
|
}
|
|
5965
6262
|
return fn(db);
|
|
5966
|
-
} catch {
|
|
6263
|
+
} catch (error) {
|
|
6264
|
+
getCoreDiagnostics()?.warn("cache.write_failed", {
|
|
6265
|
+
message: error instanceof Error ? error.message : String(error)
|
|
6266
|
+
});
|
|
5967
6267
|
return null;
|
|
5968
6268
|
} finally {
|
|
5969
6269
|
db.close();
|
|
@@ -7854,6 +8154,14 @@ function searchFileActivitySessions(query, options = {}) {
|
|
|
7854
8154
|
return results;
|
|
7855
8155
|
}
|
|
7856
8156
|
var CACHE_INITIALIZATION_VERSION = "session-cache-v2";
|
|
8157
|
+
function parseCachedSessionMeta(value) {
|
|
8158
|
+
if (!value) return null;
|
|
8159
|
+
try {
|
|
8160
|
+
return JSON.parse(value);
|
|
8161
|
+
} catch {
|
|
8162
|
+
return null;
|
|
8163
|
+
}
|
|
8164
|
+
}
|
|
7857
8165
|
function deleteLegacyCacheFile() {
|
|
7858
8166
|
const legacyPath = getLegacyCachePath();
|
|
7859
8167
|
if (!existsSync12(legacyPath)) {
|
|
@@ -7972,7 +8280,7 @@ function markAgentFullSyncCompleted(agentName) {
|
|
|
7972
8280
|
).run(Date.now(), agentName);
|
|
7973
8281
|
});
|
|
7974
8282
|
}
|
|
7975
|
-
function
|
|
8283
|
+
function loadCachedSessionDataEntry(agentName, sessionId) {
|
|
7976
8284
|
if (!hasCacheStorage()) {
|
|
7977
8285
|
return null;
|
|
7978
8286
|
}
|
|
@@ -8044,12 +8352,18 @@ function loadCachedSessionData(agentName, sessionId) {
|
|
|
8044
8352
|
`
|
|
8045
8353
|
).all(agentName, sessionId);
|
|
8046
8354
|
return {
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8355
|
+
data: {
|
|
8356
|
+
...head,
|
|
8357
|
+
messages: messageRows.map((messageRow) => messageFromCachedRow(messageRow)),
|
|
8358
|
+
file_activity: fileActivityRows.map((activityRow) => fileActivityFromRow(activityRow))
|
|
8359
|
+
},
|
|
8360
|
+
meta: parseCachedSessionMeta(row.meta_json)
|
|
8050
8361
|
};
|
|
8051
8362
|
});
|
|
8052
8363
|
}
|
|
8364
|
+
function loadCachedSessionData(agentName, sessionId) {
|
|
8365
|
+
return loadCachedSessionDataEntry(agentName, sessionId)?.data ?? null;
|
|
8366
|
+
}
|
|
8053
8367
|
function saveCachedSessions(agentName, sessions, meta = {}) {
|
|
8054
8368
|
withCacheDb((db) => {
|
|
8055
8369
|
const deleteAgent = db.prepare("DELETE FROM agent_cache WHERE agent_name = ?");
|
|
@@ -8239,9 +8553,8 @@ function listCachedProjectGroups(sessions) {
|
|
|
8239
8553
|
if (!hasCacheStorage()) {
|
|
8240
8554
|
return [];
|
|
8241
8555
|
}
|
|
8242
|
-
const
|
|
8243
|
-
|
|
8244
|
-
`
|
|
8556
|
+
const queryRows = (db) => db.prepare(
|
|
8557
|
+
`
|
|
8245
8558
|
SELECT identity_kind, identity_key, display_name, sources_csv, session_count, last_activity
|
|
8246
8559
|
FROM project_groups_v
|
|
8247
8560
|
ORDER BY
|
|
@@ -8249,34 +8562,24 @@ function listCachedProjectGroups(sessions) {
|
|
|
8249
8562
|
last_activity IS NULL,
|
|
8250
8563
|
last_activity DESC
|
|
8251
8564
|
`
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
const cache = /* @__PURE__ */ new Map();
|
|
8266
|
-
return (directory) => {
|
|
8267
|
-
const key = directory || "";
|
|
8268
|
-
const cached = cache.get(key);
|
|
8269
|
-
if (cached) return cached;
|
|
8270
|
-
const identity = computeIdentity(directory, realFs);
|
|
8271
|
-
cache.set(key, identity);
|
|
8272
|
-
return identity;
|
|
8273
|
-
};
|
|
8565
|
+
).all();
|
|
8566
|
+
let rows = withCacheDbReadOnly(queryRows);
|
|
8567
|
+
if (rows == null) {
|
|
8568
|
+
rows = withCacheDb(queryRows);
|
|
8569
|
+
}
|
|
8570
|
+
return (rows ?? []).map((row) => ({
|
|
8571
|
+
identityKind: row.identity_kind ?? "path",
|
|
8572
|
+
identityKey: String(row.identity_key ?? ""),
|
|
8573
|
+
displayName: String(row.display_name ?? ""),
|
|
8574
|
+
sources: String(row.sources_csv ?? "").split(",").filter(Boolean).sort(),
|
|
8575
|
+
sessionCount: Number(row.session_count ?? 0),
|
|
8576
|
+
lastActivity: row.last_activity == null ? null : Number(row.last_activity)
|
|
8577
|
+
}));
|
|
8274
8578
|
}
|
|
8275
8579
|
function attachMissingProjectIdentities(sessions) {
|
|
8276
|
-
const resolveIdentity = createIdentityResolver();
|
|
8277
8580
|
return sessions.map((session) => {
|
|
8278
8581
|
if (session.project_identity) return session;
|
|
8279
|
-
return { ...session, project_identity:
|
|
8582
|
+
return { ...session, project_identity: computeIdentity(session.directory, realFs) };
|
|
8280
8583
|
});
|
|
8281
8584
|
}
|
|
8282
8585
|
function buildAgentCacheMeta(agent, sessionIds) {
|
|
@@ -8306,7 +8609,7 @@ function sessionSignature(session) {
|
|
|
8306
8609
|
function sortSessions(sessions) {
|
|
8307
8610
|
return sortSessionsByActivity(sessions);
|
|
8308
8611
|
}
|
|
8309
|
-
function computeSessionDiff(cachedSessions, updatedSessions, changedIds = [], signature = sessionSignature) {
|
|
8612
|
+
function computeSessionDiff(cachedSessions, updatedSessions, changedIds = [], signature = sessionSignature, signatureCache) {
|
|
8310
8613
|
const cachedMap = new Map(cachedSessions.map((session) => [session.id, session]));
|
|
8311
8614
|
const updatedIds = new Set(updatedSessions.map((session) => session.id));
|
|
8312
8615
|
const changedIdSet = new Set(changedIds);
|
|
@@ -8319,10 +8622,13 @@ function computeSessionDiff(cachedSessions, updatedSessions, changedIds = [], si
|
|
|
8319
8622
|
if (!cached) {
|
|
8320
8623
|
newCount += 1;
|
|
8321
8624
|
changes.push({ session, sortIndex });
|
|
8625
|
+
signatureCache?.set(session.id, signature(session));
|
|
8322
8626
|
return;
|
|
8323
8627
|
}
|
|
8324
|
-
const
|
|
8325
|
-
|
|
8628
|
+
const cachedSignature = signatureCache?.get(cached.id) ?? signature(cached);
|
|
8629
|
+
const updatedSignature = signature(session);
|
|
8630
|
+
signatureCache?.set(session.id, updatedSignature);
|
|
8631
|
+
if (changedIdSet.has(session.id) || cachedSignature !== updatedSignature) {
|
|
8326
8632
|
updatedCount += 1;
|
|
8327
8633
|
changes.push({ session, sortIndex });
|
|
8328
8634
|
}
|
|
@@ -8540,7 +8846,7 @@ async function scanAgentSmart(agent, options, onProgress) {
|
|
|
8540
8846
|
});
|
|
8541
8847
|
const t2 = performance.now();
|
|
8542
8848
|
const updatedSessions = await Promise.resolve(
|
|
8543
|
-
agent.incrementalScan(cached.sessions, checkResult.changedIds || [])
|
|
8849
|
+
agent.incrementalScan(cached.sessions, checkResult.changedIds || [], checkResult.refs)
|
|
8544
8850
|
);
|
|
8545
8851
|
timing.scan = performance.now() - t2;
|
|
8546
8852
|
return finalizeAgentScan(agent, updatedSessions, {
|
|
@@ -8604,10 +8910,12 @@ async function scanAgentFull(agent, options, onProgress, timing = { total: 0 },
|
|
|
8604
8910
|
const tagged = options.includeSmartTags === false ? { sessions: headsWithIdentity, changed: false } : await ensureSessionTags(agent, headsWithIdentity, options.smartTagWorkerUrl);
|
|
8605
8911
|
timing.tags = performance.now() - t2;
|
|
8606
8912
|
const meta = buildAgentCacheMeta(agent);
|
|
8607
|
-
if (options.writeCache !== false
|
|
8608
|
-
|
|
8913
|
+
if (options.writeCache !== false) {
|
|
8914
|
+
if (options.from == null && options.to == null) {
|
|
8915
|
+
saveCachedSessions(agent.name, tagged.sessions, meta);
|
|
8916
|
+
markAgentFullSyncCompleted(agent.name);
|
|
8917
|
+
}
|
|
8609
8918
|
markAgentCacheInitialized(agent.name);
|
|
8610
|
-
markAgentFullSyncCompleted(agent.name);
|
|
8611
8919
|
}
|
|
8612
8920
|
onProgress?.({ agent: agent.name, phase: "complete", newCount: tagged.sessions.length });
|
|
8613
8921
|
const filtered = filterSessions(tagged.sessions, options);
|
|
@@ -8663,6 +8971,13 @@ async function scanSessionsAsync(options = {}, onProgress) {
|
|
|
8663
8971
|
var STATE_DB_FILENAME = "state.db";
|
|
8664
8972
|
var STATE_SCHEMA_VERSION = 2;
|
|
8665
8973
|
var MEMORY_STATE_STORE = "memory";
|
|
8974
|
+
var stateSchemaEnsuredPath = null;
|
|
8975
|
+
function getStateSchemaEnsuredPath() {
|
|
8976
|
+
return stateSchemaEnsuredPath;
|
|
8977
|
+
}
|
|
8978
|
+
function setStateSchemaEnsuredPath(path2) {
|
|
8979
|
+
stateSchemaEnsuredPath = path2;
|
|
8980
|
+
}
|
|
8666
8981
|
var StateStorageUnavailableError = class extends Error {
|
|
8667
8982
|
constructor() {
|
|
8668
8983
|
super("SQLite state database is unavailable");
|
|
@@ -8769,7 +9084,7 @@ function ensureSchema2(db, dbPath) {
|
|
|
8769
9084
|
{ version: 2, migrate: createSessionAliasesTable }
|
|
8770
9085
|
]
|
|
8771
9086
|
});
|
|
8772
|
-
if (currentVersion
|
|
9087
|
+
if (currentVersion < STATE_SCHEMA_VERSION) {
|
|
8773
9088
|
setStateSchemaVersion(db);
|
|
8774
9089
|
}
|
|
8775
9090
|
}
|
|
@@ -8778,7 +9093,10 @@ function withStateDb(fn) {
|
|
|
8778
9093
|
const db = openDb(statePath);
|
|
8779
9094
|
if (!db) throw new StateStorageUnavailableError();
|
|
8780
9095
|
try {
|
|
8781
|
-
|
|
9096
|
+
if (getStateSchemaEnsuredPath() !== statePath) {
|
|
9097
|
+
ensureSchema2(db, statePath);
|
|
9098
|
+
setStateSchemaEnsuredPath(statePath);
|
|
9099
|
+
}
|
|
8782
9100
|
return fn(db);
|
|
8783
9101
|
} finally {
|
|
8784
9102
|
db.close();
|
|
@@ -9179,6 +9497,7 @@ function buildDashboard(sessions, options) {
|
|
|
9179
9497
|
name,
|
|
9180
9498
|
displayName: info?.displayName ?? name,
|
|
9181
9499
|
icon: info?.icon ?? "",
|
|
9500
|
+
iconColored: info?.iconColored,
|
|
9182
9501
|
sessions: metrics.sessions,
|
|
9183
9502
|
messages: metrics.messages,
|
|
9184
9503
|
tokens: metrics.tokens
|
|
@@ -9219,15 +9538,6 @@ function executeSessionSearch(query, options, snapshot) {
|
|
|
9219
9538
|
function needsIndexedSearch(textQuery, options) {
|
|
9220
9539
|
return Boolean(textQuery || options.file || options.fileKind || options.tools?.length);
|
|
9221
9540
|
}
|
|
9222
|
-
function filterSessionsByActivityWindow(sessions, from, to) {
|
|
9223
|
-
if (from == null && to == null) return sessions;
|
|
9224
|
-
return sessions.filter((session) => {
|
|
9225
|
-
const activity = getSessionActivityTime(session);
|
|
9226
|
-
if (from != null && activity < from) return false;
|
|
9227
|
-
if (to != null && activity > to) return false;
|
|
9228
|
-
return true;
|
|
9229
|
-
});
|
|
9230
|
-
}
|
|
9231
9541
|
function matchesRecentSearchFilters(session, options, projectScope) {
|
|
9232
9542
|
if (options.projectKind || options.projectKey) {
|
|
9233
9543
|
if (!options.projectKind || !options.projectKey || !matchesProjectIdentity(session.project_identity, {
|
|
@@ -9253,11 +9563,18 @@ function matchesRecentSearchFilters(session, options, projectScope) {
|
|
|
9253
9563
|
if (!sessionMatchesSearchCost(session, options)) return false;
|
|
9254
9564
|
return true;
|
|
9255
9565
|
}
|
|
9566
|
+
function matchesSessionSearchFilters(agentName, session, options, projectScope = null) {
|
|
9567
|
+
if (options.agent && agentName !== options.agent) return false;
|
|
9568
|
+
const activity = getSessionActivityTime(session);
|
|
9569
|
+
if (options.from != null && activity < options.from) return false;
|
|
9570
|
+
if (options.to != null && activity > options.to) return false;
|
|
9571
|
+
return matchesRecentSearchFilters(session, options, projectScope);
|
|
9572
|
+
}
|
|
9256
9573
|
function searchRecentSessions(snapshot, options) {
|
|
9257
9574
|
const projectScope = options.cwd ? createProjectScopeMatcher(options.cwd) : null;
|
|
9258
9575
|
const entries = options.agent ? [[options.agent, snapshot.byAgent[options.agent] ?? []]] : Object.entries(snapshot.byAgent);
|
|
9259
9576
|
return entries.flatMap(
|
|
9260
|
-
([agentName, sessions]) =>
|
|
9577
|
+
([agentName, sessions]) => sessions.filter((session) => matchesSessionSearchFilters(agentName, session, options, projectScope)).map((session) => ({ agentName, session }))
|
|
9261
9578
|
).sort(
|
|
9262
9579
|
(a, b) => (b.session.time_updated ?? b.session.time_created) - (a.session.time_updated ?? a.session.time_created)
|
|
9263
9580
|
).slice(0, options.limit ?? 50).map(({ agentName, session }) => ({
|
|
@@ -9300,6 +9617,7 @@ export {
|
|
|
9300
9617
|
getRegisteredAgents,
|
|
9301
9618
|
getAgentInfoMap,
|
|
9302
9619
|
getAgentByName,
|
|
9620
|
+
setCoreDiagnostics,
|
|
9303
9621
|
parsedSession,
|
|
9304
9622
|
skippedSession,
|
|
9305
9623
|
filteredSession,
|
|
@@ -9333,6 +9651,11 @@ export {
|
|
|
9333
9651
|
applyMessageCosts,
|
|
9334
9652
|
withEstimatedSessionCost,
|
|
9335
9653
|
estimateTokenCost,
|
|
9654
|
+
asRecord,
|
|
9655
|
+
asString,
|
|
9656
|
+
asNumber,
|
|
9657
|
+
asArray,
|
|
9658
|
+
reportFieldMismatch,
|
|
9336
9659
|
openDbReadOnly,
|
|
9337
9660
|
openDb,
|
|
9338
9661
|
isSqliteAvailable,
|
|
@@ -9343,6 +9666,7 @@ export {
|
|
|
9343
9666
|
getProjectIdentityKey,
|
|
9344
9667
|
matchesProjectIdentity,
|
|
9345
9668
|
normalizeGitRemote,
|
|
9669
|
+
clearIdentityCache,
|
|
9346
9670
|
computeIdentity,
|
|
9347
9671
|
buildProjectGroups,
|
|
9348
9672
|
createProjectScopeMatcher,
|
|
@@ -9368,6 +9692,7 @@ export {
|
|
|
9368
9692
|
markAgentCacheInitialized,
|
|
9369
9693
|
getAgentLastFullSyncAt,
|
|
9370
9694
|
markAgentFullSyncCompleted,
|
|
9695
|
+
loadCachedSessionDataEntry,
|
|
9371
9696
|
loadCachedSessionData,
|
|
9372
9697
|
saveCachedSessions,
|
|
9373
9698
|
saveCachedSessionChanges,
|
|
@@ -9400,6 +9725,7 @@ export {
|
|
|
9400
9725
|
toLocalDateKey,
|
|
9401
9726
|
startOfLocalDay,
|
|
9402
9727
|
buildDashboard,
|
|
9403
|
-
executeSessionSearch
|
|
9728
|
+
executeSessionSearch,
|
|
9729
|
+
matchesSessionSearchFilters
|
|
9404
9730
|
};
|
|
9405
|
-
//# sourceMappingURL=chunk-
|
|
9731
|
+
//# sourceMappingURL=chunk-MWSJTNOW.js.map
|