codesesh 0.1.5 → 0.3.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 +18 -4
- package/dist/{chunk-FG2FZIU5.js → chunk-UQI7CTEK.js} +617 -190
- package/dist/chunk-UQI7CTEK.js.map +1 -0
- package/dist/{dist-ZF35YB7B.js → dist-ONDV5GVR.js} +12 -4
- package/dist/index.js +630 -45
- package/dist/index.js.map +1 -1
- package/dist/web/assets/index-jHkWNiQR.css +2 -0
- package/dist/web/assets/index-qhuN0bxX.js +67 -0
- package/dist/web/index.html +2 -2
- package/package.json +9 -2
- package/dist/chunk-FG2FZIU5.js.map +0 -1
- package/dist/web/assets/index-Bz2gXVMS.js +0 -67
- package/dist/web/assets/index-vSqmWltx.css +0 -2
- /package/dist/{dist-ZF35YB7B.js.map → dist-ONDV5GVR.js.map} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// ../core/dist/index.mjs
|
|
4
4
|
import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
|
|
5
|
-
import { join as join2, basename as basename2 } from "path";
|
|
5
|
+
import { join as join2, basename as basename2, dirname } from "path";
|
|
6
6
|
import { existsSync } from "fs";
|
|
7
7
|
import { homedir, platform } from "os";
|
|
8
8
|
import { join } from "path";
|
|
@@ -10,16 +10,18 @@ import { readFileSync } from "fs";
|
|
|
10
10
|
import { basename } from "path";
|
|
11
11
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
12
12
|
import { join as join3 } from "path";
|
|
13
|
+
import { mkdirSync } from "fs";
|
|
14
|
+
import { dirname as dirname2 } from "path";
|
|
13
15
|
import { createRequire } from "module";
|
|
14
16
|
import { createHash } from "crypto";
|
|
15
17
|
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
16
|
-
import { join as join4, basename as basename3, dirname } from "path";
|
|
18
|
+
import { join as join4, basename as basename3, dirname as dirname3 } from "path";
|
|
17
19
|
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
18
20
|
import { join as join5, basename as basename4 } from "path";
|
|
19
21
|
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync5 } from "fs";
|
|
20
22
|
import { join as join6, normalize } from "path";
|
|
21
23
|
import { resolve, sep } from "path";
|
|
22
|
-
import { existsSync as existsSync7,
|
|
24
|
+
import { existsSync as existsSync7, rmSync, unlinkSync } from "fs";
|
|
23
25
|
import { join as join7 } from "path";
|
|
24
26
|
import { homedir as homedir2 } from "os";
|
|
25
27
|
var registrations = [];
|
|
@@ -205,6 +207,7 @@ var PerfTracer = class {
|
|
|
205
207
|
}
|
|
206
208
|
};
|
|
207
209
|
var perf = new PerfTracer();
|
|
210
|
+
var RECENT_SESSION_REVALIDATION_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
208
211
|
function parseTimestampMs(data) {
|
|
209
212
|
const raw = String(data["timestamp"] ?? "").trim();
|
|
210
213
|
if (!raw) return 0;
|
|
@@ -348,17 +351,30 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
348
351
|
if (!this.basePath) {
|
|
349
352
|
return { hasChanges: false, timestamp: Date.now() };
|
|
350
353
|
}
|
|
351
|
-
const
|
|
352
|
-
|
|
354
|
+
const now = Date.now();
|
|
355
|
+
const changedIds = /* @__PURE__ */ new Set();
|
|
356
|
+
const recentSessions = cachedSessions.filter(
|
|
357
|
+
(session) => now - session.time_created <= RECENT_SESSION_REVALIDATION_WINDOW_MS
|
|
358
|
+
);
|
|
359
|
+
for (const session of recentSessions) {
|
|
360
|
+
changedIds.add(session.id);
|
|
353
361
|
const meta = this.sessionMetaMap.get(session.id);
|
|
354
362
|
if (!meta) continue;
|
|
363
|
+
delete this.sessionsIndexCache[basename2(dirname(meta.sourcePath))];
|
|
364
|
+
}
|
|
365
|
+
for (const session of cachedSessions) {
|
|
366
|
+
const meta = this.sessionMetaMap.get(session.id);
|
|
367
|
+
if (!meta) {
|
|
368
|
+
changedIds.add(session.id);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
355
371
|
try {
|
|
356
372
|
const stat = statSync(meta.sourcePath);
|
|
357
373
|
if (stat.mtimeMs > sinceTimestamp) {
|
|
358
|
-
changedIds.
|
|
374
|
+
changedIds.add(session.id);
|
|
359
375
|
}
|
|
360
376
|
} catch {
|
|
361
|
-
changedIds.
|
|
377
|
+
changedIds.add(session.id);
|
|
362
378
|
}
|
|
363
379
|
}
|
|
364
380
|
try {
|
|
@@ -368,14 +384,14 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
368
384
|
}
|
|
369
385
|
const hasNewFiles = totalFiles > cachedSessions.length;
|
|
370
386
|
return {
|
|
371
|
-
hasChanges: changedIds.
|
|
372
|
-
changedIds,
|
|
387
|
+
hasChanges: changedIds.size > 0 || hasNewFiles,
|
|
388
|
+
changedIds: Array.from(changedIds),
|
|
373
389
|
timestamp: Date.now()
|
|
374
390
|
};
|
|
375
391
|
} catch {
|
|
376
392
|
return {
|
|
377
|
-
hasChanges: changedIds.
|
|
378
|
-
changedIds,
|
|
393
|
+
hasChanges: changedIds.size > 0,
|
|
394
|
+
changedIds: Array.from(changedIds),
|
|
379
395
|
timestamp: Date.now()
|
|
380
396
|
};
|
|
381
397
|
}
|
|
@@ -968,6 +984,19 @@ function openDbReadOnly(dbPath) {
|
|
|
968
984
|
return null;
|
|
969
985
|
}
|
|
970
986
|
}
|
|
987
|
+
function openDb(dbPath) {
|
|
988
|
+
if (!DatabaseConstructor) return null;
|
|
989
|
+
try {
|
|
990
|
+
mkdirSync(dirname2(dbPath), { recursive: true });
|
|
991
|
+
const db = DatabaseConstructor(dbPath);
|
|
992
|
+
db.pragma("journal_mode = WAL");
|
|
993
|
+
db.pragma("synchronous = NORMAL");
|
|
994
|
+
db.pragma("foreign_keys = ON");
|
|
995
|
+
return db;
|
|
996
|
+
} catch {
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
971
1000
|
function isSqliteAvailable() {
|
|
972
1001
|
return DatabaseConstructor !== null;
|
|
973
1002
|
}
|
|
@@ -1024,6 +1053,7 @@ var OpenCodeAgent = class extends BaseAgent {
|
|
|
1024
1053
|
const timeUpdated = Number(row.time_updated ?? timeCreated);
|
|
1025
1054
|
const slug = `opencode/${id}`;
|
|
1026
1055
|
const directory = String(row.directory ?? "");
|
|
1056
|
+
const stats = hasMessageTable ? this.readSessionStats(db, id) : null;
|
|
1027
1057
|
heads.push({
|
|
1028
1058
|
id,
|
|
1029
1059
|
slug,
|
|
@@ -1032,10 +1062,10 @@ var OpenCodeAgent = class extends BaseAgent {
|
|
|
1032
1062
|
time_created: timeCreated,
|
|
1033
1063
|
time_updated: timeUpdated,
|
|
1034
1064
|
stats: {
|
|
1035
|
-
message_count: Number(row.message_count ?? 0),
|
|
1036
|
-
total_input_tokens: 0,
|
|
1037
|
-
total_output_tokens: 0,
|
|
1038
|
-
total_cost: 0
|
|
1065
|
+
message_count: stats?.message_count ?? Number(row.message_count ?? 0),
|
|
1066
|
+
total_input_tokens: stats?.total_input_tokens ?? 0,
|
|
1067
|
+
total_output_tokens: stats?.total_output_tokens ?? 0,
|
|
1068
|
+
total_cost: stats?.total_cost ?? 0
|
|
1039
1069
|
}
|
|
1040
1070
|
});
|
|
1041
1071
|
if (this.dbPath) {
|
|
@@ -1088,6 +1118,30 @@ var OpenCodeAgent = class extends BaseAgent {
|
|
|
1088
1118
|
incrementalScan(_cachedSessions, _changedIds) {
|
|
1089
1119
|
return this.scan();
|
|
1090
1120
|
}
|
|
1121
|
+
readSessionStats(db, sessionId) {
|
|
1122
|
+
try {
|
|
1123
|
+
const rows = db.prepare("SELECT data FROM message WHERE session_id = ? ORDER BY time_created ASC").all(sessionId);
|
|
1124
|
+
let totalCost = 0;
|
|
1125
|
+
let totalInputTokens = 0;
|
|
1126
|
+
let totalOutputTokens = 0;
|
|
1127
|
+
for (const row of rows) {
|
|
1128
|
+
const msgData = JSON.parse(String(row.data ?? "{}"));
|
|
1129
|
+
const cost = Number(msgData.cost ?? 0);
|
|
1130
|
+
const tokens = msgData.tokens;
|
|
1131
|
+
totalCost += cost;
|
|
1132
|
+
totalInputTokens += Number(tokens?.input ?? 0);
|
|
1133
|
+
totalOutputTokens += Number(tokens?.output ?? 0);
|
|
1134
|
+
}
|
|
1135
|
+
return {
|
|
1136
|
+
message_count: rows.length,
|
|
1137
|
+
total_input_tokens: totalInputTokens,
|
|
1138
|
+
total_output_tokens: totalOutputTokens,
|
|
1139
|
+
total_cost: totalCost
|
|
1140
|
+
};
|
|
1141
|
+
} catch {
|
|
1142
|
+
return null;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1091
1145
|
getSessionData(sessionId) {
|
|
1092
1146
|
if (!this.dbPath) {
|
|
1093
1147
|
this.dbPath = this.findDbPath();
|
|
@@ -1301,7 +1355,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1301
1355
|
parseSessionDir(sessionDir) {
|
|
1302
1356
|
try {
|
|
1303
1357
|
const sessionId = basename3(sessionDir);
|
|
1304
|
-
const projectHash = basename3(
|
|
1358
|
+
const projectHash = basename3(dirname3(sessionDir));
|
|
1305
1359
|
const contextFile = join4(sessionDir, "context.jsonl");
|
|
1306
1360
|
const wireFile = join4(sessionDir, "wire.jsonl");
|
|
1307
1361
|
if (!existsSync4(contextFile) && !existsSync4(wireFile)) return null;
|
|
@@ -1351,6 +1405,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1351
1405
|
perf.end(parseMarker);
|
|
1352
1406
|
if (!meta) continue;
|
|
1353
1407
|
this.sessionMetaMap.set(meta.id, meta);
|
|
1408
|
+
const stats = this.extractStats(meta.sourcePath);
|
|
1354
1409
|
heads.push({
|
|
1355
1410
|
id: meta.id,
|
|
1356
1411
|
slug: `kimi/${meta.id}`,
|
|
@@ -1358,12 +1413,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1358
1413
|
directory: meta.cwd,
|
|
1359
1414
|
time_created: meta.createdAt,
|
|
1360
1415
|
time_updated: meta.createdAt,
|
|
1361
|
-
stats
|
|
1362
|
-
message_count: 0,
|
|
1363
|
-
total_input_tokens: 0,
|
|
1364
|
-
total_output_tokens: 0,
|
|
1365
|
-
total_cost: 0
|
|
1366
|
-
}
|
|
1416
|
+
stats
|
|
1367
1417
|
});
|
|
1368
1418
|
} catch {
|
|
1369
1419
|
}
|
|
@@ -1421,6 +1471,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1421
1471
|
if (!meta) continue;
|
|
1422
1472
|
if (changedIds.includes(meta.id)) {
|
|
1423
1473
|
this.sessionMetaMap.set(meta.id, meta);
|
|
1474
|
+
const stats = this.extractStats(meta.sourcePath);
|
|
1424
1475
|
sessionMap.set(meta.id, {
|
|
1425
1476
|
id: meta.id,
|
|
1426
1477
|
slug: `kimi/${meta.id}`,
|
|
@@ -1428,12 +1479,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1428
1479
|
directory: meta.cwd,
|
|
1429
1480
|
time_created: meta.createdAt,
|
|
1430
1481
|
time_updated: meta.createdAt,
|
|
1431
|
-
stats
|
|
1432
|
-
message_count: 0,
|
|
1433
|
-
total_input_tokens: 0,
|
|
1434
|
-
total_output_tokens: 0,
|
|
1435
|
-
total_cost: 0
|
|
1436
|
-
}
|
|
1482
|
+
stats
|
|
1437
1483
|
});
|
|
1438
1484
|
}
|
|
1439
1485
|
} catch {
|
|
@@ -1861,6 +1907,7 @@ var CODEX_TOOL_TITLE_MAP = {
|
|
|
1861
1907
|
spawn_agent: "subagent",
|
|
1862
1908
|
subagent: "subagent"
|
|
1863
1909
|
};
|
|
1910
|
+
var RECENT_SESSION_REVALIDATION_WINDOW_MS2 = 24 * 60 * 60 * 1e3;
|
|
1864
1911
|
function extractSessionId(filename) {
|
|
1865
1912
|
const stem = basename4(filename, ".jsonl");
|
|
1866
1913
|
const parts = stem.split("-");
|
|
@@ -1878,6 +1925,9 @@ function parseTimestampMs2(data) {
|
|
|
1878
1925
|
return 0;
|
|
1879
1926
|
}
|
|
1880
1927
|
}
|
|
1928
|
+
function extractModelName(raw) {
|
|
1929
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
1930
|
+
}
|
|
1881
1931
|
function normalizeTitleText3(text) {
|
|
1882
1932
|
const line = text.split("\n").find((l) => l.trim());
|
|
1883
1933
|
return line?.trim().slice(0, 80) || "";
|
|
@@ -2051,34 +2101,43 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2051
2101
|
if (!this.basePath) {
|
|
2052
2102
|
return { hasChanges: false, timestamp: Date.now() };
|
|
2053
2103
|
}
|
|
2054
|
-
const
|
|
2104
|
+
const now = Date.now();
|
|
2105
|
+
const changedIds = /* @__PURE__ */ new Set();
|
|
2106
|
+
const currentFiles = this.listRolloutFiles();
|
|
2107
|
+
const currentIds = new Set(currentFiles.map((file) => extractSessionId(file)));
|
|
2108
|
+
const cachedIds = new Set(cachedSessions.map((session) => session.id));
|
|
2109
|
+
const recentIds = cachedSessions.filter((session) => now - session.time_created <= RECENT_SESSION_REVALIDATION_WINDOW_MS2).map((session) => session.id);
|
|
2110
|
+
for (const sessionId of recentIds) {
|
|
2111
|
+
changedIds.add(sessionId);
|
|
2112
|
+
}
|
|
2055
2113
|
for (const session of cachedSessions) {
|
|
2056
2114
|
const meta = this.sessionMetaMap.get(session.id);
|
|
2057
|
-
if (!
|
|
2115
|
+
if (!currentIds.has(session.id)) {
|
|
2116
|
+
changedIds.add(session.id);
|
|
2117
|
+
continue;
|
|
2118
|
+
}
|
|
2119
|
+
if (!meta) {
|
|
2120
|
+
changedIds.add(session.id);
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2058
2123
|
try {
|
|
2059
2124
|
const stat = statSync4(meta.sourcePath);
|
|
2060
2125
|
if (stat.mtimeMs > sinceTimestamp) {
|
|
2061
|
-
changedIds.
|
|
2126
|
+
changedIds.add(session.id);
|
|
2062
2127
|
}
|
|
2063
2128
|
} catch {
|
|
2064
|
-
changedIds.
|
|
2129
|
+
changedIds.add(session.id);
|
|
2065
2130
|
}
|
|
2066
2131
|
}
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
return {
|
|
2071
|
-
hasChanges: changedIds.length > 0 || hasNewFiles,
|
|
2072
|
-
changedIds,
|
|
2073
|
-
timestamp: Date.now()
|
|
2074
|
-
};
|
|
2075
|
-
} catch {
|
|
2076
|
-
return {
|
|
2077
|
-
hasChanges: changedIds.length > 0,
|
|
2078
|
-
changedIds,
|
|
2079
|
-
timestamp: Date.now()
|
|
2080
|
-
};
|
|
2132
|
+
const hasAddedSessions = currentFiles.some((file) => !cachedIds.has(extractSessionId(file)));
|
|
2133
|
+
if (recentIds.length > 0) {
|
|
2134
|
+
this.sessionIndexCache.clear();
|
|
2081
2135
|
}
|
|
2136
|
+
return {
|
|
2137
|
+
hasChanges: changedIds.size > 0 || hasAddedSessions,
|
|
2138
|
+
changedIds: Array.from(changedIds),
|
|
2139
|
+
timestamp: Date.now()
|
|
2140
|
+
};
|
|
2082
2141
|
}
|
|
2083
2142
|
/**
|
|
2084
2143
|
* 增量扫描
|
|
@@ -2086,10 +2145,19 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2086
2145
|
incrementalScan(cachedSessions, changedIds) {
|
|
2087
2146
|
if (!this.basePath) return cachedSessions;
|
|
2088
2147
|
const sessionMap = new Map(cachedSessions.map((s) => [s.id, s]));
|
|
2089
|
-
|
|
2148
|
+
const changedSet = new Set(changedIds);
|
|
2149
|
+
const currentFiles = this.listRolloutFiles();
|
|
2150
|
+
const currentIds = new Set(currentFiles.map((file) => extractSessionId(file)));
|
|
2151
|
+
for (const session of cachedSessions) {
|
|
2152
|
+
if (!currentIds.has(session.id)) {
|
|
2153
|
+
sessionMap.delete(session.id);
|
|
2154
|
+
this.sessionMetaMap.delete(session.id);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
for (const file of currentFiles) {
|
|
2090
2158
|
try {
|
|
2091
2159
|
const sessionId = extractSessionId(file);
|
|
2092
|
-
if (
|
|
2160
|
+
if (changedSet.has(sessionId)) {
|
|
2093
2161
|
const head = this.parseSessionHead(file);
|
|
2094
2162
|
if (head) {
|
|
2095
2163
|
sessionMap.set(head.id, head);
|
|
@@ -2108,7 +2176,7 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2108
2176
|
} catch {
|
|
2109
2177
|
}
|
|
2110
2178
|
}
|
|
2111
|
-
for (const file of
|
|
2179
|
+
for (const file of currentFiles) {
|
|
2112
2180
|
try {
|
|
2113
2181
|
const sessionId = extractSessionId(file);
|
|
2114
2182
|
if (!sessionMap.has(sessionId)) {
|
|
@@ -2144,13 +2212,18 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2144
2212
|
let currentAssistantIndex = null;
|
|
2145
2213
|
let latestAssistantTextIndex = null;
|
|
2146
2214
|
let pendingPlan = null;
|
|
2215
|
+
let activeModel = meta.model;
|
|
2147
2216
|
let prevCumulativeTotal = 0;
|
|
2148
2217
|
let prevInput = 0;
|
|
2149
|
-
let prevCached = 0;
|
|
2150
2218
|
let prevOutput = 0;
|
|
2151
2219
|
let prevReasoning = 0;
|
|
2152
2220
|
for (const record of parseJsonlLines(content)) {
|
|
2153
2221
|
try {
|
|
2222
|
+
const recordType = String(record["type"] ?? "");
|
|
2223
|
+
if (recordType === "turn_context") {
|
|
2224
|
+
const payload = record["payload"] ?? {};
|
|
2225
|
+
activeModel = extractModelName(payload["model"]) ?? activeModel;
|
|
2226
|
+
}
|
|
2154
2227
|
const result = this.convertRecord(
|
|
2155
2228
|
record,
|
|
2156
2229
|
messages,
|
|
@@ -2163,7 +2236,12 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2163
2236
|
currentAssistantIndex = result.currentAssistantIndex;
|
|
2164
2237
|
latestAssistantTextIndex = result.latestAssistantTextIndex;
|
|
2165
2238
|
pendingPlan = result.pendingPlan;
|
|
2166
|
-
|
|
2239
|
+
if (currentAssistantIndex !== null && activeModel) {
|
|
2240
|
+
const message = messages[currentAssistantIndex];
|
|
2241
|
+
if (message?.role === "assistant" && !message.model) {
|
|
2242
|
+
message.model = activeModel;
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2167
2245
|
if (recordType === "event_msg") {
|
|
2168
2246
|
const payload = record["payload"] ?? {};
|
|
2169
2247
|
if (String(payload["type"] ?? "") === "token_count") {
|
|
@@ -2175,33 +2253,29 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2175
2253
|
prevCumulativeTotal = cumulativeTotal;
|
|
2176
2254
|
const lastUsage = info?.["last_token_usage"];
|
|
2177
2255
|
let inputTokens = 0;
|
|
2178
|
-
let cachedInputTokens = 0;
|
|
2179
2256
|
let outputTokens = 0;
|
|
2180
2257
|
let reasoningTokens = 0;
|
|
2181
2258
|
if (lastUsage) {
|
|
2182
2259
|
inputTokens = Number(lastUsage["input_tokens"] ?? 0);
|
|
2183
|
-
cachedInputTokens = Number(lastUsage["cached_input_tokens"] ?? 0);
|
|
2184
2260
|
outputTokens = Number(lastUsage["output_tokens"] ?? 0);
|
|
2185
2261
|
reasoningTokens = Number(lastUsage["reasoning_output_tokens"] ?? 0);
|
|
2186
2262
|
} else if (cumulativeTotal > 0 && totalUsage) {
|
|
2187
2263
|
inputTokens = Number(totalUsage["input_tokens"] ?? 0) - prevInput;
|
|
2188
|
-
cachedInputTokens = Number(totalUsage["cached_input_tokens"] ?? 0) - prevCached;
|
|
2189
2264
|
outputTokens = Number(totalUsage["output_tokens"] ?? 0) - prevOutput;
|
|
2190
2265
|
reasoningTokens = Number(totalUsage["reasoning_output_tokens"] ?? 0) - prevReasoning;
|
|
2191
2266
|
prevInput = Number(totalUsage["input_tokens"] ?? 0);
|
|
2192
|
-
prevCached = Number(totalUsage["cached_input_tokens"] ?? 0);
|
|
2193
2267
|
prevOutput = Number(totalUsage["output_tokens"] ?? 0);
|
|
2194
2268
|
prevReasoning = Number(totalUsage["reasoning_output_tokens"] ?? 0);
|
|
2195
2269
|
}
|
|
2196
|
-
const
|
|
2197
|
-
if (
|
|
2198
|
-
totalInputTokens +=
|
|
2270
|
+
const totalInput = Math.max(0, inputTokens);
|
|
2271
|
+
if (totalInput || outputTokens || reasoningTokens) {
|
|
2272
|
+
totalInputTokens += totalInput;
|
|
2199
2273
|
totalOutputTokens += outputTokens + reasoningTokens;
|
|
2200
2274
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
2201
2275
|
const msg = messages[i];
|
|
2202
2276
|
if (msg.role === "assistant" && !msg.tokens) {
|
|
2203
2277
|
msg.tokens = {
|
|
2204
|
-
input:
|
|
2278
|
+
input: totalInput,
|
|
2205
2279
|
output: outputTokens + reasoningTokens
|
|
2206
2280
|
};
|
|
2207
2281
|
break;
|
|
@@ -2277,6 +2351,7 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2277
2351
|
}
|
|
2278
2352
|
}
|
|
2279
2353
|
getTitleForSession(sessionId) {
|
|
2354
|
+
this.loadSessionIndex();
|
|
2280
2355
|
return this.sessionIndexCache.get(sessionId) ?? null;
|
|
2281
2356
|
}
|
|
2282
2357
|
// ---- Session head parsing ----
|
|
@@ -2292,7 +2367,7 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2292
2367
|
return null;
|
|
2293
2368
|
}
|
|
2294
2369
|
const payload = firstRecord["payload"] ?? {};
|
|
2295
|
-
const createdAt = parseTimestampMs2(payload) || statSync4(filePath).mtimeMs;
|
|
2370
|
+
const createdAt = parseTimestampMs2(firstRecord) || parseTimestampMs2(payload) || statSync4(filePath).mtimeMs;
|
|
2296
2371
|
const indexTitle = this.getTitleForSession(sessionId);
|
|
2297
2372
|
const messageTitle = this.extractTitleFromLines(lines);
|
|
2298
2373
|
const directoryTitle = basenameTitle(payload["cwd"] ? String(payload["cwd"]) : null);
|
|
@@ -2304,7 +2379,6 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2304
2379
|
let totalOutputTokens = 0;
|
|
2305
2380
|
let scanPrevCumulativeTotal = 0;
|
|
2306
2381
|
let scanPrevInput = 0;
|
|
2307
|
-
let scanPrevCached = 0;
|
|
2308
2382
|
let scanPrevOutput = 0;
|
|
2309
2383
|
let scanPrevReasoning = 0;
|
|
2310
2384
|
const COUNTED_TYPES = /* @__PURE__ */ new Set(["message", "function_call", "function_call_output"]);
|
|
@@ -2312,10 +2386,13 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2312
2386
|
try {
|
|
2313
2387
|
const data = JSON.parse(line);
|
|
2314
2388
|
const recordType = String(data["type"] ?? "");
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2389
|
+
const recordTs = parseTimestampMs2(data) || parseTimestampMs2(data["payload"] ?? {});
|
|
2390
|
+
if (recordTs > updatedAt) updatedAt = recordTs;
|
|
2391
|
+
if (recordType === "session_meta" || recordType === "turn_context") {
|
|
2392
|
+
const payload2 = data["payload"] ?? {};
|
|
2393
|
+
if (!model) {
|
|
2394
|
+
model = extractModelName(payload2["model"]);
|
|
2395
|
+
}
|
|
2319
2396
|
continue;
|
|
2320
2397
|
}
|
|
2321
2398
|
if (recordType === "response_item") {
|
|
@@ -2340,26 +2417,22 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2340
2417
|
scanPrevCumulativeTotal = cumulativeTotal;
|
|
2341
2418
|
const lastUsage = info?.["last_token_usage"];
|
|
2342
2419
|
let inputTokens = 0;
|
|
2343
|
-
let cachedInputTokens = 0;
|
|
2344
2420
|
let outputTokens = 0;
|
|
2345
2421
|
let reasoningTokens = 0;
|
|
2346
2422
|
if (lastUsage) {
|
|
2347
2423
|
inputTokens = Number(lastUsage["input_tokens"] ?? 0);
|
|
2348
|
-
cachedInputTokens = Number(lastUsage["cached_input_tokens"] ?? 0);
|
|
2349
2424
|
outputTokens = Number(lastUsage["output_tokens"] ?? 0);
|
|
2350
2425
|
reasoningTokens = Number(lastUsage["reasoning_output_tokens"] ?? 0);
|
|
2351
2426
|
} else if (cumulativeTotal > 0 && totalUsage) {
|
|
2352
2427
|
inputTokens = Number(totalUsage["input_tokens"] ?? 0) - scanPrevInput;
|
|
2353
|
-
cachedInputTokens = Number(totalUsage["cached_input_tokens"] ?? 0) - scanPrevCached;
|
|
2354
2428
|
outputTokens = Number(totalUsage["output_tokens"] ?? 0) - scanPrevOutput;
|
|
2355
2429
|
reasoningTokens = Number(totalUsage["reasoning_output_tokens"] ?? 0) - scanPrevReasoning;
|
|
2356
2430
|
scanPrevInput = Number(totalUsage["input_tokens"] ?? 0);
|
|
2357
|
-
scanPrevCached = Number(totalUsage["cached_input_tokens"] ?? 0);
|
|
2358
2431
|
scanPrevOutput = Number(totalUsage["output_tokens"] ?? 0);
|
|
2359
2432
|
scanPrevReasoning = Number(totalUsage["reasoning_output_tokens"] ?? 0);
|
|
2360
2433
|
}
|
|
2361
|
-
const
|
|
2362
|
-
totalInputTokens +=
|
|
2434
|
+
const totalInput = Math.max(0, inputTokens);
|
|
2435
|
+
totalInputTokens += totalInput;
|
|
2363
2436
|
totalOutputTokens += outputTokens + reasoningTokens;
|
|
2364
2437
|
}
|
|
2365
2438
|
}
|
|
@@ -3002,7 +3075,12 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3002
3075
|
const title = this.extractTitle(composer);
|
|
3003
3076
|
const createdAt = composer.createdAt ?? 0;
|
|
3004
3077
|
const updatedAt = composer.updatedAt ?? createdAt;
|
|
3005
|
-
const messages = this.loadMessagesFromBubbles(
|
|
3078
|
+
const messages = this.loadMessagesFromBubbles(
|
|
3079
|
+
db,
|
|
3080
|
+
composerId,
|
|
3081
|
+
sessionId,
|
|
3082
|
+
composer.modelConfig?.modelName ?? composer.model ?? null
|
|
3083
|
+
);
|
|
3006
3084
|
const hasSubagents = Array.isArray(composer.subagentInfos) && composer.subagentInfos.length > 0;
|
|
3007
3085
|
if (messages.length === 0 && !hasSubagents) {
|
|
3008
3086
|
continue;
|
|
@@ -3114,7 +3192,12 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3114
3192
|
const title = this.extractTitle(composer);
|
|
3115
3193
|
const createdAt = composer.createdAt ?? 0;
|
|
3116
3194
|
const updatedAt = composer.updatedAt ?? createdAt;
|
|
3117
|
-
const messages = this.loadMessagesFromBubbles(
|
|
3195
|
+
const messages = this.loadMessagesFromBubbles(
|
|
3196
|
+
db,
|
|
3197
|
+
composerId,
|
|
3198
|
+
resolvedSessionId,
|
|
3199
|
+
composer.modelConfig?.modelName ?? composer.model ?? null
|
|
3200
|
+
);
|
|
3118
3201
|
let totalInputTokens = 0;
|
|
3119
3202
|
let totalOutputTokens = 0;
|
|
3120
3203
|
for (const msg of messages) {
|
|
@@ -3222,11 +3305,11 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3222
3305
|
}
|
|
3223
3306
|
}
|
|
3224
3307
|
/** Load messages from bubbles (like agent-dump) */
|
|
3225
|
-
loadMessagesFromBubbles(db, composerId, _sessionId) {
|
|
3308
|
+
loadMessagesFromBubbles(db, composerId, _sessionId, initialModelName) {
|
|
3226
3309
|
const messages = [];
|
|
3227
3310
|
try {
|
|
3228
3311
|
const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ORDER BY rowid ASC").all(`bubbleId:${composerId}:%`);
|
|
3229
|
-
let activeModelName =
|
|
3312
|
+
let activeModelName = initialModelName;
|
|
3230
3313
|
let messageIndex = 0;
|
|
3231
3314
|
for (const row of rows) {
|
|
3232
3315
|
try {
|
|
@@ -3241,7 +3324,7 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3241
3324
|
} else if (bubble.timestamp) {
|
|
3242
3325
|
timestampMs = bubble.timestamp;
|
|
3243
3326
|
}
|
|
3244
|
-
if (
|
|
3327
|
+
if (bubble.modelInfo?.modelName) {
|
|
3245
3328
|
activeModelName = bubble.modelInfo.modelName;
|
|
3246
3329
|
}
|
|
3247
3330
|
const inputTokens = bubble.tokenCount?.inputTokens ?? 0;
|
|
@@ -3265,7 +3348,7 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3265
3348
|
time_created: timestampMs,
|
|
3266
3349
|
time_completed: null,
|
|
3267
3350
|
mode: role === "assistant" && parts.some((p) => p.type === "tool") ? "tool" : null,
|
|
3268
|
-
model: activeModelName,
|
|
3351
|
+
model: bubble.modelInfo?.modelName ?? activeModelName,
|
|
3269
3352
|
provider: null,
|
|
3270
3353
|
tokens: { input: inputTokens, output: outputTokens },
|
|
3271
3354
|
cost: 0,
|
|
@@ -3424,89 +3507,438 @@ registerAgent({
|
|
|
3424
3507
|
icon: "/icon/agent/cursor.svg",
|
|
3425
3508
|
create: () => new CursorAgent()
|
|
3426
3509
|
});
|
|
3427
|
-
var CACHE_VERSION =
|
|
3428
|
-
var
|
|
3510
|
+
var CACHE_VERSION = 3;
|
|
3511
|
+
var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
3512
|
+
var CACHE_FILENAME = "codesesh.db";
|
|
3513
|
+
var LEGACY_CACHE_FILENAME = "scan-cache.json";
|
|
3514
|
+
function getCacheDir() {
|
|
3515
|
+
return join7(homedir2(), ".cache", "codesesh");
|
|
3516
|
+
}
|
|
3429
3517
|
function getCachePath() {
|
|
3430
|
-
return join7(
|
|
3518
|
+
return join7(getCacheDir(), CACHE_FILENAME);
|
|
3431
3519
|
}
|
|
3432
|
-
function
|
|
3433
|
-
|
|
3434
|
-
if (!existsSync7(cacheDir)) {
|
|
3435
|
-
mkdirSync(cacheDir, { recursive: true });
|
|
3436
|
-
}
|
|
3520
|
+
function getLegacyCachePath() {
|
|
3521
|
+
return join7(getCacheDir(), LEGACY_CACHE_FILENAME);
|
|
3437
3522
|
}
|
|
3438
|
-
function
|
|
3523
|
+
function hasCacheStorage() {
|
|
3524
|
+
return existsSync7(getCachePath());
|
|
3525
|
+
}
|
|
3526
|
+
function withCacheDb(fn) {
|
|
3527
|
+
const db = openDb(getCachePath());
|
|
3528
|
+
if (!db) return null;
|
|
3439
3529
|
try {
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
const data = JSON.parse(readFileSync6(cachePath, "utf-8"));
|
|
3443
|
-
if (data.version !== CACHE_VERSION) return null;
|
|
3444
|
-
const entry = data.entries[agentName];
|
|
3445
|
-
if (!entry) return null;
|
|
3446
|
-
const CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
3447
|
-
if (Date.now() - entry.timestamp > CACHE_TTL) return null;
|
|
3448
|
-
return { sessions: entry.sessions, meta: entry.meta || {}, timestamp: entry.timestamp };
|
|
3530
|
+
ensureSchema(db);
|
|
3531
|
+
return fn(db);
|
|
3449
3532
|
} catch {
|
|
3450
3533
|
return null;
|
|
3534
|
+
} finally {
|
|
3535
|
+
db.close();
|
|
3451
3536
|
}
|
|
3452
3537
|
}
|
|
3453
|
-
function
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3538
|
+
function ensureSchema(db) {
|
|
3539
|
+
db.exec(`
|
|
3540
|
+
CREATE TABLE IF NOT EXISTS cache_meta (
|
|
3541
|
+
key TEXT PRIMARY KEY,
|
|
3542
|
+
value TEXT NOT NULL
|
|
3543
|
+
);
|
|
3544
|
+
|
|
3545
|
+
CREATE TABLE IF NOT EXISTS agent_cache (
|
|
3546
|
+
agent_name TEXT PRIMARY KEY,
|
|
3547
|
+
timestamp INTEGER NOT NULL
|
|
3548
|
+
);
|
|
3549
|
+
|
|
3550
|
+
CREATE TABLE IF NOT EXISTS cached_sessions (
|
|
3551
|
+
agent_name TEXT NOT NULL,
|
|
3552
|
+
session_id TEXT NOT NULL,
|
|
3553
|
+
session_json TEXT NOT NULL,
|
|
3554
|
+
meta_json TEXT,
|
|
3555
|
+
PRIMARY KEY (agent_name, session_id)
|
|
3556
|
+
);
|
|
3557
|
+
|
|
3558
|
+
CREATE TABLE IF NOT EXISTS session_documents (
|
|
3559
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3560
|
+
agent_name TEXT NOT NULL,
|
|
3561
|
+
session_id TEXT NOT NULL,
|
|
3562
|
+
slug TEXT NOT NULL,
|
|
3563
|
+
title TEXT NOT NULL,
|
|
3564
|
+
directory TEXT NOT NULL,
|
|
3565
|
+
time_created INTEGER NOT NULL,
|
|
3566
|
+
time_updated INTEGER,
|
|
3567
|
+
activity_time INTEGER NOT NULL,
|
|
3568
|
+
content_text TEXT NOT NULL,
|
|
3569
|
+
content_hash TEXT NOT NULL,
|
|
3570
|
+
indexed_at INTEGER NOT NULL,
|
|
3571
|
+
UNIQUE(agent_name, session_id)
|
|
3572
|
+
);
|
|
3573
|
+
|
|
3574
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS session_documents_fts USING fts5(
|
|
3575
|
+
title,
|
|
3576
|
+
content_text,
|
|
3577
|
+
content='session_documents',
|
|
3578
|
+
content_rowid='id'
|
|
3579
|
+
);
|
|
3580
|
+
|
|
3581
|
+
CREATE TRIGGER IF NOT EXISTS session_documents_ai AFTER INSERT ON session_documents BEGIN
|
|
3582
|
+
INSERT INTO session_documents_fts(rowid, title, content_text)
|
|
3583
|
+
VALUES (new.id, new.title, new.content_text);
|
|
3584
|
+
END;
|
|
3585
|
+
|
|
3586
|
+
CREATE TRIGGER IF NOT EXISTS session_documents_ad AFTER DELETE ON session_documents BEGIN
|
|
3587
|
+
INSERT INTO session_documents_fts(session_documents_fts, rowid, title, content_text)
|
|
3588
|
+
VALUES ('delete', old.id, old.title, old.content_text);
|
|
3589
|
+
END;
|
|
3590
|
+
|
|
3591
|
+
CREATE TRIGGER IF NOT EXISTS session_documents_au AFTER UPDATE ON session_documents BEGIN
|
|
3592
|
+
INSERT INTO session_documents_fts(session_documents_fts, rowid, title, content_text)
|
|
3593
|
+
VALUES ('delete', old.id, old.title, old.content_text);
|
|
3594
|
+
INSERT INTO session_documents_fts(rowid, title, content_text)
|
|
3595
|
+
VALUES (new.id, new.title, new.content_text);
|
|
3596
|
+
END;
|
|
3597
|
+
`);
|
|
3598
|
+
const versionRow = db.prepare("SELECT value FROM cache_meta WHERE key = 'version'").get();
|
|
3599
|
+
const version = Number(versionRow?.value ?? 0);
|
|
3600
|
+
if (version === CACHE_VERSION) {
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
db.exec(`
|
|
3604
|
+
DELETE FROM agent_cache;
|
|
3605
|
+
DELETE FROM cached_sessions;
|
|
3606
|
+
DELETE FROM session_documents;
|
|
3607
|
+
INSERT INTO session_documents_fts(session_documents_fts) VALUES ('rebuild');
|
|
3608
|
+
INSERT INTO cache_meta(key, value)
|
|
3609
|
+
VALUES ('version', '${CACHE_VERSION}')
|
|
3610
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value;
|
|
3611
|
+
`);
|
|
3612
|
+
}
|
|
3613
|
+
function sessionContentHash(session) {
|
|
3614
|
+
return JSON.stringify([
|
|
3615
|
+
session.slug,
|
|
3616
|
+
session.title,
|
|
3617
|
+
session.directory,
|
|
3618
|
+
session.time_created,
|
|
3619
|
+
session.time_updated ?? session.time_created,
|
|
3620
|
+
session.stats.message_count,
|
|
3621
|
+
session.stats.total_input_tokens,
|
|
3622
|
+
session.stats.total_output_tokens,
|
|
3623
|
+
session.stats.total_cost,
|
|
3624
|
+
session.stats.total_tokens ?? 0
|
|
3625
|
+
]);
|
|
3626
|
+
}
|
|
3627
|
+
function escapeFtsTerm(value) {
|
|
3628
|
+
return value.replaceAll('"', '""');
|
|
3629
|
+
}
|
|
3630
|
+
function toFtsQuery(input) {
|
|
3631
|
+
const tokens = input.match(/"[^"]+"|\S+/g) ?? [];
|
|
3632
|
+
return tokens.map((token) => {
|
|
3633
|
+
if (/^OR$/i.test(token)) {
|
|
3634
|
+
return "OR";
|
|
3469
3635
|
}
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3636
|
+
if (token.startsWith('"') && token.endsWith('"')) {
|
|
3637
|
+
return `"${escapeFtsTerm(token.slice(1, -1))}"`;
|
|
3638
|
+
}
|
|
3639
|
+
return `"${escapeFtsTerm(token)}"`;
|
|
3640
|
+
}).join(" ");
|
|
3641
|
+
}
|
|
3642
|
+
function appendPlainText(value, chunks) {
|
|
3643
|
+
if (value == null) return;
|
|
3644
|
+
if (typeof value === "string") {
|
|
3645
|
+
const normalized = value.trim();
|
|
3646
|
+
if (normalized) {
|
|
3647
|
+
chunks.push(normalized);
|
|
3648
|
+
}
|
|
3649
|
+
return;
|
|
3650
|
+
}
|
|
3651
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
3652
|
+
chunks.push(String(value));
|
|
3653
|
+
return;
|
|
3654
|
+
}
|
|
3655
|
+
if (Array.isArray(value)) {
|
|
3656
|
+
for (const item of value) {
|
|
3657
|
+
appendPlainText(item, chunks);
|
|
3658
|
+
}
|
|
3659
|
+
return;
|
|
3660
|
+
}
|
|
3661
|
+
if (typeof value === "object") {
|
|
3662
|
+
for (const nested of Object.values(value)) {
|
|
3663
|
+
appendPlainText(nested, chunks);
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
function buildSessionContent(session) {
|
|
3668
|
+
const chunks = [];
|
|
3669
|
+
appendPlainText(session.title, chunks);
|
|
3670
|
+
for (const message of session.messages) {
|
|
3671
|
+
chunks.push(message.role);
|
|
3672
|
+
appendPlainText(message.agent, chunks);
|
|
3673
|
+
appendPlainText(message.model, chunks);
|
|
3674
|
+
for (const part of message.parts) {
|
|
3675
|
+
appendPlainText(part.type, chunks);
|
|
3676
|
+
appendPlainText(part.title, chunks);
|
|
3677
|
+
appendPlainText(part.nickname, chunks);
|
|
3678
|
+
appendPlainText(part.tool, chunks);
|
|
3679
|
+
appendPlainText(part.text, chunks);
|
|
3680
|
+
appendPlainText(part.input, chunks);
|
|
3681
|
+
appendPlainText(part.output, chunks);
|
|
3682
|
+
appendPlainText(part.state, chunks);
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
return chunks.join("\n");
|
|
3686
|
+
}
|
|
3687
|
+
function deleteLegacyCacheFile() {
|
|
3688
|
+
const legacyPath = getLegacyCachePath();
|
|
3689
|
+
if (!existsSync7(legacyPath)) {
|
|
3690
|
+
return;
|
|
3691
|
+
}
|
|
3692
|
+
try {
|
|
3693
|
+
unlinkSync(legacyPath);
|
|
3478
3694
|
} catch {
|
|
3479
3695
|
}
|
|
3480
3696
|
}
|
|
3697
|
+
function loadCachedSessions(agentName) {
|
|
3698
|
+
if (!hasCacheStorage()) {
|
|
3699
|
+
return null;
|
|
3700
|
+
}
|
|
3701
|
+
return withCacheDb((db) => {
|
|
3702
|
+
const timestampRow = db.prepare("SELECT timestamp AS value FROM agent_cache WHERE agent_name = ?").get(agentName);
|
|
3703
|
+
const timestamp = Number(timestampRow?.value ?? 0);
|
|
3704
|
+
if (!timestamp || Date.now() - timestamp > CACHE_TTL) {
|
|
3705
|
+
return null;
|
|
3706
|
+
}
|
|
3707
|
+
const rows = db.prepare(
|
|
3708
|
+
`
|
|
3709
|
+
SELECT session_json, meta_json
|
|
3710
|
+
FROM cached_sessions
|
|
3711
|
+
WHERE agent_name = ?
|
|
3712
|
+
ORDER BY rowid
|
|
3713
|
+
`
|
|
3714
|
+
).all(agentName);
|
|
3715
|
+
const sessions = [];
|
|
3716
|
+
const meta = {};
|
|
3717
|
+
for (const row of rows) {
|
|
3718
|
+
if (!row.session_json) {
|
|
3719
|
+
continue;
|
|
3720
|
+
}
|
|
3721
|
+
const session = JSON.parse(row.session_json);
|
|
3722
|
+
sessions.push(session);
|
|
3723
|
+
if (row.meta_json) {
|
|
3724
|
+
meta[session.id] = JSON.parse(row.meta_json);
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
return { sessions, meta, timestamp };
|
|
3728
|
+
});
|
|
3729
|
+
}
|
|
3730
|
+
function saveCachedSessions(agentName, sessions, meta = {}) {
|
|
3731
|
+
withCacheDb((db) => {
|
|
3732
|
+
const deleteAgent = db.prepare("DELETE FROM agent_cache WHERE agent_name = ?");
|
|
3733
|
+
const deleteSessions = db.prepare("DELETE FROM cached_sessions WHERE agent_name = ?");
|
|
3734
|
+
const upsertAgent = db.prepare(`
|
|
3735
|
+
INSERT INTO agent_cache(agent_name, timestamp)
|
|
3736
|
+
VALUES (?, ?)
|
|
3737
|
+
ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp
|
|
3738
|
+
`);
|
|
3739
|
+
const insertSession = db.prepare(`
|
|
3740
|
+
INSERT INTO cached_sessions(agent_name, session_id, session_json, meta_json)
|
|
3741
|
+
VALUES (?, ?, ?, ?)
|
|
3742
|
+
`);
|
|
3743
|
+
const write = db.transaction(() => {
|
|
3744
|
+
const timestamp = Date.now();
|
|
3745
|
+
deleteAgent.run(agentName);
|
|
3746
|
+
deleteSessions.run(agentName);
|
|
3747
|
+
upsertAgent.run(agentName, timestamp);
|
|
3748
|
+
for (const session of sessions) {
|
|
3749
|
+
insertSession.run(
|
|
3750
|
+
agentName,
|
|
3751
|
+
session.id,
|
|
3752
|
+
JSON.stringify(session),
|
|
3753
|
+
meta[session.id] ? JSON.stringify(meta[session.id]) : null
|
|
3754
|
+
);
|
|
3755
|
+
}
|
|
3756
|
+
});
|
|
3757
|
+
write();
|
|
3758
|
+
deleteLegacyCacheFile();
|
|
3759
|
+
});
|
|
3760
|
+
}
|
|
3481
3761
|
function clearCache() {
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3762
|
+
if (!hasCacheStorage()) {
|
|
3763
|
+
deleteLegacyCacheFile();
|
|
3764
|
+
return;
|
|
3765
|
+
}
|
|
3766
|
+
withCacheDb((db) => {
|
|
3767
|
+
db.exec(`
|
|
3768
|
+
DELETE FROM agent_cache;
|
|
3769
|
+
DELETE FROM cached_sessions;
|
|
3770
|
+
`);
|
|
3771
|
+
});
|
|
3772
|
+
deleteLegacyCacheFile();
|
|
3773
|
+
const cachePath = getCachePath();
|
|
3774
|
+
const walPath = `${cachePath}-wal`;
|
|
3775
|
+
const shmPath = `${cachePath}-shm`;
|
|
3776
|
+
for (const filePath of [walPath, shmPath]) {
|
|
3777
|
+
if (!existsSync7(filePath)) {
|
|
3778
|
+
continue;
|
|
3779
|
+
}
|
|
3780
|
+
try {
|
|
3781
|
+
rmSync(filePath, { force: true });
|
|
3782
|
+
} catch {
|
|
3491
3783
|
}
|
|
3492
|
-
} catch {
|
|
3493
3784
|
}
|
|
3494
3785
|
}
|
|
3495
3786
|
function getCacheInfo() {
|
|
3496
|
-
|
|
3497
|
-
const cachePath = getCachePath();
|
|
3498
|
-
if (!existsSync7(cachePath)) {
|
|
3499
|
-
return { lastScanTime: null, size: 0 };
|
|
3500
|
-
}
|
|
3501
|
-
const data = JSON.parse(readFileSync6(cachePath, "utf-8"));
|
|
3502
|
-
const size = Object.values(data.entries).reduce((sum, entry) => sum + entry.sessions.length, 0);
|
|
3503
|
-
return {
|
|
3504
|
-
lastScanTime: data.lastScanTime || null,
|
|
3505
|
-
size
|
|
3506
|
-
};
|
|
3507
|
-
} catch {
|
|
3787
|
+
if (!hasCacheStorage()) {
|
|
3508
3788
|
return { lastScanTime: null, size: 0 };
|
|
3509
3789
|
}
|
|
3790
|
+
const info = withCacheDb((db) => {
|
|
3791
|
+
const timestampRow = db.prepare("SELECT MAX(timestamp) AS value FROM agent_cache").get();
|
|
3792
|
+
const sizeRow = db.prepare("SELECT COUNT(*) AS value FROM cached_sessions").get();
|
|
3793
|
+
const lastScanTime = Number(timestampRow?.value ?? 0) || null;
|
|
3794
|
+
const size = Number(sizeRow?.value ?? 0);
|
|
3795
|
+
return { lastScanTime, size };
|
|
3796
|
+
});
|
|
3797
|
+
return info ?? { lastScanTime: null, size: 0 };
|
|
3798
|
+
}
|
|
3799
|
+
function syncSessionSearchIndex(agentName, sessions, loadSessionData) {
|
|
3800
|
+
if (!hasCacheStorage()) {
|
|
3801
|
+
return;
|
|
3802
|
+
}
|
|
3803
|
+
withCacheDb((db) => {
|
|
3804
|
+
const existingRows = db.prepare(
|
|
3805
|
+
"SELECT session_id, content_hash FROM session_documents WHERE agent_name = ? ORDER BY id"
|
|
3806
|
+
).all(agentName);
|
|
3807
|
+
const existingMap = new Map(
|
|
3808
|
+
existingRows.map((row) => [String(row.session_id), String(row.content_hash ?? "")])
|
|
3809
|
+
);
|
|
3810
|
+
const sessionMap = new Map(sessions.map((session) => [session.id, session]));
|
|
3811
|
+
const toDelete = existingRows.map((row) => String(row.session_id)).filter((sessionId) => !sessionMap.has(sessionId));
|
|
3812
|
+
const toUpsert = sessions.filter(
|
|
3813
|
+
(session) => existingMap.get(session.id) !== sessionContentHash(session)
|
|
3814
|
+
);
|
|
3815
|
+
const loaded = toUpsert.map((session) => {
|
|
3816
|
+
try {
|
|
3817
|
+
const data = loadSessionData(session.id);
|
|
3818
|
+
return {
|
|
3819
|
+
session,
|
|
3820
|
+
contentText: buildSessionContent(data),
|
|
3821
|
+
contentHash: sessionContentHash(session)
|
|
3822
|
+
};
|
|
3823
|
+
} catch {
|
|
3824
|
+
return null;
|
|
3825
|
+
}
|
|
3826
|
+
}).filter((entry) => entry !== null);
|
|
3827
|
+
const deleteRow = db.prepare(
|
|
3828
|
+
"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?"
|
|
3829
|
+
);
|
|
3830
|
+
const upsertRow = db.prepare(`
|
|
3831
|
+
INSERT INTO session_documents(
|
|
3832
|
+
agent_name,
|
|
3833
|
+
session_id,
|
|
3834
|
+
slug,
|
|
3835
|
+
title,
|
|
3836
|
+
directory,
|
|
3837
|
+
time_created,
|
|
3838
|
+
time_updated,
|
|
3839
|
+
activity_time,
|
|
3840
|
+
content_text,
|
|
3841
|
+
content_hash,
|
|
3842
|
+
indexed_at
|
|
3843
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
3844
|
+
ON CONFLICT(agent_name, session_id) DO UPDATE SET
|
|
3845
|
+
slug = excluded.slug,
|
|
3846
|
+
title = excluded.title,
|
|
3847
|
+
directory = excluded.directory,
|
|
3848
|
+
time_created = excluded.time_created,
|
|
3849
|
+
time_updated = excluded.time_updated,
|
|
3850
|
+
activity_time = excluded.activity_time,
|
|
3851
|
+
content_text = excluded.content_text,
|
|
3852
|
+
content_hash = excluded.content_hash,
|
|
3853
|
+
indexed_at = excluded.indexed_at
|
|
3854
|
+
`);
|
|
3855
|
+
const write = db.transaction(() => {
|
|
3856
|
+
for (const sessionId of toDelete) {
|
|
3857
|
+
deleteRow.run(agentName, sessionId);
|
|
3858
|
+
}
|
|
3859
|
+
for (const entry of loaded) {
|
|
3860
|
+
const activityTime = entry.session.time_updated ?? entry.session.time_created;
|
|
3861
|
+
upsertRow.run(
|
|
3862
|
+
agentName,
|
|
3863
|
+
entry.session.id,
|
|
3864
|
+
entry.session.slug,
|
|
3865
|
+
entry.session.title,
|
|
3866
|
+
entry.session.directory,
|
|
3867
|
+
entry.session.time_created,
|
|
3868
|
+
entry.session.time_updated ?? null,
|
|
3869
|
+
activityTime,
|
|
3870
|
+
entry.contentText,
|
|
3871
|
+
entry.contentHash,
|
|
3872
|
+
Date.now()
|
|
3873
|
+
);
|
|
3874
|
+
}
|
|
3875
|
+
});
|
|
3876
|
+
write();
|
|
3877
|
+
});
|
|
3878
|
+
}
|
|
3879
|
+
function searchSessions(query, options = {}) {
|
|
3880
|
+
const normalizedQuery = query.trim();
|
|
3881
|
+
if (!normalizedQuery || !hasCacheStorage()) {
|
|
3882
|
+
return [];
|
|
3883
|
+
}
|
|
3884
|
+
const ftsQuery = toFtsQuery(normalizedQuery);
|
|
3885
|
+
const results = withCacheDb((db) => {
|
|
3886
|
+
const rows = db.prepare(
|
|
3887
|
+
`
|
|
3888
|
+
SELECT
|
|
3889
|
+
d.agent_name,
|
|
3890
|
+
d.session_id,
|
|
3891
|
+
d.slug,
|
|
3892
|
+
d.title,
|
|
3893
|
+
d.directory,
|
|
3894
|
+
d.time_created,
|
|
3895
|
+
d.time_updated,
|
|
3896
|
+
COALESCE(
|
|
3897
|
+
NULLIF(snippet(session_documents_fts, 1, '<mark>', '</mark>', ' \u2026 ', 18), ''),
|
|
3898
|
+
highlight(session_documents_fts, 0, '<mark>', '</mark>')
|
|
3899
|
+
) AS snippet
|
|
3900
|
+
FROM session_documents_fts
|
|
3901
|
+
JOIN session_documents d ON d.id = session_documents_fts.rowid
|
|
3902
|
+
WHERE session_documents_fts MATCH ?
|
|
3903
|
+
AND (? IS NULL OR d.agent_name = ?)
|
|
3904
|
+
AND (? IS NULL OR LOWER(d.directory) LIKE ?)
|
|
3905
|
+
AND (? IS NULL OR d.activity_time >= ?)
|
|
3906
|
+
AND (? IS NULL OR d.activity_time <= ?)
|
|
3907
|
+
ORDER BY bm25(session_documents_fts, 8.0, 1.0), d.activity_time DESC
|
|
3908
|
+
LIMIT ?
|
|
3909
|
+
`
|
|
3910
|
+
).all(
|
|
3911
|
+
ftsQuery,
|
|
3912
|
+
options.agent ?? null,
|
|
3913
|
+
options.agent ?? null,
|
|
3914
|
+
options.cwd?.toLowerCase() ?? null,
|
|
3915
|
+
options.cwd ? `%${options.cwd.toLowerCase()}%` : null,
|
|
3916
|
+
options.from ?? null,
|
|
3917
|
+
options.from ?? null,
|
|
3918
|
+
options.to ?? null,
|
|
3919
|
+
options.to ?? null,
|
|
3920
|
+
options.limit ?? 50
|
|
3921
|
+
);
|
|
3922
|
+
return rows.map((row) => ({
|
|
3923
|
+
agentName: String(row.agent_name),
|
|
3924
|
+
session: {
|
|
3925
|
+
id: String(row.session_id),
|
|
3926
|
+
slug: String(row.slug),
|
|
3927
|
+
title: String(row.title),
|
|
3928
|
+
directory: String(row.directory),
|
|
3929
|
+
time_created: Number(row.time_created),
|
|
3930
|
+
time_updated: row.time_updated == null ? void 0 : Number(row.time_updated),
|
|
3931
|
+
stats: {
|
|
3932
|
+
message_count: 0,
|
|
3933
|
+
total_input_tokens: 0,
|
|
3934
|
+
total_output_tokens: 0,
|
|
3935
|
+
total_cost: 0
|
|
3936
|
+
}
|
|
3937
|
+
},
|
|
3938
|
+
snippet: String(row.snippet ?? "")
|
|
3939
|
+
}));
|
|
3940
|
+
});
|
|
3941
|
+
return results ?? [];
|
|
3510
3942
|
}
|
|
3511
3943
|
function isPathScopeMatch(queryPath, sessionPath) {
|
|
3512
3944
|
if (!sessionPath) return false;
|
|
@@ -3531,9 +3963,18 @@ function filterSessions(sessions, options) {
|
|
|
3531
3963
|
}
|
|
3532
3964
|
return result;
|
|
3533
3965
|
}
|
|
3966
|
+
function buildAgentCacheMeta(agent) {
|
|
3967
|
+
const metaMap = agent.getSessionMetaMap?.();
|
|
3968
|
+
const meta = {};
|
|
3969
|
+
if (!metaMap) return meta;
|
|
3970
|
+
for (const [id, data] of metaMap.entries()) {
|
|
3971
|
+
meta[id] = { id, ...data };
|
|
3972
|
+
}
|
|
3973
|
+
return meta;
|
|
3974
|
+
}
|
|
3534
3975
|
async function scanAgentSmart(agent, options, onProgress) {
|
|
3535
3976
|
const useCache = options.useCache ?? true;
|
|
3536
|
-
const
|
|
3977
|
+
const canValidateCache = Boolean(agent.checkForChanges && agent.incrementalScan);
|
|
3537
3978
|
if (useCache) {
|
|
3538
3979
|
const cached = loadCachedSessions(agent.name);
|
|
3539
3980
|
if (cached !== null) {
|
|
@@ -3544,16 +3985,39 @@ async function scanAgentSmart(agent, options, onProgress) {
|
|
|
3544
3985
|
}
|
|
3545
3986
|
agent.setSessionMetaMap(metaMap);
|
|
3546
3987
|
}
|
|
3547
|
-
agent.isAvailable();
|
|
3988
|
+
const isAvail = agent.isAvailable();
|
|
3989
|
+
if (!isAvail) {
|
|
3990
|
+
return null;
|
|
3991
|
+
}
|
|
3548
3992
|
onProgress?.({
|
|
3549
3993
|
agent: agent.name,
|
|
3550
3994
|
phase: "cache",
|
|
3551
3995
|
cachedCount: cached.sessions.length
|
|
3552
3996
|
});
|
|
3553
|
-
if (
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3997
|
+
if (canValidateCache) {
|
|
3998
|
+
onProgress?.({ agent: agent.name, phase: "checking" });
|
|
3999
|
+
const checkResult = await Promise.resolve(
|
|
4000
|
+
agent.checkForChanges(cached.timestamp, cached.sessions)
|
|
4001
|
+
);
|
|
4002
|
+
if (checkResult.hasChanges) {
|
|
4003
|
+
onProgress?.({
|
|
4004
|
+
agent: agent.name,
|
|
4005
|
+
phase: "incremental",
|
|
4006
|
+
changedCount: checkResult.changedIds?.length
|
|
4007
|
+
});
|
|
4008
|
+
const updatedSessions = await Promise.resolve(
|
|
4009
|
+
agent.incrementalScan(cached.sessions, checkResult.changedIds || [])
|
|
4010
|
+
);
|
|
4011
|
+
saveCachedSessions(agent.name, updatedSessions, buildAgentCacheMeta(agent));
|
|
4012
|
+
onProgress?.({
|
|
4013
|
+
agent: agent.name,
|
|
4014
|
+
phase: "complete",
|
|
4015
|
+
newCount: updatedSessions.length
|
|
4016
|
+
});
|
|
4017
|
+
const filtered2 = filterSessions(updatedSessions, options);
|
|
4018
|
+
return { agent, heads: filtered2, fromCache: true, refreshed: true };
|
|
4019
|
+
}
|
|
4020
|
+
onProgress?.({ agent: agent.name, phase: "complete", newCount: cached.sessions.length });
|
|
3557
4021
|
}
|
|
3558
4022
|
const filtered = filterSessions(cached.sessions, options);
|
|
3559
4023
|
return { agent, heads: filtered, fromCache: true };
|
|
@@ -3561,41 +4025,6 @@ async function scanAgentSmart(agent, options, onProgress) {
|
|
|
3561
4025
|
}
|
|
3562
4026
|
return scanAgentFull(agent, options, onProgress);
|
|
3563
4027
|
}
|
|
3564
|
-
async function refreshAgentAsync(agent, cachedSessions, cacheTimestamp, onProgress) {
|
|
3565
|
-
try {
|
|
3566
|
-
onProgress?.({ agent: agent.name, phase: "checking" });
|
|
3567
|
-
const checkResult = await Promise.resolve(
|
|
3568
|
-
agent.checkForChanges(cacheTimestamp, cachedSessions)
|
|
3569
|
-
);
|
|
3570
|
-
if (!checkResult.hasChanges) {
|
|
3571
|
-
onProgress?.({ agent: agent.name, phase: "complete" });
|
|
3572
|
-
return;
|
|
3573
|
-
}
|
|
3574
|
-
onProgress?.({
|
|
3575
|
-
agent: agent.name,
|
|
3576
|
-
phase: "incremental",
|
|
3577
|
-
changedCount: checkResult.changedIds?.length
|
|
3578
|
-
});
|
|
3579
|
-
const updatedSessions = await Promise.resolve(
|
|
3580
|
-
agent.incrementalScan(cachedSessions, checkResult.changedIds || [])
|
|
3581
|
-
);
|
|
3582
|
-
const metaMap = agent.getSessionMetaMap?.();
|
|
3583
|
-
const meta = {};
|
|
3584
|
-
if (metaMap) {
|
|
3585
|
-
for (const [id, data] of metaMap.entries()) {
|
|
3586
|
-
meta[id] = { id, ...data };
|
|
3587
|
-
}
|
|
3588
|
-
}
|
|
3589
|
-
saveCachedSessions(agent.name, updatedSessions, meta);
|
|
3590
|
-
onProgress?.({
|
|
3591
|
-
agent: agent.name,
|
|
3592
|
-
phase: "complete",
|
|
3593
|
-
newCount: updatedSessions.length
|
|
3594
|
-
});
|
|
3595
|
-
} catch (err) {
|
|
3596
|
-
console.error(`[${agent.name}] Background refresh failed:`, err);
|
|
3597
|
-
}
|
|
3598
|
-
}
|
|
3599
4028
|
async function scanAgentFull(agent, options, onProgress) {
|
|
3600
4029
|
const availMarker = perf.start(`agent:${agent.name}:isAvailable`);
|
|
3601
4030
|
const isAvail = agent.isAvailable();
|
|
@@ -3607,13 +4036,7 @@ async function scanAgentFull(agent, options, onProgress) {
|
|
|
3607
4036
|
const scanMarker = perf.start(`agent:${agent.name}:scan`);
|
|
3608
4037
|
const heads = agent.scan();
|
|
3609
4038
|
perf.end(scanMarker);
|
|
3610
|
-
const
|
|
3611
|
-
const meta = {};
|
|
3612
|
-
if (metaMap) {
|
|
3613
|
-
for (const [id, data] of metaMap.entries()) {
|
|
3614
|
-
meta[id] = { id, ...data };
|
|
3615
|
-
}
|
|
3616
|
-
}
|
|
4039
|
+
const meta = buildAgentCacheMeta(agent);
|
|
3617
4040
|
saveCachedSessions(agent.name, heads, meta);
|
|
3618
4041
|
onProgress?.({ agent: agent.name, phase: "complete", newCount: heads.length });
|
|
3619
4042
|
const filtered = filterSessions(heads, options);
|
|
@@ -3669,12 +4092,16 @@ export {
|
|
|
3669
4092
|
resolveSessionTitle,
|
|
3670
4093
|
perf,
|
|
3671
4094
|
openDbReadOnly,
|
|
4095
|
+
openDb,
|
|
3672
4096
|
isSqliteAvailable,
|
|
3673
4097
|
loadCachedSessions,
|
|
3674
4098
|
saveCachedSessions,
|
|
3675
4099
|
clearCache,
|
|
3676
4100
|
getCacheInfo,
|
|
4101
|
+
syncSessionSearchIndex,
|
|
4102
|
+
searchSessions,
|
|
4103
|
+
filterSessions,
|
|
3677
4104
|
scanSessions,
|
|
3678
4105
|
scanSessionsAsync
|
|
3679
4106
|
};
|
|
3680
|
-
//# sourceMappingURL=chunk-
|
|
4107
|
+
//# sourceMappingURL=chunk-UQI7CTEK.js.map
|