codesesh 0.1.5 → 0.2.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 +12 -0
- package/dist/{chunk-FG2FZIU5.js → chunk-2UNXB2D3.js} +185 -125
- package/dist/chunk-2UNXB2D3.js.map +1 -0
- package/dist/{dist-ZF35YB7B.js → dist-6EV6SS6N.js} +4 -2
- package/dist/index.js +603 -40
- package/dist/index.js.map +1 -1
- package/dist/web/assets/index-B4PtJ1VM.css +2 -0
- package/dist/web/assets/{index-Bz2gXVMS.js → index-BzkyjHEA.js} +40 -40
- 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-vSqmWltx.css +0 -2
- /package/dist/{dist-ZF35YB7B.js.map → dist-6EV6SS6N.js.map} +0 -0
package/README.md
CHANGED
|
@@ -19,10 +19,12 @@ Your browser will open at `http://localhost:4321` with all your sessions ready t
|
|
|
19
19
|
## Features
|
|
20
20
|
|
|
21
21
|
- **Unified Timeline** — Browse sessions across all your AI agents in a single, searchable interface
|
|
22
|
+
- **Dashboard & Activity Trends** — See totals, daily activity, agent distribution, and recent sessions
|
|
22
23
|
- **Full Conversation Replay** — Read every message, tool call, and reasoning step exactly as it happened
|
|
23
24
|
- **Cost & Token Visibility** — See exactly how many tokens and dollars each session consumed
|
|
24
25
|
- **Zero Configuration** — Just run it. CodeSesh auto-discovers everything on your filesystem
|
|
25
26
|
- **100% Local & Private** — Nothing leaves your machine. No accounts, no cloud sync, no telemetry
|
|
27
|
+
- **Live Refresh** — Local session changes are picked up automatically while the server is running
|
|
26
28
|
|
|
27
29
|
## Supported Agents
|
|
28
30
|
|
|
@@ -46,6 +48,9 @@ npx codesesh --port 8080
|
|
|
46
48
|
# Only show sessions from the last 3 days
|
|
47
49
|
npx codesesh --days 3
|
|
48
50
|
|
|
51
|
+
# Jump directly to a session
|
|
52
|
+
npx codesesh --session claudecode://3b0e4ead-eba9-43e7-9fac-b30647e189f8
|
|
53
|
+
|
|
49
54
|
# Filter to sessions from current project
|
|
50
55
|
npx codesesh --cwd .
|
|
51
56
|
|
|
@@ -54,6 +59,9 @@ npx codesesh --agent claudecode
|
|
|
54
59
|
|
|
55
60
|
# Output JSON instead of starting server
|
|
56
61
|
npx codesesh --json
|
|
62
|
+
|
|
63
|
+
# Show performance trace logs
|
|
64
|
+
npx codesesh --trace
|
|
57
65
|
```
|
|
58
66
|
|
|
59
67
|
## CLI Options
|
|
@@ -66,8 +74,12 @@ npx codesesh --json
|
|
|
66
74
|
| `--agent` | `-a` | all | Filter to specific agent(s), comma-separated |
|
|
67
75
|
| `--from` | — | — | Sessions created after this date `YYYY-MM-DD` |
|
|
68
76
|
| `--to` | — | — | Sessions created before this date `YYYY-MM-DD` |
|
|
77
|
+
| `--session` | `-s` | — | Directly open a session (`agent://session-id`) |
|
|
69
78
|
| `--json` | `-j` | `false` | Output JSON and exit (no server) |
|
|
70
79
|
| `--no-open` | — | `false` | Don't auto-open the browser |
|
|
80
|
+
| `--trace` | — | `false` | Print performance trace logs |
|
|
81
|
+
| `--cache` | — | `true` | Use cached scan results when available |
|
|
82
|
+
| `--clear-cache` | — | `false` | Clear scan cache before starting |
|
|
71
83
|
|
|
72
84
|
## Requirements
|
|
73
85
|
|
|
@@ -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";
|
|
@@ -13,7 +13,7 @@ import { join as join3 } from "path";
|
|
|
13
13
|
import { createRequire } from "module";
|
|
14
14
|
import { createHash } from "crypto";
|
|
15
15
|
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";
|
|
16
|
+
import { join as join4, basename as basename3, dirname as dirname2 } from "path";
|
|
17
17
|
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
18
18
|
import { join as join5, basename as basename4 } from "path";
|
|
19
19
|
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync5 } from "fs";
|
|
@@ -205,6 +205,7 @@ var PerfTracer = class {
|
|
|
205
205
|
}
|
|
206
206
|
};
|
|
207
207
|
var perf = new PerfTracer();
|
|
208
|
+
var RECENT_SESSION_REVALIDATION_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
208
209
|
function parseTimestampMs(data) {
|
|
209
210
|
const raw = String(data["timestamp"] ?? "").trim();
|
|
210
211
|
if (!raw) return 0;
|
|
@@ -348,17 +349,30 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
348
349
|
if (!this.basePath) {
|
|
349
350
|
return { hasChanges: false, timestamp: Date.now() };
|
|
350
351
|
}
|
|
351
|
-
const
|
|
352
|
-
|
|
352
|
+
const now = Date.now();
|
|
353
|
+
const changedIds = /* @__PURE__ */ new Set();
|
|
354
|
+
const recentSessions = cachedSessions.filter(
|
|
355
|
+
(session) => now - session.time_created <= RECENT_SESSION_REVALIDATION_WINDOW_MS
|
|
356
|
+
);
|
|
357
|
+
for (const session of recentSessions) {
|
|
358
|
+
changedIds.add(session.id);
|
|
353
359
|
const meta = this.sessionMetaMap.get(session.id);
|
|
354
360
|
if (!meta) continue;
|
|
361
|
+
delete this.sessionsIndexCache[basename2(dirname(meta.sourcePath))];
|
|
362
|
+
}
|
|
363
|
+
for (const session of cachedSessions) {
|
|
364
|
+
const meta = this.sessionMetaMap.get(session.id);
|
|
365
|
+
if (!meta) {
|
|
366
|
+
changedIds.add(session.id);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
355
369
|
try {
|
|
356
370
|
const stat = statSync(meta.sourcePath);
|
|
357
371
|
if (stat.mtimeMs > sinceTimestamp) {
|
|
358
|
-
changedIds.
|
|
372
|
+
changedIds.add(session.id);
|
|
359
373
|
}
|
|
360
374
|
} catch {
|
|
361
|
-
changedIds.
|
|
375
|
+
changedIds.add(session.id);
|
|
362
376
|
}
|
|
363
377
|
}
|
|
364
378
|
try {
|
|
@@ -368,14 +382,14 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
368
382
|
}
|
|
369
383
|
const hasNewFiles = totalFiles > cachedSessions.length;
|
|
370
384
|
return {
|
|
371
|
-
hasChanges: changedIds.
|
|
372
|
-
changedIds,
|
|
385
|
+
hasChanges: changedIds.size > 0 || hasNewFiles,
|
|
386
|
+
changedIds: Array.from(changedIds),
|
|
373
387
|
timestamp: Date.now()
|
|
374
388
|
};
|
|
375
389
|
} catch {
|
|
376
390
|
return {
|
|
377
|
-
hasChanges: changedIds.
|
|
378
|
-
changedIds,
|
|
391
|
+
hasChanges: changedIds.size > 0,
|
|
392
|
+
changedIds: Array.from(changedIds),
|
|
379
393
|
timestamp: Date.now()
|
|
380
394
|
};
|
|
381
395
|
}
|
|
@@ -1024,6 +1038,7 @@ var OpenCodeAgent = class extends BaseAgent {
|
|
|
1024
1038
|
const timeUpdated = Number(row.time_updated ?? timeCreated);
|
|
1025
1039
|
const slug = `opencode/${id}`;
|
|
1026
1040
|
const directory = String(row.directory ?? "");
|
|
1041
|
+
const stats = hasMessageTable ? this.readSessionStats(db, id) : null;
|
|
1027
1042
|
heads.push({
|
|
1028
1043
|
id,
|
|
1029
1044
|
slug,
|
|
@@ -1032,10 +1047,10 @@ var OpenCodeAgent = class extends BaseAgent {
|
|
|
1032
1047
|
time_created: timeCreated,
|
|
1033
1048
|
time_updated: timeUpdated,
|
|
1034
1049
|
stats: {
|
|
1035
|
-
message_count: Number(row.message_count ?? 0),
|
|
1036
|
-
total_input_tokens: 0,
|
|
1037
|
-
total_output_tokens: 0,
|
|
1038
|
-
total_cost: 0
|
|
1050
|
+
message_count: stats?.message_count ?? Number(row.message_count ?? 0),
|
|
1051
|
+
total_input_tokens: stats?.total_input_tokens ?? 0,
|
|
1052
|
+
total_output_tokens: stats?.total_output_tokens ?? 0,
|
|
1053
|
+
total_cost: stats?.total_cost ?? 0
|
|
1039
1054
|
}
|
|
1040
1055
|
});
|
|
1041
1056
|
if (this.dbPath) {
|
|
@@ -1088,6 +1103,30 @@ var OpenCodeAgent = class extends BaseAgent {
|
|
|
1088
1103
|
incrementalScan(_cachedSessions, _changedIds) {
|
|
1089
1104
|
return this.scan();
|
|
1090
1105
|
}
|
|
1106
|
+
readSessionStats(db, sessionId) {
|
|
1107
|
+
try {
|
|
1108
|
+
const rows = db.prepare("SELECT data FROM message WHERE session_id = ? ORDER BY time_created ASC").all(sessionId);
|
|
1109
|
+
let totalCost = 0;
|
|
1110
|
+
let totalInputTokens = 0;
|
|
1111
|
+
let totalOutputTokens = 0;
|
|
1112
|
+
for (const row of rows) {
|
|
1113
|
+
const msgData = JSON.parse(String(row.data ?? "{}"));
|
|
1114
|
+
const cost = Number(msgData.cost ?? 0);
|
|
1115
|
+
const tokens = msgData.tokens;
|
|
1116
|
+
totalCost += cost;
|
|
1117
|
+
totalInputTokens += Number(tokens?.input ?? 0);
|
|
1118
|
+
totalOutputTokens += Number(tokens?.output ?? 0);
|
|
1119
|
+
}
|
|
1120
|
+
return {
|
|
1121
|
+
message_count: rows.length,
|
|
1122
|
+
total_input_tokens: totalInputTokens,
|
|
1123
|
+
total_output_tokens: totalOutputTokens,
|
|
1124
|
+
total_cost: totalCost
|
|
1125
|
+
};
|
|
1126
|
+
} catch {
|
|
1127
|
+
return null;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1091
1130
|
getSessionData(sessionId) {
|
|
1092
1131
|
if (!this.dbPath) {
|
|
1093
1132
|
this.dbPath = this.findDbPath();
|
|
@@ -1301,7 +1340,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1301
1340
|
parseSessionDir(sessionDir) {
|
|
1302
1341
|
try {
|
|
1303
1342
|
const sessionId = basename3(sessionDir);
|
|
1304
|
-
const projectHash = basename3(
|
|
1343
|
+
const projectHash = basename3(dirname2(sessionDir));
|
|
1305
1344
|
const contextFile = join4(sessionDir, "context.jsonl");
|
|
1306
1345
|
const wireFile = join4(sessionDir, "wire.jsonl");
|
|
1307
1346
|
if (!existsSync4(contextFile) && !existsSync4(wireFile)) return null;
|
|
@@ -1351,6 +1390,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1351
1390
|
perf.end(parseMarker);
|
|
1352
1391
|
if (!meta) continue;
|
|
1353
1392
|
this.sessionMetaMap.set(meta.id, meta);
|
|
1393
|
+
const stats = this.extractStats(meta.sourcePath);
|
|
1354
1394
|
heads.push({
|
|
1355
1395
|
id: meta.id,
|
|
1356
1396
|
slug: `kimi/${meta.id}`,
|
|
@@ -1358,12 +1398,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1358
1398
|
directory: meta.cwd,
|
|
1359
1399
|
time_created: meta.createdAt,
|
|
1360
1400
|
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
|
-
}
|
|
1401
|
+
stats
|
|
1367
1402
|
});
|
|
1368
1403
|
} catch {
|
|
1369
1404
|
}
|
|
@@ -1421,6 +1456,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1421
1456
|
if (!meta) continue;
|
|
1422
1457
|
if (changedIds.includes(meta.id)) {
|
|
1423
1458
|
this.sessionMetaMap.set(meta.id, meta);
|
|
1459
|
+
const stats = this.extractStats(meta.sourcePath);
|
|
1424
1460
|
sessionMap.set(meta.id, {
|
|
1425
1461
|
id: meta.id,
|
|
1426
1462
|
slug: `kimi/${meta.id}`,
|
|
@@ -1428,12 +1464,7 @@ var KimiAgent = class extends BaseAgent {
|
|
|
1428
1464
|
directory: meta.cwd,
|
|
1429
1465
|
time_created: meta.createdAt,
|
|
1430
1466
|
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
|
-
}
|
|
1467
|
+
stats
|
|
1437
1468
|
});
|
|
1438
1469
|
}
|
|
1439
1470
|
} catch {
|
|
@@ -1861,6 +1892,7 @@ var CODEX_TOOL_TITLE_MAP = {
|
|
|
1861
1892
|
spawn_agent: "subagent",
|
|
1862
1893
|
subagent: "subagent"
|
|
1863
1894
|
};
|
|
1895
|
+
var RECENT_SESSION_REVALIDATION_WINDOW_MS2 = 24 * 60 * 60 * 1e3;
|
|
1864
1896
|
function extractSessionId(filename) {
|
|
1865
1897
|
const stem = basename4(filename, ".jsonl");
|
|
1866
1898
|
const parts = stem.split("-");
|
|
@@ -1878,6 +1910,9 @@ function parseTimestampMs2(data) {
|
|
|
1878
1910
|
return 0;
|
|
1879
1911
|
}
|
|
1880
1912
|
}
|
|
1913
|
+
function extractModelName(raw) {
|
|
1914
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
1915
|
+
}
|
|
1881
1916
|
function normalizeTitleText3(text) {
|
|
1882
1917
|
const line = text.split("\n").find((l) => l.trim());
|
|
1883
1918
|
return line?.trim().slice(0, 80) || "";
|
|
@@ -2051,34 +2086,43 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2051
2086
|
if (!this.basePath) {
|
|
2052
2087
|
return { hasChanges: false, timestamp: Date.now() };
|
|
2053
2088
|
}
|
|
2054
|
-
const
|
|
2089
|
+
const now = Date.now();
|
|
2090
|
+
const changedIds = /* @__PURE__ */ new Set();
|
|
2091
|
+
const currentFiles = this.listRolloutFiles();
|
|
2092
|
+
const currentIds = new Set(currentFiles.map((file) => extractSessionId(file)));
|
|
2093
|
+
const cachedIds = new Set(cachedSessions.map((session) => session.id));
|
|
2094
|
+
const recentIds = cachedSessions.filter((session) => now - session.time_created <= RECENT_SESSION_REVALIDATION_WINDOW_MS2).map((session) => session.id);
|
|
2095
|
+
for (const sessionId of recentIds) {
|
|
2096
|
+
changedIds.add(sessionId);
|
|
2097
|
+
}
|
|
2055
2098
|
for (const session of cachedSessions) {
|
|
2056
2099
|
const meta = this.sessionMetaMap.get(session.id);
|
|
2057
|
-
if (!
|
|
2100
|
+
if (!currentIds.has(session.id)) {
|
|
2101
|
+
changedIds.add(session.id);
|
|
2102
|
+
continue;
|
|
2103
|
+
}
|
|
2104
|
+
if (!meta) {
|
|
2105
|
+
changedIds.add(session.id);
|
|
2106
|
+
continue;
|
|
2107
|
+
}
|
|
2058
2108
|
try {
|
|
2059
2109
|
const stat = statSync4(meta.sourcePath);
|
|
2060
2110
|
if (stat.mtimeMs > sinceTimestamp) {
|
|
2061
|
-
changedIds.
|
|
2111
|
+
changedIds.add(session.id);
|
|
2062
2112
|
}
|
|
2063
2113
|
} catch {
|
|
2064
|
-
changedIds.
|
|
2114
|
+
changedIds.add(session.id);
|
|
2065
2115
|
}
|
|
2066
2116
|
}
|
|
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
|
-
};
|
|
2117
|
+
const hasAddedSessions = currentFiles.some((file) => !cachedIds.has(extractSessionId(file)));
|
|
2118
|
+
if (recentIds.length > 0) {
|
|
2119
|
+
this.sessionIndexCache.clear();
|
|
2081
2120
|
}
|
|
2121
|
+
return {
|
|
2122
|
+
hasChanges: changedIds.size > 0 || hasAddedSessions,
|
|
2123
|
+
changedIds: Array.from(changedIds),
|
|
2124
|
+
timestamp: Date.now()
|
|
2125
|
+
};
|
|
2082
2126
|
}
|
|
2083
2127
|
/**
|
|
2084
2128
|
* 增量扫描
|
|
@@ -2086,10 +2130,19 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2086
2130
|
incrementalScan(cachedSessions, changedIds) {
|
|
2087
2131
|
if (!this.basePath) return cachedSessions;
|
|
2088
2132
|
const sessionMap = new Map(cachedSessions.map((s) => [s.id, s]));
|
|
2089
|
-
|
|
2133
|
+
const changedSet = new Set(changedIds);
|
|
2134
|
+
const currentFiles = this.listRolloutFiles();
|
|
2135
|
+
const currentIds = new Set(currentFiles.map((file) => extractSessionId(file)));
|
|
2136
|
+
for (const session of cachedSessions) {
|
|
2137
|
+
if (!currentIds.has(session.id)) {
|
|
2138
|
+
sessionMap.delete(session.id);
|
|
2139
|
+
this.sessionMetaMap.delete(session.id);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
for (const file of currentFiles) {
|
|
2090
2143
|
try {
|
|
2091
2144
|
const sessionId = extractSessionId(file);
|
|
2092
|
-
if (
|
|
2145
|
+
if (changedSet.has(sessionId)) {
|
|
2093
2146
|
const head = this.parseSessionHead(file);
|
|
2094
2147
|
if (head) {
|
|
2095
2148
|
sessionMap.set(head.id, head);
|
|
@@ -2108,7 +2161,7 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2108
2161
|
} catch {
|
|
2109
2162
|
}
|
|
2110
2163
|
}
|
|
2111
|
-
for (const file of
|
|
2164
|
+
for (const file of currentFiles) {
|
|
2112
2165
|
try {
|
|
2113
2166
|
const sessionId = extractSessionId(file);
|
|
2114
2167
|
if (!sessionMap.has(sessionId)) {
|
|
@@ -2144,13 +2197,18 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2144
2197
|
let currentAssistantIndex = null;
|
|
2145
2198
|
let latestAssistantTextIndex = null;
|
|
2146
2199
|
let pendingPlan = null;
|
|
2200
|
+
let activeModel = meta.model;
|
|
2147
2201
|
let prevCumulativeTotal = 0;
|
|
2148
2202
|
let prevInput = 0;
|
|
2149
|
-
let prevCached = 0;
|
|
2150
2203
|
let prevOutput = 0;
|
|
2151
2204
|
let prevReasoning = 0;
|
|
2152
2205
|
for (const record of parseJsonlLines(content)) {
|
|
2153
2206
|
try {
|
|
2207
|
+
const recordType = String(record["type"] ?? "");
|
|
2208
|
+
if (recordType === "turn_context") {
|
|
2209
|
+
const payload = record["payload"] ?? {};
|
|
2210
|
+
activeModel = extractModelName(payload["model"]) ?? activeModel;
|
|
2211
|
+
}
|
|
2154
2212
|
const result = this.convertRecord(
|
|
2155
2213
|
record,
|
|
2156
2214
|
messages,
|
|
@@ -2163,7 +2221,12 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2163
2221
|
currentAssistantIndex = result.currentAssistantIndex;
|
|
2164
2222
|
latestAssistantTextIndex = result.latestAssistantTextIndex;
|
|
2165
2223
|
pendingPlan = result.pendingPlan;
|
|
2166
|
-
|
|
2224
|
+
if (currentAssistantIndex !== null && activeModel) {
|
|
2225
|
+
const message = messages[currentAssistantIndex];
|
|
2226
|
+
if (message?.role === "assistant" && !message.model) {
|
|
2227
|
+
message.model = activeModel;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2167
2230
|
if (recordType === "event_msg") {
|
|
2168
2231
|
const payload = record["payload"] ?? {};
|
|
2169
2232
|
if (String(payload["type"] ?? "") === "token_count") {
|
|
@@ -2175,33 +2238,29 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2175
2238
|
prevCumulativeTotal = cumulativeTotal;
|
|
2176
2239
|
const lastUsage = info?.["last_token_usage"];
|
|
2177
2240
|
let inputTokens = 0;
|
|
2178
|
-
let cachedInputTokens = 0;
|
|
2179
2241
|
let outputTokens = 0;
|
|
2180
2242
|
let reasoningTokens = 0;
|
|
2181
2243
|
if (lastUsage) {
|
|
2182
2244
|
inputTokens = Number(lastUsage["input_tokens"] ?? 0);
|
|
2183
|
-
cachedInputTokens = Number(lastUsage["cached_input_tokens"] ?? 0);
|
|
2184
2245
|
outputTokens = Number(lastUsage["output_tokens"] ?? 0);
|
|
2185
2246
|
reasoningTokens = Number(lastUsage["reasoning_output_tokens"] ?? 0);
|
|
2186
2247
|
} else if (cumulativeTotal > 0 && totalUsage) {
|
|
2187
2248
|
inputTokens = Number(totalUsage["input_tokens"] ?? 0) - prevInput;
|
|
2188
|
-
cachedInputTokens = Number(totalUsage["cached_input_tokens"] ?? 0) - prevCached;
|
|
2189
2249
|
outputTokens = Number(totalUsage["output_tokens"] ?? 0) - prevOutput;
|
|
2190
2250
|
reasoningTokens = Number(totalUsage["reasoning_output_tokens"] ?? 0) - prevReasoning;
|
|
2191
2251
|
prevInput = Number(totalUsage["input_tokens"] ?? 0);
|
|
2192
|
-
prevCached = Number(totalUsage["cached_input_tokens"] ?? 0);
|
|
2193
2252
|
prevOutput = Number(totalUsage["output_tokens"] ?? 0);
|
|
2194
2253
|
prevReasoning = Number(totalUsage["reasoning_output_tokens"] ?? 0);
|
|
2195
2254
|
}
|
|
2196
|
-
const
|
|
2197
|
-
if (
|
|
2198
|
-
totalInputTokens +=
|
|
2255
|
+
const totalInput = Math.max(0, inputTokens);
|
|
2256
|
+
if (totalInput || outputTokens || reasoningTokens) {
|
|
2257
|
+
totalInputTokens += totalInput;
|
|
2199
2258
|
totalOutputTokens += outputTokens + reasoningTokens;
|
|
2200
2259
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
2201
2260
|
const msg = messages[i];
|
|
2202
2261
|
if (msg.role === "assistant" && !msg.tokens) {
|
|
2203
2262
|
msg.tokens = {
|
|
2204
|
-
input:
|
|
2263
|
+
input: totalInput,
|
|
2205
2264
|
output: outputTokens + reasoningTokens
|
|
2206
2265
|
};
|
|
2207
2266
|
break;
|
|
@@ -2277,6 +2336,7 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2277
2336
|
}
|
|
2278
2337
|
}
|
|
2279
2338
|
getTitleForSession(sessionId) {
|
|
2339
|
+
this.loadSessionIndex();
|
|
2280
2340
|
return this.sessionIndexCache.get(sessionId) ?? null;
|
|
2281
2341
|
}
|
|
2282
2342
|
// ---- Session head parsing ----
|
|
@@ -2292,7 +2352,7 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2292
2352
|
return null;
|
|
2293
2353
|
}
|
|
2294
2354
|
const payload = firstRecord["payload"] ?? {};
|
|
2295
|
-
const createdAt = parseTimestampMs2(payload) || statSync4(filePath).mtimeMs;
|
|
2355
|
+
const createdAt = parseTimestampMs2(firstRecord) || parseTimestampMs2(payload) || statSync4(filePath).mtimeMs;
|
|
2296
2356
|
const indexTitle = this.getTitleForSession(sessionId);
|
|
2297
2357
|
const messageTitle = this.extractTitleFromLines(lines);
|
|
2298
2358
|
const directoryTitle = basenameTitle(payload["cwd"] ? String(payload["cwd"]) : null);
|
|
@@ -2304,7 +2364,6 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2304
2364
|
let totalOutputTokens = 0;
|
|
2305
2365
|
let scanPrevCumulativeTotal = 0;
|
|
2306
2366
|
let scanPrevInput = 0;
|
|
2307
|
-
let scanPrevCached = 0;
|
|
2308
2367
|
let scanPrevOutput = 0;
|
|
2309
2368
|
let scanPrevReasoning = 0;
|
|
2310
2369
|
const COUNTED_TYPES = /* @__PURE__ */ new Set(["message", "function_call", "function_call_output"]);
|
|
@@ -2312,10 +2371,13 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2312
2371
|
try {
|
|
2313
2372
|
const data = JSON.parse(line);
|
|
2314
2373
|
const recordType = String(data["type"] ?? "");
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2374
|
+
const recordTs = parseTimestampMs2(data) || parseTimestampMs2(data["payload"] ?? {});
|
|
2375
|
+
if (recordTs > updatedAt) updatedAt = recordTs;
|
|
2376
|
+
if (recordType === "session_meta" || recordType === "turn_context") {
|
|
2377
|
+
const payload2 = data["payload"] ?? {};
|
|
2378
|
+
if (!model) {
|
|
2379
|
+
model = extractModelName(payload2["model"]);
|
|
2380
|
+
}
|
|
2319
2381
|
continue;
|
|
2320
2382
|
}
|
|
2321
2383
|
if (recordType === "response_item") {
|
|
@@ -2340,26 +2402,22 @@ var CodexAgent = class extends BaseAgent {
|
|
|
2340
2402
|
scanPrevCumulativeTotal = cumulativeTotal;
|
|
2341
2403
|
const lastUsage = info?.["last_token_usage"];
|
|
2342
2404
|
let inputTokens = 0;
|
|
2343
|
-
let cachedInputTokens = 0;
|
|
2344
2405
|
let outputTokens = 0;
|
|
2345
2406
|
let reasoningTokens = 0;
|
|
2346
2407
|
if (lastUsage) {
|
|
2347
2408
|
inputTokens = Number(lastUsage["input_tokens"] ?? 0);
|
|
2348
|
-
cachedInputTokens = Number(lastUsage["cached_input_tokens"] ?? 0);
|
|
2349
2409
|
outputTokens = Number(lastUsage["output_tokens"] ?? 0);
|
|
2350
2410
|
reasoningTokens = Number(lastUsage["reasoning_output_tokens"] ?? 0);
|
|
2351
2411
|
} else if (cumulativeTotal > 0 && totalUsage) {
|
|
2352
2412
|
inputTokens = Number(totalUsage["input_tokens"] ?? 0) - scanPrevInput;
|
|
2353
|
-
cachedInputTokens = Number(totalUsage["cached_input_tokens"] ?? 0) - scanPrevCached;
|
|
2354
2413
|
outputTokens = Number(totalUsage["output_tokens"] ?? 0) - scanPrevOutput;
|
|
2355
2414
|
reasoningTokens = Number(totalUsage["reasoning_output_tokens"] ?? 0) - scanPrevReasoning;
|
|
2356
2415
|
scanPrevInput = Number(totalUsage["input_tokens"] ?? 0);
|
|
2357
|
-
scanPrevCached = Number(totalUsage["cached_input_tokens"] ?? 0);
|
|
2358
2416
|
scanPrevOutput = Number(totalUsage["output_tokens"] ?? 0);
|
|
2359
2417
|
scanPrevReasoning = Number(totalUsage["reasoning_output_tokens"] ?? 0);
|
|
2360
2418
|
}
|
|
2361
|
-
const
|
|
2362
|
-
totalInputTokens +=
|
|
2419
|
+
const totalInput = Math.max(0, inputTokens);
|
|
2420
|
+
totalInputTokens += totalInput;
|
|
2363
2421
|
totalOutputTokens += outputTokens + reasoningTokens;
|
|
2364
2422
|
}
|
|
2365
2423
|
}
|
|
@@ -3002,7 +3060,12 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3002
3060
|
const title = this.extractTitle(composer);
|
|
3003
3061
|
const createdAt = composer.createdAt ?? 0;
|
|
3004
3062
|
const updatedAt = composer.updatedAt ?? createdAt;
|
|
3005
|
-
const messages = this.loadMessagesFromBubbles(
|
|
3063
|
+
const messages = this.loadMessagesFromBubbles(
|
|
3064
|
+
db,
|
|
3065
|
+
composerId,
|
|
3066
|
+
sessionId,
|
|
3067
|
+
composer.modelConfig?.modelName ?? composer.model ?? null
|
|
3068
|
+
);
|
|
3006
3069
|
const hasSubagents = Array.isArray(composer.subagentInfos) && composer.subagentInfos.length > 0;
|
|
3007
3070
|
if (messages.length === 0 && !hasSubagents) {
|
|
3008
3071
|
continue;
|
|
@@ -3114,7 +3177,12 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3114
3177
|
const title = this.extractTitle(composer);
|
|
3115
3178
|
const createdAt = composer.createdAt ?? 0;
|
|
3116
3179
|
const updatedAt = composer.updatedAt ?? createdAt;
|
|
3117
|
-
const messages = this.loadMessagesFromBubbles(
|
|
3180
|
+
const messages = this.loadMessagesFromBubbles(
|
|
3181
|
+
db,
|
|
3182
|
+
composerId,
|
|
3183
|
+
resolvedSessionId,
|
|
3184
|
+
composer.modelConfig?.modelName ?? composer.model ?? null
|
|
3185
|
+
);
|
|
3118
3186
|
let totalInputTokens = 0;
|
|
3119
3187
|
let totalOutputTokens = 0;
|
|
3120
3188
|
for (const msg of messages) {
|
|
@@ -3222,11 +3290,11 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3222
3290
|
}
|
|
3223
3291
|
}
|
|
3224
3292
|
/** Load messages from bubbles (like agent-dump) */
|
|
3225
|
-
loadMessagesFromBubbles(db, composerId, _sessionId) {
|
|
3293
|
+
loadMessagesFromBubbles(db, composerId, _sessionId, initialModelName) {
|
|
3226
3294
|
const messages = [];
|
|
3227
3295
|
try {
|
|
3228
3296
|
const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ORDER BY rowid ASC").all(`bubbleId:${composerId}:%`);
|
|
3229
|
-
let activeModelName =
|
|
3297
|
+
let activeModelName = initialModelName;
|
|
3230
3298
|
let messageIndex = 0;
|
|
3231
3299
|
for (const row of rows) {
|
|
3232
3300
|
try {
|
|
@@ -3241,7 +3309,7 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3241
3309
|
} else if (bubble.timestamp) {
|
|
3242
3310
|
timestampMs = bubble.timestamp;
|
|
3243
3311
|
}
|
|
3244
|
-
if (
|
|
3312
|
+
if (bubble.modelInfo?.modelName) {
|
|
3245
3313
|
activeModelName = bubble.modelInfo.modelName;
|
|
3246
3314
|
}
|
|
3247
3315
|
const inputTokens = bubble.tokenCount?.inputTokens ?? 0;
|
|
@@ -3265,7 +3333,7 @@ var CursorAgent = class extends BaseAgent {
|
|
|
3265
3333
|
time_created: timestampMs,
|
|
3266
3334
|
time_completed: null,
|
|
3267
3335
|
mode: role === "assistant" && parts.some((p) => p.type === "tool") ? "tool" : null,
|
|
3268
|
-
model: activeModelName,
|
|
3336
|
+
model: bubble.modelInfo?.modelName ?? activeModelName,
|
|
3269
3337
|
provider: null,
|
|
3270
3338
|
tokens: { input: inputTokens, output: outputTokens },
|
|
3271
3339
|
cost: 0,
|
|
@@ -3531,9 +3599,18 @@ function filterSessions(sessions, options) {
|
|
|
3531
3599
|
}
|
|
3532
3600
|
return result;
|
|
3533
3601
|
}
|
|
3602
|
+
function buildAgentCacheMeta(agent) {
|
|
3603
|
+
const metaMap = agent.getSessionMetaMap?.();
|
|
3604
|
+
const meta = {};
|
|
3605
|
+
if (!metaMap) return meta;
|
|
3606
|
+
for (const [id, data] of metaMap.entries()) {
|
|
3607
|
+
meta[id] = { id, ...data };
|
|
3608
|
+
}
|
|
3609
|
+
return meta;
|
|
3610
|
+
}
|
|
3534
3611
|
async function scanAgentSmart(agent, options, onProgress) {
|
|
3535
3612
|
const useCache = options.useCache ?? true;
|
|
3536
|
-
const
|
|
3613
|
+
const canValidateCache = Boolean(agent.checkForChanges && agent.incrementalScan);
|
|
3537
3614
|
if (useCache) {
|
|
3538
3615
|
const cached = loadCachedSessions(agent.name);
|
|
3539
3616
|
if (cached !== null) {
|
|
@@ -3544,16 +3621,39 @@ async function scanAgentSmart(agent, options, onProgress) {
|
|
|
3544
3621
|
}
|
|
3545
3622
|
agent.setSessionMetaMap(metaMap);
|
|
3546
3623
|
}
|
|
3547
|
-
agent.isAvailable();
|
|
3624
|
+
const isAvail = agent.isAvailable();
|
|
3625
|
+
if (!isAvail) {
|
|
3626
|
+
return null;
|
|
3627
|
+
}
|
|
3548
3628
|
onProgress?.({
|
|
3549
3629
|
agent: agent.name,
|
|
3550
3630
|
phase: "cache",
|
|
3551
3631
|
cachedCount: cached.sessions.length
|
|
3552
3632
|
});
|
|
3553
|
-
if (
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3633
|
+
if (canValidateCache) {
|
|
3634
|
+
onProgress?.({ agent: agent.name, phase: "checking" });
|
|
3635
|
+
const checkResult = await Promise.resolve(
|
|
3636
|
+
agent.checkForChanges(cached.timestamp, cached.sessions)
|
|
3637
|
+
);
|
|
3638
|
+
if (checkResult.hasChanges) {
|
|
3639
|
+
onProgress?.({
|
|
3640
|
+
agent: agent.name,
|
|
3641
|
+
phase: "incremental",
|
|
3642
|
+
changedCount: checkResult.changedIds?.length
|
|
3643
|
+
});
|
|
3644
|
+
const updatedSessions = await Promise.resolve(
|
|
3645
|
+
agent.incrementalScan(cached.sessions, checkResult.changedIds || [])
|
|
3646
|
+
);
|
|
3647
|
+
saveCachedSessions(agent.name, updatedSessions, buildAgentCacheMeta(agent));
|
|
3648
|
+
onProgress?.({
|
|
3649
|
+
agent: agent.name,
|
|
3650
|
+
phase: "complete",
|
|
3651
|
+
newCount: updatedSessions.length
|
|
3652
|
+
});
|
|
3653
|
+
const filtered2 = filterSessions(updatedSessions, options);
|
|
3654
|
+
return { agent, heads: filtered2, fromCache: true, refreshed: true };
|
|
3655
|
+
}
|
|
3656
|
+
onProgress?.({ agent: agent.name, phase: "complete", newCount: cached.sessions.length });
|
|
3557
3657
|
}
|
|
3558
3658
|
const filtered = filterSessions(cached.sessions, options);
|
|
3559
3659
|
return { agent, heads: filtered, fromCache: true };
|
|
@@ -3561,41 +3661,6 @@ async function scanAgentSmart(agent, options, onProgress) {
|
|
|
3561
3661
|
}
|
|
3562
3662
|
return scanAgentFull(agent, options, onProgress);
|
|
3563
3663
|
}
|
|
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
3664
|
async function scanAgentFull(agent, options, onProgress) {
|
|
3600
3665
|
const availMarker = perf.start(`agent:${agent.name}:isAvailable`);
|
|
3601
3666
|
const isAvail = agent.isAvailable();
|
|
@@ -3607,13 +3672,7 @@ async function scanAgentFull(agent, options, onProgress) {
|
|
|
3607
3672
|
const scanMarker = perf.start(`agent:${agent.name}:scan`);
|
|
3608
3673
|
const heads = agent.scan();
|
|
3609
3674
|
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
|
-
}
|
|
3675
|
+
const meta = buildAgentCacheMeta(agent);
|
|
3617
3676
|
saveCachedSessions(agent.name, heads, meta);
|
|
3618
3677
|
onProgress?.({ agent: agent.name, phase: "complete", newCount: heads.length });
|
|
3619
3678
|
const filtered = filterSessions(heads, options);
|
|
@@ -3674,7 +3733,8 @@ export {
|
|
|
3674
3733
|
saveCachedSessions,
|
|
3675
3734
|
clearCache,
|
|
3676
3735
|
getCacheInfo,
|
|
3736
|
+
filterSessions,
|
|
3677
3737
|
scanSessions,
|
|
3678
3738
|
scanSessionsAsync
|
|
3679
3739
|
};
|
|
3680
|
-
//# sourceMappingURL=chunk-
|
|
3740
|
+
//# sourceMappingURL=chunk-2UNXB2D3.js.map
|