codesesh 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{chunk-XANARSZG.js → chunk-5UOLRSFH.js} +662 -46
- package/dist/chunk-5UOLRSFH.js.map +1 -0
- package/dist/{dist-WJUBVCLN.js → dist-VEIV33FR.js} +2 -2
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +1 -1
- package/dist/search-index-worker.js +1 -1
- package/dist/smart-tag-worker.js +1 -1
- package/dist/web/assets/index-BHmQBGNx.css +2 -0
- package/dist/web/assets/index-CT4gLIAq.js +111 -0
- package/dist/web/assets/vendor-Da5am_Td.js +40 -0
- package/dist/web/icon/agent/pi.svg +20 -0
- package/dist/web/index.html +3 -3
- package/package.json +3 -2
- package/dist/chunk-XANARSZG.js.map +0 -1
- package/dist/web/assets/index-67i6w_Xd.js +0 -108
- package/dist/web/assets/index-BKpG5jDy.css +0 -2
- package/dist/web/assets/vendor-DWjfsTQM.js +0 -40
- /package/dist/{dist-WJUBVCLN.js.map → dist-VEIV33FR.js.map} +0 -0
|
@@ -31,18 +31,20 @@ import {
|
|
|
31
31
|
import { join as join7, basename as basename5 } from "path";
|
|
32
32
|
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
33
33
|
import { join as join8, normalize } from "path";
|
|
34
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
|
|
35
|
+
import { basename as basename6, join as join9 } from "path";
|
|
34
36
|
import { availableParallelism } from "os";
|
|
35
37
|
import { Worker } from "worker_threads";
|
|
36
|
-
import { existsSync as
|
|
38
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
37
39
|
import { spawnSync } from "child_process";
|
|
38
40
|
import * as os from "os";
|
|
39
41
|
import * as path from "path";
|
|
40
42
|
import { resolve, sep } from "path";
|
|
41
|
-
import { existsSync as
|
|
42
|
-
import { join as
|
|
43
|
+
import { existsSync as existsSync11, rmSync, unlinkSync } from "fs";
|
|
44
|
+
import { join as join10 } from "path";
|
|
43
45
|
import { homedir as homedir4 } from "os";
|
|
44
46
|
import { homedir as homedir5, platform as platform2 } from "os";
|
|
45
|
-
import { join as
|
|
47
|
+
import { join as join11 } from "path";
|
|
46
48
|
var registrations = [];
|
|
47
49
|
function registerAgent(reg) {
|
|
48
50
|
registrations.push(reg);
|
|
@@ -112,7 +114,8 @@ function resolveProviderRoots() {
|
|
|
112
114
|
codexRoot: envPath("CODEX_HOME") ?? join(home, ".codex"),
|
|
113
115
|
claudeRoot: envPath("CLAUDE_CONFIG_DIR") ?? join(home, ".claude"),
|
|
114
116
|
kimiRoot: envPath("KIMI_SHARE_DIR") ?? join(home, ".kimi"),
|
|
115
|
-
opencodeRoot: join(getDataHome(), "opencode")
|
|
117
|
+
opencodeRoot: join(getDataHome(), "opencode"),
|
|
118
|
+
piRoot: envPath("PI_HOME") ?? join(home, ".pi")
|
|
116
119
|
};
|
|
117
120
|
}
|
|
118
121
|
function getCursorDataPath() {
|
|
@@ -701,7 +704,7 @@ function withEstimatedSessionCost(stats, model) {
|
|
|
701
704
|
function estimateTokenCost(model, tokens) {
|
|
702
705
|
return estimateCostForTokens(model, tokens)?.cost ?? null;
|
|
703
706
|
}
|
|
704
|
-
var HEAD_INDEX_VERSION = "claudecode-head-
|
|
707
|
+
var HEAD_INDEX_VERSION = "claudecode-head-v2";
|
|
705
708
|
function parseTimestampMs(data) {
|
|
706
709
|
const raw = String(data["timestamp"] ?? "").trim();
|
|
707
710
|
if (!raw) return 0;
|
|
@@ -711,6 +714,25 @@ function parseTimestampMs(data) {
|
|
|
711
714
|
return 0;
|
|
712
715
|
}
|
|
713
716
|
}
|
|
717
|
+
function numericUsage(value) {
|
|
718
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
719
|
+
}
|
|
720
|
+
function extractClaudeUsage(data, msg) {
|
|
721
|
+
const usage = msg["usage"];
|
|
722
|
+
if (!usage || typeof usage !== "object") return null;
|
|
723
|
+
const u = usage;
|
|
724
|
+
const requestId = typeof data["requestId"] === "string" ? data["requestId"].trim() : "";
|
|
725
|
+
const uuid = typeof data["uuid"] === "string" ? data["uuid"].trim() : "";
|
|
726
|
+
const key = requestId || uuid;
|
|
727
|
+
if (!key) return null;
|
|
728
|
+
return {
|
|
729
|
+
key,
|
|
730
|
+
input: numericUsage(u["input_tokens"]),
|
|
731
|
+
output: numericUsage(u["output_tokens"]),
|
|
732
|
+
cacheRead: numericUsage(u["cache_read_input_tokens"]),
|
|
733
|
+
cacheCreate: numericUsage(u["cache_creation_input_tokens"])
|
|
734
|
+
};
|
|
735
|
+
}
|
|
714
736
|
var ClaudeCodeAgent = class extends BaseAgent {
|
|
715
737
|
name = "claudecode";
|
|
716
738
|
displayName = "Claude Code";
|
|
@@ -820,6 +842,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
820
842
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
821
843
|
const ignoredToolCallIds = /* @__PURE__ */ new Set();
|
|
822
844
|
const assistantUuidToToolCalls = /* @__PURE__ */ new Map();
|
|
845
|
+
const countedUsageKeys = /* @__PURE__ */ new Set();
|
|
823
846
|
const assistantState = {
|
|
824
847
|
currentIndex: null,
|
|
825
848
|
latestTextIndex: null
|
|
@@ -837,6 +860,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
837
860
|
pendingToolCalls,
|
|
838
861
|
ignoredToolCallIds,
|
|
839
862
|
assistantUuidToToolCalls,
|
|
863
|
+
countedUsageKeys,
|
|
840
864
|
assistantState
|
|
841
865
|
);
|
|
842
866
|
} catch {
|
|
@@ -1054,6 +1078,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1054
1078
|
let totalCacheCreateTokens = 0;
|
|
1055
1079
|
let totalCost = 0;
|
|
1056
1080
|
const modelUsageMap = {};
|
|
1081
|
+
const countedUsageKeys = /* @__PURE__ */ new Set();
|
|
1057
1082
|
for (const line of lines) {
|
|
1058
1083
|
try {
|
|
1059
1084
|
const data = JSON.parse(line);
|
|
@@ -1074,12 +1099,13 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1074
1099
|
if (typeof m === "string" && m.trim()) model = m.trim();
|
|
1075
1100
|
}
|
|
1076
1101
|
if (role === "assistant") {
|
|
1077
|
-
const usage = msg
|
|
1078
|
-
if (usage &&
|
|
1079
|
-
|
|
1080
|
-
const
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1102
|
+
const usage = extractClaudeUsage(data, msg);
|
|
1103
|
+
if (usage && !countedUsageKeys.has(usage.key)) {
|
|
1104
|
+
countedUsageKeys.add(usage.key);
|
|
1105
|
+
const inputTokens = usage.input;
|
|
1106
|
+
const cacheRead = usage.cacheRead;
|
|
1107
|
+
const cacheCreate = usage.cacheCreate;
|
|
1108
|
+
const outputTokens = usage.output;
|
|
1083
1109
|
totalInputTokens += inputTokens + cacheRead + cacheCreate;
|
|
1084
1110
|
totalOutputTokens += outputTokens;
|
|
1085
1111
|
totalCacheReadTokens += cacheRead;
|
|
@@ -1153,7 +1179,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1153
1179
|
return null;
|
|
1154
1180
|
}
|
|
1155
1181
|
// --- Record conversion ---
|
|
1156
|
-
convertRecord(data, messages, pendingToolCalls, ignoredToolCallIds, assistantUuidToToolCalls, assistantState) {
|
|
1182
|
+
convertRecord(data, messages, pendingToolCalls, ignoredToolCallIds, assistantUuidToToolCalls, countedUsageKeys, assistantState) {
|
|
1157
1183
|
if (data["isMeta"] === true) return;
|
|
1158
1184
|
const msgType = String(data["type"] ?? "");
|
|
1159
1185
|
if (isInternalEventType(msgType)) return;
|
|
@@ -1164,6 +1190,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1164
1190
|
pendingToolCalls,
|
|
1165
1191
|
ignoredToolCallIds,
|
|
1166
1192
|
assistantUuidToToolCalls,
|
|
1193
|
+
countedUsageKeys,
|
|
1167
1194
|
assistantState
|
|
1168
1195
|
);
|
|
1169
1196
|
} else if (msgType === "user") {
|
|
@@ -1179,7 +1206,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1179
1206
|
this.convertToolResultRecord(data, messages, assistantState);
|
|
1180
1207
|
}
|
|
1181
1208
|
}
|
|
1182
|
-
convertAssistantRecord(data, messages, pendingToolCalls, ignoredToolCallIds, assistantUuidToToolCalls, assistantState) {
|
|
1209
|
+
convertAssistantRecord(data, messages, pendingToolCalls, ignoredToolCallIds, assistantUuidToToolCalls, countedUsageKeys, assistantState) {
|
|
1183
1210
|
const msg = data["message"] ?? {};
|
|
1184
1211
|
const timestampMs = parseTimestampMs(data);
|
|
1185
1212
|
const rawContent = msg["content"] ?? [];
|
|
@@ -1197,7 +1224,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1197
1224
|
if (text) {
|
|
1198
1225
|
currentAssistantIndex = this.appendAssistantReasoning(
|
|
1199
1226
|
messages,
|
|
1200
|
-
{ messageId: uuid, msg, timestampMs, text },
|
|
1227
|
+
{ messageId: uuid, data, msg, timestampMs, text, countedUsageKeys },
|
|
1201
1228
|
currentAssistantIndex
|
|
1202
1229
|
);
|
|
1203
1230
|
}
|
|
@@ -1208,7 +1235,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1208
1235
|
if (text) {
|
|
1209
1236
|
currentAssistantIndex = this.appendAssistantText(
|
|
1210
1237
|
messages,
|
|
1211
|
-
{ messageId: uuid, msg, timestampMs, text },
|
|
1238
|
+
{ messageId: uuid, data, msg, timestampMs, text, countedUsageKeys },
|
|
1212
1239
|
currentAssistantIndex
|
|
1213
1240
|
);
|
|
1214
1241
|
latestAssistantTextIndex = currentAssistantIndex;
|
|
@@ -1225,10 +1252,12 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1225
1252
|
const toolPart = this.buildToolPart(part, timestampMs);
|
|
1226
1253
|
const [msgIndex, partIndex] = this.attachToolCallToLatestAssistant(messages, {
|
|
1227
1254
|
messageId: uuid,
|
|
1255
|
+
data,
|
|
1228
1256
|
msg,
|
|
1229
1257
|
timestampMs,
|
|
1230
1258
|
toolPart,
|
|
1231
|
-
latestTextIndex: latestAssistantTextIndex
|
|
1259
|
+
latestTextIndex: latestAssistantTextIndex,
|
|
1260
|
+
countedUsageKeys
|
|
1232
1261
|
});
|
|
1233
1262
|
currentAssistantIndex = msgIndex;
|
|
1234
1263
|
if (toolCallId) {
|
|
@@ -1350,21 +1379,19 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1350
1379
|
time_created: timestampMs
|
|
1351
1380
|
};
|
|
1352
1381
|
}
|
|
1353
|
-
applyAssistantMetadata(message, msg) {
|
|
1382
|
+
applyAssistantMetadata(message, data, msg, countedUsageKeys) {
|
|
1354
1383
|
const model = msg["model"];
|
|
1355
1384
|
if (model && typeof model === "string" && !message.model) {
|
|
1356
1385
|
message.model = model;
|
|
1357
1386
|
}
|
|
1358
|
-
const usage = msg
|
|
1359
|
-
if (usage &&
|
|
1360
|
-
|
|
1361
|
-
const cacheRead = u["cache_read_input_tokens"] ?? 0;
|
|
1362
|
-
const cacheCreate = u["cache_creation_input_tokens"] ?? 0;
|
|
1387
|
+
const usage = extractClaudeUsage(data, msg);
|
|
1388
|
+
if (usage && !message.tokens && !countedUsageKeys.has(usage.key)) {
|
|
1389
|
+
countedUsageKeys.add(usage.key);
|
|
1363
1390
|
message.tokens = {
|
|
1364
|
-
input:
|
|
1365
|
-
output:
|
|
1366
|
-
cache_read: cacheRead,
|
|
1367
|
-
cache_create: cacheCreate
|
|
1391
|
+
input: usage.input + usage.cacheCreate + usage.cacheRead,
|
|
1392
|
+
output: usage.output,
|
|
1393
|
+
cache_read: usage.cacheRead,
|
|
1394
|
+
cache_create: usage.cacheCreate
|
|
1368
1395
|
};
|
|
1369
1396
|
const cost = estimateTokenCost(message.model, message.tokens);
|
|
1370
1397
|
if (cost !== null) {
|
|
@@ -1382,7 +1409,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1382
1409
|
const hasTool = message2.parts.some((p) => p.type === "tool");
|
|
1383
1410
|
if (!hasText && !hasTool) {
|
|
1384
1411
|
this.appendPartIfNew(message2, part);
|
|
1385
|
-
this.applyAssistantMetadata(message2, opts.msg);
|
|
1412
|
+
this.applyAssistantMetadata(message2, opts.data, opts.msg, opts.countedUsageKeys);
|
|
1386
1413
|
return currentIndex;
|
|
1387
1414
|
}
|
|
1388
1415
|
}
|
|
@@ -1393,7 +1420,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1393
1420
|
parts: [part],
|
|
1394
1421
|
agent: "claude"
|
|
1395
1422
|
});
|
|
1396
|
-
this.applyAssistantMetadata(message, opts.msg);
|
|
1423
|
+
this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);
|
|
1397
1424
|
messages.push(message);
|
|
1398
1425
|
return messages.length - 1;
|
|
1399
1426
|
}
|
|
@@ -1404,7 +1431,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1404
1431
|
const hasTool = message2.parts.some((p) => p.type === "tool");
|
|
1405
1432
|
if (!hasTool) {
|
|
1406
1433
|
this.appendPartIfNew(message2, part);
|
|
1407
|
-
this.applyAssistantMetadata(message2, opts.msg);
|
|
1434
|
+
this.applyAssistantMetadata(message2, opts.data, opts.msg, opts.countedUsageKeys);
|
|
1408
1435
|
return currentIndex;
|
|
1409
1436
|
}
|
|
1410
1437
|
}
|
|
@@ -1415,7 +1442,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1415
1442
|
parts: [part],
|
|
1416
1443
|
agent: "claude"
|
|
1417
1444
|
});
|
|
1418
|
-
this.applyAssistantMetadata(message, opts.msg);
|
|
1445
|
+
this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);
|
|
1419
1446
|
messages.push(message);
|
|
1420
1447
|
return messages.length - 1;
|
|
1421
1448
|
}
|
|
@@ -1423,7 +1450,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1423
1450
|
if (opts.latestTextIndex !== null) {
|
|
1424
1451
|
const message2 = messages[opts.latestTextIndex];
|
|
1425
1452
|
message2.parts.push(opts.toolPart);
|
|
1426
|
-
this.applyAssistantMetadata(message2, opts.msg);
|
|
1453
|
+
this.applyAssistantMetadata(message2, opts.data, opts.msg, opts.countedUsageKeys);
|
|
1427
1454
|
return [opts.latestTextIndex, message2.parts.length - 1];
|
|
1428
1455
|
}
|
|
1429
1456
|
const message = this.buildMessage({
|
|
@@ -1434,7 +1461,7 @@ var ClaudeCodeAgent = class extends BaseAgent {
|
|
|
1434
1461
|
agent: "claude",
|
|
1435
1462
|
mode: "tool"
|
|
1436
1463
|
});
|
|
1437
|
-
this.applyAssistantMetadata(message, opts.msg);
|
|
1464
|
+
this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);
|
|
1438
1465
|
messages.push(message);
|
|
1439
1466
|
return [messages.length - 1, 0];
|
|
1440
1467
|
}
|
|
@@ -4664,6 +4691,589 @@ var CursorAgent = class extends BaseAgent {
|
|
|
4664
4691
|
}
|
|
4665
4692
|
}
|
|
4666
4693
|
};
|
|
4694
|
+
var HEAD_INDEX_VERSION3 = "pi-head-v1";
|
|
4695
|
+
var PARSER_VERSION2 = "pi-parser-v1";
|
|
4696
|
+
function parseTimestampMs3(value) {
|
|
4697
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : 0;
|
|
4698
|
+
const text = String(value ?? "").trim();
|
|
4699
|
+
if (!text) return 0;
|
|
4700
|
+
const ts = Date.parse(text);
|
|
4701
|
+
return Number.isNaN(ts) ? 0 : ts;
|
|
4702
|
+
}
|
|
4703
|
+
function extractSessionIdFromFilename(filePath) {
|
|
4704
|
+
const stem = basename6(filePath, ".jsonl");
|
|
4705
|
+
const underscore = stem.indexOf("_");
|
|
4706
|
+
return underscore >= 0 ? stem.slice(underscore + 1) || stem : stem;
|
|
4707
|
+
}
|
|
4708
|
+
function isObject(value) {
|
|
4709
|
+
return typeof value === "object" && value !== null;
|
|
4710
|
+
}
|
|
4711
|
+
function contentToText(content) {
|
|
4712
|
+
if (typeof content === "string") return content;
|
|
4713
|
+
if (!Array.isArray(content)) return "";
|
|
4714
|
+
return content.map((item) => {
|
|
4715
|
+
if (!isObject(item)) return "";
|
|
4716
|
+
if (item["type"] === "text") return String(item["text"] ?? "");
|
|
4717
|
+
if (item["type"] === "image") return "[image]";
|
|
4718
|
+
return "";
|
|
4719
|
+
}).filter(Boolean).join("\n");
|
|
4720
|
+
}
|
|
4721
|
+
function normalizeTextParts(content, timestampMs) {
|
|
4722
|
+
const text = cleanInternalText(contentToText(content));
|
|
4723
|
+
return text ? [{ type: "text", text, time_created: timestampMs }] : [];
|
|
4724
|
+
}
|
|
4725
|
+
function buildMessage(params) {
|
|
4726
|
+
return {
|
|
4727
|
+
id: params.id,
|
|
4728
|
+
role: params.role,
|
|
4729
|
+
agent: params.agent,
|
|
4730
|
+
time_created: params.timestampMs,
|
|
4731
|
+
provider: params.provider,
|
|
4732
|
+
model: params.model,
|
|
4733
|
+
tokens: params.tokens,
|
|
4734
|
+
cost: params.cost,
|
|
4735
|
+
cost_source: params.costSource,
|
|
4736
|
+
parts: params.parts
|
|
4737
|
+
};
|
|
4738
|
+
}
|
|
4739
|
+
function getEntryTimestamp(entry) {
|
|
4740
|
+
return parseTimestampMs3(entry["timestamp"]);
|
|
4741
|
+
}
|
|
4742
|
+
function chooseLeafEntry(entries) {
|
|
4743
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
4744
|
+
if (typeof entries[index]?.["id"] === "string") return entries[index];
|
|
4745
|
+
}
|
|
4746
|
+
return null;
|
|
4747
|
+
}
|
|
4748
|
+
function buildCurrentPathEntries(entries) {
|
|
4749
|
+
const byId = /* @__PURE__ */ new Map();
|
|
4750
|
+
for (const entry of entries) {
|
|
4751
|
+
const id = entry["id"];
|
|
4752
|
+
if (typeof id === "string" && id) byId.set(id, entry);
|
|
4753
|
+
}
|
|
4754
|
+
const leaf = chooseLeafEntry(entries);
|
|
4755
|
+
if (!leaf) return [];
|
|
4756
|
+
const path2 = [];
|
|
4757
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4758
|
+
let current = leaf;
|
|
4759
|
+
while (current) {
|
|
4760
|
+
const id = String(current["id"] ?? "");
|
|
4761
|
+
if (!id || seen.has(id)) break;
|
|
4762
|
+
seen.add(id);
|
|
4763
|
+
path2.push(current);
|
|
4764
|
+
const parentId = current["parentId"];
|
|
4765
|
+
current = typeof parentId === "string" ? byId.get(parentId) : void 0;
|
|
4766
|
+
}
|
|
4767
|
+
return path2.reverse();
|
|
4768
|
+
}
|
|
4769
|
+
var PiAgent = class extends BaseAgent {
|
|
4770
|
+
name = "pi";
|
|
4771
|
+
displayName = "Pi";
|
|
4772
|
+
basePath = null;
|
|
4773
|
+
sessionMetaMap = /* @__PURE__ */ new Map();
|
|
4774
|
+
findBasePath() {
|
|
4775
|
+
const roots = resolveProviderRoots();
|
|
4776
|
+
return firstExisting(join9(roots.piRoot, "agent", "sessions"), "data/pi");
|
|
4777
|
+
}
|
|
4778
|
+
isAvailable() {
|
|
4779
|
+
this.basePath = this.findBasePath();
|
|
4780
|
+
if (!this.basePath) return false;
|
|
4781
|
+
return this.listSessionFiles().length > 0;
|
|
4782
|
+
}
|
|
4783
|
+
scan(options) {
|
|
4784
|
+
if (!this.basePath) return [];
|
|
4785
|
+
const scanMarker = perf.start("pi:scan");
|
|
4786
|
+
const files = this.listSessionFiles(options);
|
|
4787
|
+
options?.onProgress?.({ total: files.length, processed: 0, sessions: 0 });
|
|
4788
|
+
const heads = [];
|
|
4789
|
+
let processed = 0;
|
|
4790
|
+
for (const file of files) {
|
|
4791
|
+
try {
|
|
4792
|
+
const head = getParsedSession(this.parseSessionHeadResult(file));
|
|
4793
|
+
if (head) {
|
|
4794
|
+
heads.push(head);
|
|
4795
|
+
this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file));
|
|
4796
|
+
}
|
|
4797
|
+
} catch {
|
|
4798
|
+
} finally {
|
|
4799
|
+
processed += 1;
|
|
4800
|
+
options?.onProgress?.({ total: files.length, processed, sessions: heads.length });
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
perf.end(scanMarker);
|
|
4804
|
+
return heads;
|
|
4805
|
+
}
|
|
4806
|
+
listSessionSources() {
|
|
4807
|
+
if (!this.basePath) return [];
|
|
4808
|
+
return this.listSessionFiles().map((file) => ({
|
|
4809
|
+
sessionId: extractSessionIdFromFilename(file),
|
|
4810
|
+
sourcePath: file,
|
|
4811
|
+
fingerprint: this.sourceFingerprint(file)
|
|
4812
|
+
}));
|
|
4813
|
+
}
|
|
4814
|
+
scanSessionSource(sourcePath) {
|
|
4815
|
+
const head = getParsedSession(this.parseSessionHeadResult(sourcePath));
|
|
4816
|
+
if (head) {
|
|
4817
|
+
this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, sourcePath));
|
|
4818
|
+
}
|
|
4819
|
+
return head;
|
|
4820
|
+
}
|
|
4821
|
+
getSessionMetaMap() {
|
|
4822
|
+
return this.sessionMetaMap;
|
|
4823
|
+
}
|
|
4824
|
+
setSessionMetaMap(meta) {
|
|
4825
|
+
this.sessionMetaMap = meta;
|
|
4826
|
+
}
|
|
4827
|
+
checkForChanges(_sinceTimestamp, cachedSessions) {
|
|
4828
|
+
if (!this.basePath) return { hasChanges: false, timestamp: Date.now() };
|
|
4829
|
+
const currentFiles = this.listSessionFiles();
|
|
4830
|
+
const currentIds = new Set(currentFiles.map((file) => extractSessionIdFromFilename(file)));
|
|
4831
|
+
const cachedIds = new Set(cachedSessions.map((session) => session.id));
|
|
4832
|
+
const changedIds = /* @__PURE__ */ new Set();
|
|
4833
|
+
for (const session of cachedSessions) {
|
|
4834
|
+
if (!currentIds.has(session.id)) {
|
|
4835
|
+
changedIds.add(session.id);
|
|
4836
|
+
continue;
|
|
4837
|
+
}
|
|
4838
|
+
const meta = this.sessionMetaMap.get(session.id);
|
|
4839
|
+
if (!meta) {
|
|
4840
|
+
changedIds.add(session.id);
|
|
4841
|
+
continue;
|
|
4842
|
+
}
|
|
4843
|
+
try {
|
|
4844
|
+
if (this.hasMetaChanged(meta)) changedIds.add(session.id);
|
|
4845
|
+
} catch {
|
|
4846
|
+
changedIds.add(session.id);
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
const hasAddedSessions = currentFiles.some(
|
|
4850
|
+
(file) => !cachedIds.has(extractSessionIdFromFilename(file))
|
|
4851
|
+
);
|
|
4852
|
+
return {
|
|
4853
|
+
hasChanges: changedIds.size > 0 || hasAddedSessions,
|
|
4854
|
+
changedIds: [...changedIds],
|
|
4855
|
+
timestamp: Date.now()
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
incrementalScan(cachedSessions, changedIds) {
|
|
4859
|
+
if (!this.basePath) return cachedSessions;
|
|
4860
|
+
const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));
|
|
4861
|
+
const changedSet = new Set(changedIds);
|
|
4862
|
+
const currentFiles = this.listSessionFiles();
|
|
4863
|
+
const currentIds = new Set(currentFiles.map((file) => extractSessionIdFromFilename(file)));
|
|
4864
|
+
for (const session of cachedSessions) {
|
|
4865
|
+
if (!currentIds.has(session.id)) {
|
|
4866
|
+
sessionMap.delete(session.id);
|
|
4867
|
+
this.sessionMetaMap.delete(session.id);
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4870
|
+
for (const file of currentFiles) {
|
|
4871
|
+
try {
|
|
4872
|
+
const sessionId = extractSessionIdFromFilename(file);
|
|
4873
|
+
if (!changedSet.has(sessionId) && sessionMap.has(sessionId)) continue;
|
|
4874
|
+
const head = getParsedSession(this.parseSessionHeadResult(file));
|
|
4875
|
+
if (head) {
|
|
4876
|
+
sessionMap.set(head.id, head);
|
|
4877
|
+
this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file));
|
|
4878
|
+
}
|
|
4879
|
+
} catch {
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
return [...sessionMap.values()];
|
|
4883
|
+
}
|
|
4884
|
+
getSessionData(sessionId) {
|
|
4885
|
+
const meta = this.sessionMetaMap.get(sessionId);
|
|
4886
|
+
if (!meta) throw new Error(`Session not found: ${sessionId}`);
|
|
4887
|
+
if (!existsSync9(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);
|
|
4888
|
+
const parsed2 = this.parsePiFile(meta.sourcePath);
|
|
4889
|
+
const state = this.convertEntries(parsed2.pathEntries);
|
|
4890
|
+
const cleanedMessages = cleanParsedMessages(state.messages);
|
|
4891
|
+
return {
|
|
4892
|
+
id: meta.id,
|
|
4893
|
+
title: meta.title,
|
|
4894
|
+
slug: `pi/${meta.id}`,
|
|
4895
|
+
directory: meta.directory,
|
|
4896
|
+
time_created: meta.createdAt,
|
|
4897
|
+
time_updated: meta.updatedAt,
|
|
4898
|
+
stats: {
|
|
4899
|
+
message_count: cleanedMessages.length,
|
|
4900
|
+
total_input_tokens: state.totalInputTokens,
|
|
4901
|
+
total_output_tokens: state.totalOutputTokens,
|
|
4902
|
+
total_cache_read_tokens: state.totalCacheReadTokens || void 0,
|
|
4903
|
+
total_cache_create_tokens: state.totalCacheCreateTokens || void 0,
|
|
4904
|
+
total_cost: state.totalCost,
|
|
4905
|
+
cost_source: state.totalCost > 0 ? "recorded" : void 0
|
|
4906
|
+
},
|
|
4907
|
+
messages: cleanedMessages
|
|
4908
|
+
};
|
|
4909
|
+
}
|
|
4910
|
+
listSessionFiles(options) {
|
|
4911
|
+
if (!this.basePath) return [];
|
|
4912
|
+
return this.walkJsonlFiles(this.basePath, options);
|
|
4913
|
+
}
|
|
4914
|
+
walkJsonlFiles(dir, options) {
|
|
4915
|
+
const files = [];
|
|
4916
|
+
try {
|
|
4917
|
+
for (const entry of readdirSync5(dir, { withFileTypes: true })) {
|
|
4918
|
+
const fullPath = join9(dir, entry.name);
|
|
4919
|
+
if (entry.isDirectory()) {
|
|
4920
|
+
files.push(...this.walkJsonlFiles(fullPath, options));
|
|
4921
|
+
continue;
|
|
4922
|
+
}
|
|
4923
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
4924
|
+
if (!matchesScanWindow(statSync6(fullPath).mtimeMs, options)) continue;
|
|
4925
|
+
files.push(fullPath);
|
|
4926
|
+
}
|
|
4927
|
+
} catch {
|
|
4928
|
+
}
|
|
4929
|
+
return files;
|
|
4930
|
+
}
|
|
4931
|
+
buildSessionMeta(head, file) {
|
|
4932
|
+
return {
|
|
4933
|
+
id: head.id,
|
|
4934
|
+
title: head.title,
|
|
4935
|
+
sourcePath: file,
|
|
4936
|
+
sourceFingerprint: this.sourceFingerprint(file),
|
|
4937
|
+
sourceMtimeMs: statSync6(file).mtimeMs,
|
|
4938
|
+
headIndexVersion: HEAD_INDEX_VERSION3,
|
|
4939
|
+
parserVersion: PARSER_VERSION2,
|
|
4940
|
+
directory: head.directory,
|
|
4941
|
+
messageCount: head.stats.message_count,
|
|
4942
|
+
createdAt: head.time_created,
|
|
4943
|
+
updatedAt: head.time_updated ?? head.time_created
|
|
4944
|
+
};
|
|
4945
|
+
}
|
|
4946
|
+
hasMetaChanged(meta) {
|
|
4947
|
+
if (meta.headIndexVersion !== HEAD_INDEX_VERSION3) return true;
|
|
4948
|
+
if (meta.parserVersion !== PARSER_VERSION2) return true;
|
|
4949
|
+
return statSync6(meta.sourcePath).mtimeMs !== meta.sourceMtimeMs;
|
|
4950
|
+
}
|
|
4951
|
+
sourceFingerprint(file) {
|
|
4952
|
+
const stat = statSync6(file);
|
|
4953
|
+
return JSON.stringify([HEAD_INDEX_VERSION3, PARSER_VERSION2, stat.mtimeMs, stat.size]);
|
|
4954
|
+
}
|
|
4955
|
+
parseSessionHeadResult(filePath) {
|
|
4956
|
+
const parsed2 = this.parsePiFile(filePath);
|
|
4957
|
+
const state = this.convertEntries(parsed2.pathEntries);
|
|
4958
|
+
const messageCount = state.messages.length;
|
|
4959
|
+
if (messageCount === 0) return filteredSession("no visible messages");
|
|
4960
|
+
const modelUsage = Object.keys(state.modelUsage).length > 0 ? state.modelUsage : void 0;
|
|
4961
|
+
return parsedSession({
|
|
4962
|
+
id: parsed2.sessionId,
|
|
4963
|
+
slug: `pi/${parsed2.sessionId}`,
|
|
4964
|
+
title: parsed2.title,
|
|
4965
|
+
directory: parsed2.directory,
|
|
4966
|
+
time_created: parsed2.createdAt,
|
|
4967
|
+
time_updated: parsed2.updatedAt,
|
|
4968
|
+
stats: {
|
|
4969
|
+
message_count: messageCount,
|
|
4970
|
+
total_input_tokens: state.totalInputTokens,
|
|
4971
|
+
total_output_tokens: state.totalOutputTokens,
|
|
4972
|
+
total_cache_read_tokens: state.totalCacheReadTokens || void 0,
|
|
4973
|
+
total_cache_create_tokens: state.totalCacheCreateTokens || void 0,
|
|
4974
|
+
total_cost: state.totalCost,
|
|
4975
|
+
cost_source: state.totalCost > 0 ? "recorded" : void 0
|
|
4976
|
+
},
|
|
4977
|
+
model_usage: modelUsage
|
|
4978
|
+
});
|
|
4979
|
+
}
|
|
4980
|
+
parsePiFile(filePath) {
|
|
4981
|
+
const records = Array.from(parseJsonlLines(readFileSync7(filePath, "utf-8")));
|
|
4982
|
+
if (records.length === 0) throw new Error("empty file");
|
|
4983
|
+
const header = records.find((record) => record["type"] === "session");
|
|
4984
|
+
if (!header) throw new Error("missing session header");
|
|
4985
|
+
const entries = records.filter((record) => record["type"] !== "session");
|
|
4986
|
+
const pathEntries = buildCurrentPathEntries(entries);
|
|
4987
|
+
if (pathEntries.length === 0) throw new Error("empty session tree");
|
|
4988
|
+
const sessionId = String(header["id"] ?? extractSessionIdFromFilename(filePath)).trim();
|
|
4989
|
+
if (!sessionId) throw new Error("missing session id");
|
|
4990
|
+
const stat = statSync6(filePath);
|
|
4991
|
+
const directory = String(header["cwd"] ?? "").trim() || basename6(filePath, ".jsonl");
|
|
4992
|
+
const createdAt = parseTimestampMs3(header["timestamp"]) || stat.mtimeMs;
|
|
4993
|
+
const updatedAt = pathEntries.reduce(
|
|
4994
|
+
(max, entry) => Math.max(max, getEntryTimestamp(entry)),
|
|
4995
|
+
createdAt
|
|
4996
|
+
);
|
|
4997
|
+
const explicitTitle = this.extractSessionName(pathEntries);
|
|
4998
|
+
const messageTitle = this.extractTitle(pathEntries);
|
|
4999
|
+
const directoryTitle = basenameTitle(directory);
|
|
5000
|
+
return {
|
|
5001
|
+
sessionId,
|
|
5002
|
+
directory,
|
|
5003
|
+
createdAt,
|
|
5004
|
+
updatedAt,
|
|
5005
|
+
title: resolveSessionTitle(explicitTitle, messageTitle, directoryTitle),
|
|
5006
|
+
pathEntries
|
|
5007
|
+
};
|
|
5008
|
+
}
|
|
5009
|
+
extractSessionName(entries) {
|
|
5010
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
5011
|
+
const entry = entries[index];
|
|
5012
|
+
if (entry["type"] !== "session_info") continue;
|
|
5013
|
+
const name = normalizeTitleText(String(entry["name"] ?? ""));
|
|
5014
|
+
if (name) return name;
|
|
5015
|
+
}
|
|
5016
|
+
return null;
|
|
5017
|
+
}
|
|
5018
|
+
extractTitle(entries) {
|
|
5019
|
+
for (const entry of entries) {
|
|
5020
|
+
if (entry["type"] !== "message") continue;
|
|
5021
|
+
const message = entry["message"];
|
|
5022
|
+
if (!isObject(message) || message["role"] !== "user") continue;
|
|
5023
|
+
const title = normalizeTitleText(contentToText(message["content"]));
|
|
5024
|
+
if (title) return title;
|
|
5025
|
+
}
|
|
5026
|
+
return null;
|
|
5027
|
+
}
|
|
5028
|
+
convertEntries(entries) {
|
|
5029
|
+
const messages = [];
|
|
5030
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
5031
|
+
const modelUsage = {};
|
|
5032
|
+
let totalInputTokens = 0;
|
|
5033
|
+
let totalOutputTokens = 0;
|
|
5034
|
+
let totalCacheReadTokens = 0;
|
|
5035
|
+
let totalCacheCreateTokens = 0;
|
|
5036
|
+
let totalCost = 0;
|
|
5037
|
+
for (const entry of entries) {
|
|
5038
|
+
const timestampMs = getEntryTimestamp(entry);
|
|
5039
|
+
const type = String(entry["type"] ?? "");
|
|
5040
|
+
if (type === "message") {
|
|
5041
|
+
const message = entry["message"];
|
|
5042
|
+
if (!isObject(message)) continue;
|
|
5043
|
+
const result = this.convertAgentMessage(
|
|
5044
|
+
entry,
|
|
5045
|
+
message,
|
|
5046
|
+
timestampMs,
|
|
5047
|
+
pendingToolCalls,
|
|
5048
|
+
messages.length,
|
|
5049
|
+
messages
|
|
5050
|
+
);
|
|
5051
|
+
if (!result) continue;
|
|
5052
|
+
if (result.message) messages.push(result.message);
|
|
5053
|
+
totalInputTokens += result.inputTokens;
|
|
5054
|
+
totalOutputTokens += result.outputTokens;
|
|
5055
|
+
totalCacheReadTokens += result.cacheReadTokens;
|
|
5056
|
+
totalCacheCreateTokens += result.cacheCreateTokens;
|
|
5057
|
+
totalCost += result.cost;
|
|
5058
|
+
if (result.model && result.totalTokens > 0) {
|
|
5059
|
+
modelUsage[result.model] = (modelUsage[result.model] ?? 0) + result.totalTokens;
|
|
5060
|
+
}
|
|
5061
|
+
continue;
|
|
5062
|
+
}
|
|
5063
|
+
const summary = this.convertSummaryEntry(entry, timestampMs);
|
|
5064
|
+
if (summary) messages.push(summary);
|
|
5065
|
+
}
|
|
5066
|
+
return {
|
|
5067
|
+
messages,
|
|
5068
|
+
totalInputTokens,
|
|
5069
|
+
totalOutputTokens,
|
|
5070
|
+
totalCacheReadTokens,
|
|
5071
|
+
totalCacheCreateTokens,
|
|
5072
|
+
totalCost,
|
|
5073
|
+
modelUsage
|
|
5074
|
+
};
|
|
5075
|
+
}
|
|
5076
|
+
convertAgentMessage(entry, message, timestampMs, pendingToolCalls, nextMessageIndex, messages) {
|
|
5077
|
+
const id = String(entry["id"] ?? "");
|
|
5078
|
+
const role = String(message["role"] ?? "");
|
|
5079
|
+
if (role === "user") {
|
|
5080
|
+
const parts = normalizeTextParts(message["content"], timestampMs);
|
|
5081
|
+
if (parts.length === 0) return null;
|
|
5082
|
+
return this.emptyUsageResult(buildMessage({ id, role: "user", timestampMs, parts }));
|
|
5083
|
+
}
|
|
5084
|
+
if (role === "assistant") {
|
|
5085
|
+
const parts = this.normalizeAssistantParts(
|
|
5086
|
+
message["content"],
|
|
5087
|
+
timestampMs,
|
|
5088
|
+
pendingToolCalls,
|
|
5089
|
+
nextMessageIndex
|
|
5090
|
+
);
|
|
5091
|
+
if (parts.length === 0) return null;
|
|
5092
|
+
const usage = this.normalizeUsage(message["usage"]);
|
|
5093
|
+
const model = typeof message["model"] === "string" ? message["model"].trim() : null;
|
|
5094
|
+
const cost = usage.cost ?? estimateTokenCost(model, usage.tokens) ?? 0;
|
|
5095
|
+
return {
|
|
5096
|
+
message: buildMessage({
|
|
5097
|
+
id,
|
|
5098
|
+
role: "assistant",
|
|
5099
|
+
agent: "pi",
|
|
5100
|
+
timestampMs,
|
|
5101
|
+
parts,
|
|
5102
|
+
provider: typeof message["provider"] === "string" ? message["provider"] : null,
|
|
5103
|
+
model,
|
|
5104
|
+
tokens: usage.tokens,
|
|
5105
|
+
cost: cost || void 0,
|
|
5106
|
+
costSource: cost > 0 ? "recorded" : void 0
|
|
5107
|
+
}),
|
|
5108
|
+
inputTokens: usage.inputTokens,
|
|
5109
|
+
outputTokens: usage.outputTokens,
|
|
5110
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
5111
|
+
cacheCreateTokens: usage.cacheCreateTokens,
|
|
5112
|
+
totalTokens: usage.totalTokens,
|
|
5113
|
+
cost,
|
|
5114
|
+
model
|
|
5115
|
+
};
|
|
5116
|
+
}
|
|
5117
|
+
if (role === "toolResult") {
|
|
5118
|
+
this.attachToolResult(message, timestampMs, pendingToolCalls, messages);
|
|
5119
|
+
return this.emptyUsageResult();
|
|
5120
|
+
}
|
|
5121
|
+
if (role === "bashExecution") {
|
|
5122
|
+
return this.emptyUsageResult(this.convertBashExecution(id, message, timestampMs));
|
|
5123
|
+
}
|
|
5124
|
+
if (role === "custom" && message["display"] === true) {
|
|
5125
|
+
const parts = normalizeTextParts(message["content"], timestampMs);
|
|
5126
|
+
if (parts.length === 0) return null;
|
|
5127
|
+
return this.emptyUsageResult(buildMessage({ id, role: "user", timestampMs, parts }));
|
|
5128
|
+
}
|
|
5129
|
+
if (role === "branchSummary" || role === "compactionSummary") {
|
|
5130
|
+
const summary = String(message["summary"] ?? "").trim();
|
|
5131
|
+
if (!summary) return null;
|
|
5132
|
+
return this.emptyUsageResult(
|
|
5133
|
+
buildMessage({
|
|
5134
|
+
id,
|
|
5135
|
+
role: "assistant",
|
|
5136
|
+
agent: "pi",
|
|
5137
|
+
timestampMs,
|
|
5138
|
+
parts: [{ type: "text", text: summary, time_created: timestampMs }]
|
|
5139
|
+
})
|
|
5140
|
+
);
|
|
5141
|
+
}
|
|
5142
|
+
return null;
|
|
5143
|
+
}
|
|
5144
|
+
normalizeAssistantParts(content, timestampMs, pendingToolCalls, messageIndex) {
|
|
5145
|
+
if (!Array.isArray(content)) return [];
|
|
5146
|
+
const parts = [];
|
|
5147
|
+
for (const item of content) {
|
|
5148
|
+
if (!isObject(item)) continue;
|
|
5149
|
+
const type = item["type"];
|
|
5150
|
+
if (type === "text") {
|
|
5151
|
+
const text = cleanInternalText(String(item["text"] ?? ""));
|
|
5152
|
+
if (text) parts.push({ type: "text", text, time_created: timestampMs });
|
|
5153
|
+
continue;
|
|
5154
|
+
}
|
|
5155
|
+
if (type === "thinking") {
|
|
5156
|
+
const text = cleanInternalText(String(item["thinking"] ?? ""));
|
|
5157
|
+
if (text) parts.push({ type: "reasoning", text, time_created: timestampMs });
|
|
5158
|
+
continue;
|
|
5159
|
+
}
|
|
5160
|
+
if (type === "toolCall") {
|
|
5161
|
+
const callId = String(item["id"] ?? "").trim();
|
|
5162
|
+
const toolName = String(item["name"] ?? "").trim() || "tool";
|
|
5163
|
+
const toolPart = {
|
|
5164
|
+
type: "tool",
|
|
5165
|
+
tool: toolName,
|
|
5166
|
+
title: `Tool: ${toolName}`,
|
|
5167
|
+
callID: callId || void 0,
|
|
5168
|
+
time_created: timestampMs,
|
|
5169
|
+
state: {
|
|
5170
|
+
status: "running",
|
|
5171
|
+
input: item["arguments"] ?? {}
|
|
5172
|
+
}
|
|
5173
|
+
};
|
|
5174
|
+
parts.push(toolPart);
|
|
5175
|
+
if (callId) pendingToolCalls.set(callId, [messageIndex, parts.length - 1]);
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
return parts;
|
|
5179
|
+
}
|
|
5180
|
+
attachToolResult(message, timestampMs, pendingToolCalls, messages) {
|
|
5181
|
+
const callId = String(message["toolCallId"] ?? "").trim();
|
|
5182
|
+
const output = normalizeTextParts(message["content"], timestampMs);
|
|
5183
|
+
const location = callId ? pendingToolCalls.get(callId) : void 0;
|
|
5184
|
+
if (!location) return;
|
|
5185
|
+
const [messageIndex, partIndex] = location;
|
|
5186
|
+
const target = messages[messageIndex]?.parts[partIndex];
|
|
5187
|
+
if (!target?.state) return;
|
|
5188
|
+
target.state.output = output;
|
|
5189
|
+
target.state.status = message["isError"] === true ? "error" : "completed";
|
|
5190
|
+
target.state.metadata = message["details"];
|
|
5191
|
+
pendingToolCalls.delete(callId);
|
|
5192
|
+
}
|
|
5193
|
+
convertBashExecution(id, message, timestampMs) {
|
|
5194
|
+
const command = String(message["command"] ?? "");
|
|
5195
|
+
const output = String(message["output"] ?? "");
|
|
5196
|
+
const isError = Number(message["exitCode"] ?? 0) !== 0 || message["cancelled"] === true;
|
|
5197
|
+
return buildMessage({
|
|
5198
|
+
id,
|
|
5199
|
+
role: "tool",
|
|
5200
|
+
timestampMs,
|
|
5201
|
+
parts: [
|
|
5202
|
+
{
|
|
5203
|
+
type: "tool",
|
|
5204
|
+
tool: "bash",
|
|
5205
|
+
title: "Tool: bash",
|
|
5206
|
+
time_created: timestampMs,
|
|
5207
|
+
state: {
|
|
5208
|
+
status: isError ? "error" : "completed",
|
|
5209
|
+
input: { command },
|
|
5210
|
+
output: output ? [{ type: "text", text: output, time_created: timestampMs }] : [],
|
|
5211
|
+
metadata: {
|
|
5212
|
+
exitCode: message["exitCode"],
|
|
5213
|
+
cancelled: message["cancelled"],
|
|
5214
|
+
truncated: message["truncated"],
|
|
5215
|
+
fullOutputPath: message["fullOutputPath"]
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
]
|
|
5220
|
+
});
|
|
5221
|
+
}
|
|
5222
|
+
convertSummaryEntry(entry, timestampMs) {
|
|
5223
|
+
const type = entry["type"];
|
|
5224
|
+
if (type !== "compaction" && type !== "branch_summary" && type !== "custom_message") {
|
|
5225
|
+
return null;
|
|
5226
|
+
}
|
|
5227
|
+
if (type === "custom_message" && entry["display"] !== true) return null;
|
|
5228
|
+
const rawText = type === "custom_message" ? contentToText(entry["content"]) : String(entry["summary"] ?? "");
|
|
5229
|
+
const text = cleanInternalText(rawText);
|
|
5230
|
+
if (!text) return null;
|
|
5231
|
+
return buildMessage({
|
|
5232
|
+
id: String(entry["id"] ?? ""),
|
|
5233
|
+
role: type === "custom_message" ? "user" : "assistant",
|
|
5234
|
+
agent: type === "custom_message" ? void 0 : "pi",
|
|
5235
|
+
timestampMs,
|
|
5236
|
+
parts: [{ type: "text", text, time_created: timestampMs }]
|
|
5237
|
+
});
|
|
5238
|
+
}
|
|
5239
|
+
normalizeUsage(raw) {
|
|
5240
|
+
const usage = isObject(raw) ? raw : {};
|
|
5241
|
+
const inputTokens = Number(usage["input"] ?? 0);
|
|
5242
|
+
const outputTokens = Number(usage["output"] ?? 0);
|
|
5243
|
+
const cacheReadTokens = Number(usage["cacheRead"] ?? 0);
|
|
5244
|
+
const cacheCreateTokens = Number(usage["cacheWrite"] ?? 0);
|
|
5245
|
+
const totalTokens = Number(
|
|
5246
|
+
usage["totalTokens"] ?? inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens
|
|
5247
|
+
);
|
|
5248
|
+
const cost = isObject(usage["cost"]) ? Number(usage["cost"]["total"] ?? 0) : null;
|
|
5249
|
+
return {
|
|
5250
|
+
inputTokens: inputTokens + cacheReadTokens + cacheCreateTokens,
|
|
5251
|
+
outputTokens,
|
|
5252
|
+
cacheReadTokens,
|
|
5253
|
+
cacheCreateTokens,
|
|
5254
|
+
totalTokens,
|
|
5255
|
+
cost: cost && Number.isFinite(cost) ? cost : null,
|
|
5256
|
+
tokens: {
|
|
5257
|
+
input: inputTokens + cacheReadTokens + cacheCreateTokens,
|
|
5258
|
+
output: outputTokens,
|
|
5259
|
+
cache_read: cacheReadTokens || void 0,
|
|
5260
|
+
cache_create: cacheCreateTokens || void 0
|
|
5261
|
+
}
|
|
5262
|
+
};
|
|
5263
|
+
}
|
|
5264
|
+
emptyUsageResult(message) {
|
|
5265
|
+
return {
|
|
5266
|
+
message,
|
|
5267
|
+
inputTokens: 0,
|
|
5268
|
+
outputTokens: 0,
|
|
5269
|
+
cacheReadTokens: 0,
|
|
5270
|
+
cacheCreateTokens: 0,
|
|
5271
|
+
totalTokens: 0,
|
|
5272
|
+
cost: 0,
|
|
5273
|
+
model: null
|
|
5274
|
+
};
|
|
5275
|
+
}
|
|
5276
|
+
};
|
|
4667
5277
|
registerAgent({
|
|
4668
5278
|
name: "claudecode",
|
|
4669
5279
|
displayName: "Claude Code",
|
|
@@ -4688,6 +5298,12 @@ registerAgent({
|
|
|
4688
5298
|
icon: "/icon/agent/codex.svg",
|
|
4689
5299
|
create: () => new CodexAgent()
|
|
4690
5300
|
});
|
|
5301
|
+
registerAgent({
|
|
5302
|
+
name: "pi",
|
|
5303
|
+
displayName: "Pi",
|
|
5304
|
+
icon: "/icon/agent/pi.svg",
|
|
5305
|
+
create: () => new PiAgent()
|
|
5306
|
+
});
|
|
4691
5307
|
registerAgent({
|
|
4692
5308
|
name: "cursor",
|
|
4693
5309
|
displayName: "Cursor",
|
|
@@ -4702,11 +5318,11 @@ function fallbackDisplayName(input) {
|
|
|
4702
5318
|
}
|
|
4703
5319
|
var realFs = {
|
|
4704
5320
|
exists(path2) {
|
|
4705
|
-
return
|
|
5321
|
+
return existsSync10(path2);
|
|
4706
5322
|
},
|
|
4707
5323
|
readText(path2) {
|
|
4708
5324
|
try {
|
|
4709
|
-
return
|
|
5325
|
+
return readFileSync8(path2, "utf8");
|
|
4710
5326
|
} catch {
|
|
4711
5327
|
return null;
|
|
4712
5328
|
}
|
|
@@ -5196,16 +5812,16 @@ var LEGACY_CACHE_FILENAME = "scan-cache.json";
|
|
|
5196
5812
|
var SEARCH_INDEX_BULK_SYNC_THRESHOLD = 100;
|
|
5197
5813
|
var ftsIntegrityCheckedPath = null;
|
|
5198
5814
|
function getCacheDir2() {
|
|
5199
|
-
return
|
|
5815
|
+
return join10(homedir4(), ".cache", "codesesh");
|
|
5200
5816
|
}
|
|
5201
5817
|
function getCachePath2() {
|
|
5202
|
-
return
|
|
5818
|
+
return join10(getCacheDir2(), CACHE_FILENAME);
|
|
5203
5819
|
}
|
|
5204
5820
|
function getLegacyCachePath() {
|
|
5205
|
-
return
|
|
5821
|
+
return join10(getCacheDir2(), LEGACY_CACHE_FILENAME);
|
|
5206
5822
|
}
|
|
5207
5823
|
function hasCacheStorage() {
|
|
5208
|
-
return
|
|
5824
|
+
return existsSync11(getCachePath2());
|
|
5209
5825
|
}
|
|
5210
5826
|
function withCacheDb(fn) {
|
|
5211
5827
|
const cachePath = getCachePath2();
|
|
@@ -6644,7 +7260,7 @@ function buildSessionContentFromMessages(title, messages) {
|
|
|
6644
7260
|
}
|
|
6645
7261
|
function deleteLegacyCacheFile() {
|
|
6646
7262
|
const legacyPath = getLegacyCachePath();
|
|
6647
|
-
if (!
|
|
7263
|
+
if (!existsSync11(legacyPath)) {
|
|
6648
7264
|
return;
|
|
6649
7265
|
}
|
|
6650
7266
|
try {
|
|
@@ -6971,7 +7587,7 @@ function clearCache() {
|
|
|
6971
7587
|
const walPath = `${cachePath}-wal`;
|
|
6972
7588
|
const shmPath = `${cachePath}-shm`;
|
|
6973
7589
|
for (const filePath of [walPath, shmPath]) {
|
|
6974
|
-
if (!
|
|
7590
|
+
if (!existsSync11(filePath)) {
|
|
6975
7591
|
continue;
|
|
6976
7592
|
}
|
|
6977
7593
|
try {
|
|
@@ -8179,16 +8795,16 @@ function getStateDir() {
|
|
|
8179
8795
|
}
|
|
8180
8796
|
const p = platform2();
|
|
8181
8797
|
if (p === "darwin") {
|
|
8182
|
-
return
|
|
8798
|
+
return join11(homedir5(), "Library", "Application Support", "codesesh");
|
|
8183
8799
|
}
|
|
8184
8800
|
if (p === "win32") {
|
|
8185
8801
|
const appData = process.env.APPDATA ?? process.env.LOCALAPPDATA;
|
|
8186
|
-
return
|
|
8802
|
+
return join11(appData ?? join11(homedir5(), "AppData", "Roaming"), "codesesh");
|
|
8187
8803
|
}
|
|
8188
|
-
return
|
|
8804
|
+
return join11(process.env.XDG_DATA_HOME ?? join11(homedir5(), ".local", "share"), "codesesh");
|
|
8189
8805
|
}
|
|
8190
8806
|
function getStateDbPath() {
|
|
8191
|
-
return
|
|
8807
|
+
return join11(getStateDir(), BOOKMARK_DB_FILENAME);
|
|
8192
8808
|
}
|
|
8193
8809
|
function useMemoryStateStore() {
|
|
8194
8810
|
return process.env.CODESESH_STATE_STORE === MEMORY_STATE_STORE;
|
|
@@ -8556,4 +9172,4 @@ export {
|
|
|
8556
9172
|
importBookmarks,
|
|
8557
9173
|
deleteBookmark
|
|
8558
9174
|
};
|
|
8559
|
-
//# sourceMappingURL=chunk-
|
|
9175
|
+
//# sourceMappingURL=chunk-5UOLRSFH.js.map
|