codesesh 0.19.0 → 1.0.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 +2 -1
- package/dist/{chunk-G2BTNW3C.js → chunk-BEF6LLRG.js} +1230 -182
- package/dist/chunk-BEF6LLRG.js.map +1 -0
- package/dist/{chunk-KD3DGWZY.js → chunk-TIHF4T3K.js} +2 -2
- package/dist/{dist-ALXOBKV2.js → dist-3F467V44.js} +4 -2
- package/dist/index.js +53 -12
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +2 -2
- package/dist/search-index-worker.js +9 -11
- package/dist/search-index-worker.js.map +1 -1
- package/dist/smart-tag-worker.js +2 -2
- package/dist/web/assets/ErrorBoundary-BY-N1QzJ.js +1 -0
- package/dist/web/assets/InteractiveReceipt-DYGyHeZd.js +1 -0
- package/dist/web/assets/OverviewScreen-_ZaVjhxN.js +1 -0
- package/dist/web/assets/PrismHighlighter-BZkkX0AU.js +6 -0
- package/dist/web/assets/Projects-q6cEm2dc.js +1 -0
- package/dist/web/assets/SearchFilterBar-CrVBpo40.js +1 -0
- package/dist/web/assets/SearchResultsPanel-Cg5V8Ia6.js +1 -0
- package/dist/web/assets/SessionDetail-BSSuddsZ.js +54 -0
- package/dist/web/assets/{session-title-CNhapdPJ.js → SmartTagChips-ux6idUGJ.js} +1 -1
- package/dist/web/assets/chunk-62JRHF6Z-BWRsEBnL.js +4 -0
- package/dist/web/assets/code-metrics-UYFsCC7E.js +1 -0
- package/dist/web/assets/ibm-plex-sans-cyrillic-ext-wght-normal-d45eAU9y.woff2 +0 -0
- package/dist/web/assets/ibm-plex-sans-cyrillic-wght-normal-BAAhND-U.woff2 +0 -0
- package/dist/web/assets/ibm-plex-sans-greek-wght-normal-CmyJS8uq.woff2 +0 -0
- package/dist/web/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
- package/dist/web/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
- package/dist/web/assets/ibm-plex-sans-vietnamese-wght-normal-Dg1JeJN0.woff2 +0 -0
- package/dist/web/assets/index-C3KgxGwE.js +1410 -0
- package/dist/web/assets/index-DQX42cFQ.css +1 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/web/assets/jsx-runtime-B-hcVAMW.js +1 -0
- package/dist/web/assets/panel-B7kuE60V.js +1 -0
- package/dist/web/assets/session-indexes-DmnjZ_JL.js +1 -0
- package/dist/web/assets/session-title-DdtlxtlR.js +1 -0
- package/dist/web/assets/space-grotesk-latin-ext-wght-normal-D9tNdqV9.woff2 +0 -0
- package/dist/web/assets/space-grotesk-latin-wght-normal-BhU9QXUp.woff2 +0 -0
- package/dist/web/assets/space-grotesk-vietnamese-wght-normal-D0rl6rjA.woff2 +0 -0
- package/dist/web/assets/utils-t2u9IbNT.js +1 -0
- package/dist/web/icon/agent/grok.svg +1 -0
- package/dist/web/index.html +43 -30
- package/package.json +8 -8
- package/dist/chunk-G2BTNW3C.js.map +0 -1
- package/dist/web/assets/AgentIcon-CEj7HO1m.js +0 -1
- package/dist/web/assets/BookmarkButton-DLEnIyeE.js +0 -1
- package/dist/web/assets/Dashboard-DUG0IFcy.js +0 -39
- package/dist/web/assets/DialogTitle-Dv6DQPIb.js +0 -1
- package/dist/web/assets/InteractiveReceipt-xnRqJvfd.js +0 -1
- package/dist/web/assets/PrismHighlighter-C7OfXHq2.js +0 -6
- package/dist/web/assets/Projects-BMaZc6J5.js +0 -1
- package/dist/web/assets/SearchFilterBar-iP6pzlZo.js +0 -1
- package/dist/web/assets/SearchResultsPanel-RuiLPkbP.js +0 -1
- package/dist/web/assets/SessionDetail-De1Wl3mu.js +0 -54
- package/dist/web/assets/index-B-CV7pFu.css +0 -2
- package/dist/web/assets/index-CQI8F_8X.js +0 -1930
- package/dist/web/assets/index.dom-CCLJ9_FR.js +0 -1
- package/dist/web/assets/jsx-runtime-n5LQ9ujS.js +0 -1
- package/dist/web/assets/session-indexes-BuxBafvh.js +0 -4
- package/dist/web/assets/useTheme-CwDcVdGz.js +0 -1
- package/dist/web/assets/utils-B6KiDbIe.js +0 -1
- /package/dist/{chunk-KD3DGWZY.js.map → chunk-TIHF4T3K.js.map} +0 -0
- /package/dist/{dist-ALXOBKV2.js.map → dist-3F467V44.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// ../core/dist/chunk-
|
|
3
|
+
// ../core/dist/chunk-TXYCGCSU.mjs
|
|
4
4
|
function toRecord(value) {
|
|
5
5
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
6
6
|
}
|
|
@@ -253,14 +253,20 @@ function mergeSortedSessions(shards) {
|
|
|
253
253
|
}
|
|
254
254
|
return merged;
|
|
255
255
|
}
|
|
256
|
-
function
|
|
257
|
-
return
|
|
256
|
+
function getSessionRouteKey(agentName, sessionId) {
|
|
257
|
+
return formatSessionReference({ agentName, sessionId });
|
|
258
258
|
}
|
|
259
259
|
function sessionKey(session) {
|
|
260
|
-
return
|
|
260
|
+
return getSessionRouteKey(getSessionAgentKey(session), session.id);
|
|
261
|
+
}
|
|
262
|
+
function parentKey(session) {
|
|
263
|
+
return session.parent_reference ? formatSessionReference(session.parent_reference) : null;
|
|
264
|
+
}
|
|
265
|
+
function activityTime(session) {
|
|
266
|
+
return session.time_updated ?? session.time_created;
|
|
261
267
|
}
|
|
262
268
|
function hasActivityInWindow(session, from, to) {
|
|
263
|
-
const activity = session
|
|
269
|
+
const activity = activityTime(session);
|
|
264
270
|
return (from == null || activity >= from) && (to == null || activity <= to);
|
|
265
271
|
}
|
|
266
272
|
function isChildSession(session) {
|
|
@@ -269,20 +275,129 @@ function isChildSession(session) {
|
|
|
269
275
|
function getRootSessions(sessions) {
|
|
270
276
|
return sessions.filter((session) => !session.parent_reference);
|
|
271
277
|
}
|
|
278
|
+
function ownStats(session) {
|
|
279
|
+
const stats = session.stats;
|
|
280
|
+
const cost = stats.total_cost ?? 0;
|
|
281
|
+
return {
|
|
282
|
+
messageCount: stats.message_count,
|
|
283
|
+
inputTokens: stats.total_input_tokens,
|
|
284
|
+
outputTokens: stats.total_output_tokens,
|
|
285
|
+
cacheReadTokens: stats.total_cache_read_tokens ?? 0,
|
|
286
|
+
cacheCreateTokens: stats.total_cache_create_tokens ?? 0,
|
|
287
|
+
totalTokens: stats.total_tokens ?? stats.total_input_tokens + stats.total_output_tokens,
|
|
288
|
+
cost,
|
|
289
|
+
costSource: cost > 0 ? stats.cost_source ?? "recorded" : void 0
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function addStats(target, source) {
|
|
293
|
+
target.messageCount += source.messageCount;
|
|
294
|
+
target.inputTokens += source.inputTokens;
|
|
295
|
+
target.outputTokens += source.outputTokens;
|
|
296
|
+
target.cacheReadTokens += source.cacheReadTokens;
|
|
297
|
+
target.cacheCreateTokens += source.cacheCreateTokens;
|
|
298
|
+
target.totalTokens += source.totalTokens;
|
|
299
|
+
target.cost += source.cost;
|
|
300
|
+
if (source.costSource === "estimated") target.costSource = "estimated";
|
|
301
|
+
}
|
|
302
|
+
function rollUpSubtree(entry) {
|
|
303
|
+
const order = [];
|
|
304
|
+
const pending2 = [entry];
|
|
305
|
+
while (pending2.length > 0) {
|
|
306
|
+
const node = pending2.pop();
|
|
307
|
+
order.push(node);
|
|
308
|
+
for (const child of node.children) pending2.push(child);
|
|
309
|
+
}
|
|
310
|
+
for (let index = order.length - 1; index >= 0; index -= 1) {
|
|
311
|
+
const node = order[index];
|
|
312
|
+
const stats = node.inclusiveStats;
|
|
313
|
+
let descendants = 0;
|
|
314
|
+
for (const child of node.children) {
|
|
315
|
+
descendants += 1 + child.descendantCount;
|
|
316
|
+
addStats(stats, child.inclusiveStats);
|
|
317
|
+
}
|
|
318
|
+
if (stats.cost > 0 && stats.costSource == null) stats.costSource = "recorded";
|
|
319
|
+
node.descendantCount = descendants;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function buildSessionTree(sessions) {
|
|
323
|
+
const byRouteKey = /* @__PURE__ */ new Map();
|
|
324
|
+
const nodes = sessions.map((session) => ({
|
|
325
|
+
session,
|
|
326
|
+
children: [],
|
|
327
|
+
descendantCount: 0,
|
|
328
|
+
inclusiveStats: ownStats(session)
|
|
329
|
+
}));
|
|
330
|
+
for (const node of nodes) {
|
|
331
|
+
const key = sessionKey(node.session);
|
|
332
|
+
if (!byRouteKey.has(key)) byRouteKey.set(key, node);
|
|
333
|
+
}
|
|
334
|
+
const chainTerminates = /* @__PURE__ */ new Map();
|
|
335
|
+
function reachesRoot(startKey) {
|
|
336
|
+
const path2 = [];
|
|
337
|
+
const onPath = /* @__PURE__ */ new Set();
|
|
338
|
+
let key = startKey;
|
|
339
|
+
let terminates = true;
|
|
340
|
+
while (key != null) {
|
|
341
|
+
const memo = chainTerminates.get(key);
|
|
342
|
+
if (memo != null) {
|
|
343
|
+
terminates = memo;
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
if (onPath.has(key)) {
|
|
347
|
+
terminates = false;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
onPath.add(key);
|
|
351
|
+
path2.push(key);
|
|
352
|
+
const parent = parentKey(byRouteKey.get(key).session);
|
|
353
|
+
key = parent != null && byRouteKey.has(parent) ? parent : null;
|
|
354
|
+
}
|
|
355
|
+
for (const visited of path2) chainTerminates.set(visited, terminates);
|
|
356
|
+
return terminates;
|
|
357
|
+
}
|
|
358
|
+
const mountStates = /* @__PURE__ */ new Map();
|
|
359
|
+
const roots = [];
|
|
360
|
+
const orphans = [];
|
|
361
|
+
const entries = [];
|
|
362
|
+
for (const node of nodes) {
|
|
363
|
+
const key = sessionKey(node.session);
|
|
364
|
+
const parent = parentKey(node.session);
|
|
365
|
+
const state = parent == null ? "root" : byRouteKey.has(parent) && reachesRoot(key) ? "mounted-child" : "orphan";
|
|
366
|
+
mountStates.set(key, state);
|
|
367
|
+
if (state === "mounted-child") {
|
|
368
|
+
byRouteKey.get(parent).children.push(node);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
(state === "root" ? roots : orphans).push(node);
|
|
372
|
+
entries.push(node);
|
|
373
|
+
}
|
|
374
|
+
for (const entry of entries) rollUpSubtree(entry);
|
|
375
|
+
return {
|
|
376
|
+
roots,
|
|
377
|
+
orphans,
|
|
378
|
+
entries,
|
|
379
|
+
byRouteKey,
|
|
380
|
+
mountStateOf(session) {
|
|
381
|
+
return mountStates.get(sessionKey(session)) ?? (session.parent_reference ? "orphan" : "root");
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
272
385
|
function filterSessionTreeByActivityWindow(sessions, from, to) {
|
|
273
386
|
if (from == null && to == null) return sessions;
|
|
274
387
|
const available = new Set(sessions.map(sessionKey));
|
|
275
388
|
const childrenByParent = /* @__PURE__ */ new Map();
|
|
389
|
+
const pending2 = [];
|
|
276
390
|
for (const session of sessions) {
|
|
277
|
-
const parent = session
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
391
|
+
const parent = parentKey(session);
|
|
392
|
+
if (parent != null && available.has(parent)) {
|
|
393
|
+
const children = childrenByParent.get(parent);
|
|
394
|
+
if (children) children.push(sessionKey(session));
|
|
395
|
+
else childrenByParent.set(parent, [sessionKey(session)]);
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (hasActivityInWindow(session, from, to)) pending2.push(sessionKey(session));
|
|
283
399
|
}
|
|
284
400
|
const visible = /* @__PURE__ */ new Set();
|
|
285
|
-
const pending2 = getRootSessions(sessions).filter((session) => hasActivityInWindow(session, from, to)).map(sessionKey);
|
|
286
401
|
while (pending2.length > 0) {
|
|
287
402
|
const key = pending2.pop();
|
|
288
403
|
if (visible.has(key)) continue;
|
|
@@ -339,9 +454,15 @@ var SAMPLE_DASHBOARD_DATA = {
|
|
|
339
454
|
messages: 12,
|
|
340
455
|
tokens: 6e3,
|
|
341
456
|
cost: 0.042,
|
|
457
|
+
costRecorded: 0.042,
|
|
458
|
+
costEstimated: 0,
|
|
459
|
+
cacheReadTokens: 3e3,
|
|
342
460
|
cost_source: "recorded",
|
|
343
|
-
latestActivity: 17000036e5
|
|
461
|
+
latestActivity: 17000036e5,
|
|
462
|
+
latestActivityProject: "example/project",
|
|
463
|
+
latestActivityAgent: "claudecode"
|
|
344
464
|
},
|
|
465
|
+
scopeCounts: { projects: 1, agents: 1 },
|
|
345
466
|
perAgent: [
|
|
346
467
|
{
|
|
347
468
|
name: "claudecode",
|
|
@@ -349,14 +470,38 @@ var SAMPLE_DASHBOARD_DATA = {
|
|
|
349
470
|
icon: "claude",
|
|
350
471
|
sessions: 1,
|
|
351
472
|
messages: 12,
|
|
352
|
-
tokens: 6e3
|
|
473
|
+
tokens: 6e3,
|
|
474
|
+
cost: 0.042
|
|
353
475
|
}
|
|
354
476
|
],
|
|
355
|
-
dailyActivity: [
|
|
356
|
-
|
|
357
|
-
|
|
477
|
+
dailyActivity: [
|
|
478
|
+
{
|
|
479
|
+
date: "2023-11-14",
|
|
480
|
+
sessions: 1,
|
|
481
|
+
messages: 12,
|
|
482
|
+
cost: 0.042,
|
|
483
|
+
input: 700,
|
|
484
|
+
output: 1800,
|
|
485
|
+
cache_read: 3e3,
|
|
486
|
+
cache_create: 500
|
|
487
|
+
}
|
|
358
488
|
],
|
|
359
489
|
modelDistribution: [{ model: "claude-5-sonnet", tokens: 6e3, sessions: 1 }],
|
|
490
|
+
perProject: [
|
|
491
|
+
{
|
|
492
|
+
identityKind: "git_remote",
|
|
493
|
+
identityKey: "github.com/example/project",
|
|
494
|
+
displayName: "example/project",
|
|
495
|
+
sessions: 1,
|
|
496
|
+
messages: 12,
|
|
497
|
+
tokens: 6e3,
|
|
498
|
+
cost: 0.042,
|
|
499
|
+
cost_source: "recorded",
|
|
500
|
+
agents: ["claudecode"],
|
|
501
|
+
sparkline: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.042]
|
|
502
|
+
}
|
|
503
|
+
],
|
|
504
|
+
projectRollup: { projects: 0, sessions: 0, tokens: 0, cost: 0 },
|
|
360
505
|
recentSessions: [
|
|
361
506
|
{
|
|
362
507
|
reference: { agentName: "claudecode", sessionId: SAMPLE_SESSION_HEAD.id },
|
|
@@ -364,6 +509,7 @@ var SAMPLE_DASHBOARD_DATA = {
|
|
|
364
509
|
}
|
|
365
510
|
],
|
|
366
511
|
recentFileActivities: [],
|
|
512
|
+
modelCost: null,
|
|
367
513
|
window: { from: 16999e8, to: 17000036e5, days: 1 }
|
|
368
514
|
};
|
|
369
515
|
|
|
@@ -409,19 +555,21 @@ import { existsSync as existsSync11 } from "fs";
|
|
|
409
555
|
import { basename as basename8, join as join12 } from "path";
|
|
410
556
|
import { homedir as homedir4, platform as platform3 } from "os";
|
|
411
557
|
import { join as join13 } from "path";
|
|
558
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, statSync as statSync8 } from "fs";
|
|
559
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
412
560
|
import { availableParallelism } from "os";
|
|
413
561
|
import { Worker } from "worker_threads";
|
|
414
|
-
import { existsSync as
|
|
562
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
|
|
415
563
|
import { spawnSync } from "child_process";
|
|
416
564
|
import * as os from "os";
|
|
417
565
|
import * as path from "path";
|
|
418
566
|
import { resolve as resolve2, sep } from "path";
|
|
419
|
-
import { existsSync as
|
|
420
|
-
import { existsSync as
|
|
421
|
-
import { join as
|
|
567
|
+
import { existsSync as existsSync15, rmSync as rmSync2, unlinkSync } from "fs";
|
|
568
|
+
import { existsSync as existsSync14 } from "fs";
|
|
569
|
+
import { join as join15 } from "path";
|
|
422
570
|
import { homedir as homedir6 } from "os";
|
|
423
571
|
import { homedir as homedir7, platform as platform4 } from "os";
|
|
424
|
-
import { join as
|
|
572
|
+
import { join as join16 } from "path";
|
|
425
573
|
var registrations = [];
|
|
426
574
|
function registerAgent(reg) {
|
|
427
575
|
registrations.push(reg);
|
|
@@ -480,9 +628,9 @@ function filteredSession(reason) {
|
|
|
480
628
|
function getParsedSession(result) {
|
|
481
629
|
return result.status === "parsed" ? result.data : null;
|
|
482
630
|
}
|
|
483
|
-
function matchesScanWindow(
|
|
484
|
-
if (options?.from != null &&
|
|
485
|
-
if (options?.to != null &&
|
|
631
|
+
function matchesScanWindow(activityTime2, options) {
|
|
632
|
+
if (options?.from != null && activityTime2 < options.from) return false;
|
|
633
|
+
if (options?.to != null && activityTime2 > options.to) return false;
|
|
486
634
|
return true;
|
|
487
635
|
}
|
|
488
636
|
function readCachedMeta(meta, sessionId) {
|
|
@@ -2491,7 +2639,7 @@ function runSchemaMigrations(db, options) {
|
|
|
2491
2639
|
migration.migrate(db);
|
|
2492
2640
|
setUserVersion(db, migration.version);
|
|
2493
2641
|
});
|
|
2494
|
-
apply();
|
|
2642
|
+
apply.immediate();
|
|
2495
2643
|
currentVersion = migration.version;
|
|
2496
2644
|
getCoreDiagnostics()?.info?.("sqlite.migration.completed", {
|
|
2497
2645
|
label: options.backupLabel,
|
|
@@ -2545,10 +2693,10 @@ function openDb(dbPath) {
|
|
|
2545
2693
|
const db = DatabaseConstructor(dbPath);
|
|
2546
2694
|
restrictPrivateDatabase(dbPath);
|
|
2547
2695
|
try {
|
|
2696
|
+
db.pragma("busy_timeout = 5000");
|
|
2548
2697
|
db.pragma("journal_mode = WAL");
|
|
2549
2698
|
db.pragma("synchronous = NORMAL");
|
|
2550
2699
|
db.pragma("foreign_keys = ON");
|
|
2551
|
-
db.pragma("busy_timeout = 5000");
|
|
2552
2700
|
} catch {
|
|
2553
2701
|
}
|
|
2554
2702
|
return db;
|
|
@@ -5506,13 +5654,13 @@ var CodexAgent = class extends SingleFileSessionSource {
|
|
|
5506
5654
|
const planMatch = fullText.match(PROPOSED_PLAN_PATTERN);
|
|
5507
5655
|
if (planMatch) {
|
|
5508
5656
|
const planText2 = planMatch[1].trim();
|
|
5509
|
-
const
|
|
5657
|
+
const planPart2 = {
|
|
5510
5658
|
type: "plan",
|
|
5511
5659
|
text: planText2,
|
|
5512
5660
|
approval_status: "success",
|
|
5513
5661
|
time_created: timestampMs
|
|
5514
5662
|
};
|
|
5515
|
-
pendingPlan =
|
|
5663
|
+
pendingPlan = planPart2;
|
|
5516
5664
|
}
|
|
5517
5665
|
const displayText = cleanInternalText(fullText.replace(PROPOSED_PLAN_PATTERN, ""));
|
|
5518
5666
|
if (!displayText) return pendingPlan;
|
|
@@ -7081,6 +7229,726 @@ var ZCodeAgent = class extends OpenCodeSqliteAgent {
|
|
|
7081
7229
|
});
|
|
7082
7230
|
}
|
|
7083
7231
|
};
|
|
7232
|
+
var HEAD_INDEX_VERSION4 = "grok-head-v1";
|
|
7233
|
+
var PARSER_VERSION3 = "grok-parser-v1";
|
|
7234
|
+
var SUMMARY_FILE = "summary.json";
|
|
7235
|
+
var UPDATES_FILE = "updates.jsonl";
|
|
7236
|
+
var ACP_UPDATE_METHOD = "session/update";
|
|
7237
|
+
var XAI_UPDATE_METHOD = "_x.ai/session/update";
|
|
7238
|
+
var USD_TICKS_PER_USD = 1e10;
|
|
7239
|
+
var GROK_TOOL_TITLE_MAP = {
|
|
7240
|
+
get_command_or_subagent_output: "task",
|
|
7241
|
+
grep: "grep",
|
|
7242
|
+
list_dir: "list",
|
|
7243
|
+
read_file: "read",
|
|
7244
|
+
run_terminal_command: "bash",
|
|
7245
|
+
search_replace: "edit",
|
|
7246
|
+
todo_write: "todo",
|
|
7247
|
+
web_fetch: "web fetch"
|
|
7248
|
+
};
|
|
7249
|
+
function resolveGrokDataRoot() {
|
|
7250
|
+
return resolveHomePath("GROK_HOME", ".grok");
|
|
7251
|
+
}
|
|
7252
|
+
function safeCount(value) {
|
|
7253
|
+
const number = asNumber(value);
|
|
7254
|
+
return number !== void 0 && Number.isSafeInteger(number) && number >= 0 ? number : 0;
|
|
7255
|
+
}
|
|
7256
|
+
function addCount(total, value) {
|
|
7257
|
+
return Math.min(Number.MAX_SAFE_INTEGER, total + value);
|
|
7258
|
+
}
|
|
7259
|
+
function timestampFromIso(value) {
|
|
7260
|
+
const text = asString(value);
|
|
7261
|
+
if (!text) return null;
|
|
7262
|
+
const timestamp = Date.parse(text);
|
|
7263
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
7264
|
+
}
|
|
7265
|
+
function readJsonRecord(filePath) {
|
|
7266
|
+
try {
|
|
7267
|
+
return asRecord(JSON.parse(readFileSync7(filePath, "utf8"))) ?? null;
|
|
7268
|
+
} catch {
|
|
7269
|
+
return null;
|
|
7270
|
+
}
|
|
7271
|
+
}
|
|
7272
|
+
function parseSummary(source) {
|
|
7273
|
+
const summary = readJsonRecord(source.file);
|
|
7274
|
+
const info = asRecord(summary?.info);
|
|
7275
|
+
const id = asString(info?.id)?.trim();
|
|
7276
|
+
const cwd = asString(info?.cwd)?.trim();
|
|
7277
|
+
if (!id || !cwd) return null;
|
|
7278
|
+
const createdAt = timestampFromIso(summary?.created_at) ?? source.stat.mtimeMs;
|
|
7279
|
+
const updatedAt = timestampFromIso(summary?.last_active_at) ?? timestampFromIso(summary?.updated_at) ?? createdAt;
|
|
7280
|
+
const generatedTitle = asString(summary?.generated_title)?.trim();
|
|
7281
|
+
const sessionSummary = asString(summary?.session_summary)?.trim();
|
|
7282
|
+
const parentSessionId = asString(summary?.parent_session_id)?.trim() || null;
|
|
7283
|
+
return {
|
|
7284
|
+
id,
|
|
7285
|
+
cwd,
|
|
7286
|
+
title: generatedTitle || sessionSummary || null,
|
|
7287
|
+
createdAt,
|
|
7288
|
+
updatedAt,
|
|
7289
|
+
messageCount: safeCount(summary?.num_chat_messages),
|
|
7290
|
+
currentModel: asString(summary?.current_model_id)?.trim() || null,
|
|
7291
|
+
parentSessionId: parentSessionId === id ? null : parentSessionId
|
|
7292
|
+
};
|
|
7293
|
+
}
|
|
7294
|
+
function optionalFileFingerprint(filePath) {
|
|
7295
|
+
try {
|
|
7296
|
+
const stat = statSync8(filePath);
|
|
7297
|
+
return [stat.mtimeMs, stat.size];
|
|
7298
|
+
} catch {
|
|
7299
|
+
return null;
|
|
7300
|
+
}
|
|
7301
|
+
}
|
|
7302
|
+
function unpackUpdate(record, fallbackTimestampMs) {
|
|
7303
|
+
const method = asString(record.method) ?? ACP_UPDATE_METHOD;
|
|
7304
|
+
const params = asRecord(record.params) ?? record;
|
|
7305
|
+
const update = asRecord(params.update);
|
|
7306
|
+
if (!update) return null;
|
|
7307
|
+
const paramsMeta = asRecord(params._meta);
|
|
7308
|
+
const agentTimestampMs = asNumber(paramsMeta?.agentTimestampMs);
|
|
7309
|
+
const envelopeTimestamp = asNumber(record.timestamp);
|
|
7310
|
+
const timestampMs = agentTimestampMs !== void 0 && Number.isSafeInteger(agentTimestampMs) && agentTimestampMs >= 0 ? agentTimestampMs : envelopeTimestamp !== void 0 && Number.isSafeInteger(envelopeTimestamp) && envelopeTimestamp >= 0 && envelopeTimestamp <= Number.MAX_SAFE_INTEGER / 1e3 ? envelopeTimestamp * 1e3 : fallbackTimestampMs;
|
|
7311
|
+
return { method, params, update, timestampMs };
|
|
7312
|
+
}
|
|
7313
|
+
function isHostTurn(update) {
|
|
7314
|
+
return asRecord(update._meta)?.hostTurn === true;
|
|
7315
|
+
}
|
|
7316
|
+
function updateType(update) {
|
|
7317
|
+
return asString(update.update.sessionUpdate) ?? "";
|
|
7318
|
+
}
|
|
7319
|
+
function parseUsage(update) {
|
|
7320
|
+
const usage = asRecord(update.usage);
|
|
7321
|
+
if (!usage) return null;
|
|
7322
|
+
const input = safeCount(usage.inputTokens);
|
|
7323
|
+
const output = safeCount(usage.outputTokens);
|
|
7324
|
+
const reasoning = safeCount(usage.reasoningTokens);
|
|
7325
|
+
const cacheRead = safeCount(usage.cachedReadTokens);
|
|
7326
|
+
const cacheCreate = safeCount(usage.cacheCreationTokens);
|
|
7327
|
+
const totalTokens = safeCount(usage.totalTokens) || addCount(input, output);
|
|
7328
|
+
const isIncomplete = usage.usageIsIncomplete === true || usage.costIsPartial === true;
|
|
7329
|
+
const costTicks = safeCount(usage.costUsdTicks);
|
|
7330
|
+
const cost = !isIncomplete && costTicks > 0 ? costTicks / USD_TICKS_PER_USD : null;
|
|
7331
|
+
const modelUsage = {};
|
|
7332
|
+
const modelUsageRecord = asRecord(usage.modelUsage);
|
|
7333
|
+
if (modelUsageRecord) {
|
|
7334
|
+
for (const [model, rawUsage] of Object.entries(modelUsageRecord)) {
|
|
7335
|
+
const modelRecord = asRecord(rawUsage);
|
|
7336
|
+
if (!modelRecord) continue;
|
|
7337
|
+
const modelTotal = safeCount(modelRecord.totalTokens) || addCount(safeCount(modelRecord.inputTokens), safeCount(modelRecord.outputTokens));
|
|
7338
|
+
if (modelTotal > 0) modelUsage[model] = modelTotal;
|
|
7339
|
+
}
|
|
7340
|
+
}
|
|
7341
|
+
const models = Object.keys(modelUsage);
|
|
7342
|
+
return {
|
|
7343
|
+
tokens: {
|
|
7344
|
+
input,
|
|
7345
|
+
output,
|
|
7346
|
+
reasoning: reasoning || void 0,
|
|
7347
|
+
cache_read: cacheRead || void 0,
|
|
7348
|
+
cache_create: cacheCreate || void 0
|
|
7349
|
+
},
|
|
7350
|
+
totalTokens,
|
|
7351
|
+
cost,
|
|
7352
|
+
modelUsage,
|
|
7353
|
+
primaryModel: models.length === 1 ? models[0] : null
|
|
7354
|
+
};
|
|
7355
|
+
}
|
|
7356
|
+
function textFromContentBlock(value) {
|
|
7357
|
+
const content = asRecord(value);
|
|
7358
|
+
if (!content) return "";
|
|
7359
|
+
if (content.type === "text") return asString(content.text) ?? "";
|
|
7360
|
+
const resource = asRecord(content.resource);
|
|
7361
|
+
return asString(resource?.text) ?? "";
|
|
7362
|
+
}
|
|
7363
|
+
function messagePartFromContentBlock(value, timestampMs) {
|
|
7364
|
+
const content = asRecord(value);
|
|
7365
|
+
if (!content) return null;
|
|
7366
|
+
if (content.type === "text") {
|
|
7367
|
+
const text2 = asString(content.text) ?? "";
|
|
7368
|
+
return text2 ? { type: "text", text: text2, time_created: timestampMs } : null;
|
|
7369
|
+
}
|
|
7370
|
+
if (content.type === "image") {
|
|
7371
|
+
const data = asString(content.data);
|
|
7372
|
+
const url = asString(content.uri) ?? asString(content.url);
|
|
7373
|
+
const mimeType = asString(content.mimeType) ?? asString(content.mime_type);
|
|
7374
|
+
if (data && mimeType) {
|
|
7375
|
+
return { type: "image", data, mime_type: mimeType, url, time_created: timestampMs };
|
|
7376
|
+
}
|
|
7377
|
+
if (url) return { type: "image", url, mime_type: mimeType, time_created: timestampMs };
|
|
7378
|
+
}
|
|
7379
|
+
const text = textFromContentBlock(content);
|
|
7380
|
+
return text ? { type: "text", text, time_created: timestampMs } : null;
|
|
7381
|
+
}
|
|
7382
|
+
var GrokMessageCounter = class {
|
|
7383
|
+
firstUserText = null;
|
|
7384
|
+
messageCount = 0;
|
|
7385
|
+
activeAssistant = false;
|
|
7386
|
+
activeAssistantPromptId = null;
|
|
7387
|
+
activeUser = false;
|
|
7388
|
+
activeUserPromptIndex = null;
|
|
7389
|
+
process(envelope) {
|
|
7390
|
+
if (envelope.method === XAI_UPDATE_METHOD) return;
|
|
7391
|
+
switch (updateType(envelope)) {
|
|
7392
|
+
case "user_message_chunk":
|
|
7393
|
+
this.appendUser(envelope);
|
|
7394
|
+
break;
|
|
7395
|
+
case "agent_thought_chunk":
|
|
7396
|
+
case "agent_message_chunk":
|
|
7397
|
+
if (cleanInternalText(textFromContentBlock(envelope.update.content))) {
|
|
7398
|
+
this.appendAssistant(envelope);
|
|
7399
|
+
}
|
|
7400
|
+
break;
|
|
7401
|
+
case "tool_call":
|
|
7402
|
+
if (asString(envelope.update.toolCallId)?.trim()) this.appendAssistant(envelope);
|
|
7403
|
+
break;
|
|
7404
|
+
case "plan":
|
|
7405
|
+
if (planPart(envelope.update, envelope.timestampMs)) this.appendAssistant(envelope);
|
|
7406
|
+
break;
|
|
7407
|
+
}
|
|
7408
|
+
}
|
|
7409
|
+
appendUser(envelope) {
|
|
7410
|
+
if (isHostTurn(envelope.update)) return;
|
|
7411
|
+
const part = messagePartFromContentBlock(envelope.update.content, envelope.timestampMs);
|
|
7412
|
+
if (!part) return;
|
|
7413
|
+
if (part.type === "text" && !cleanInternalText(part.text)) return;
|
|
7414
|
+
const promptIndexValue = asNumber(asRecord(envelope.update._meta)?.promptIndex);
|
|
7415
|
+
const promptIndex = promptIndexValue !== void 0 && Number.isSafeInteger(promptIndexValue) ? promptIndexValue : null;
|
|
7416
|
+
const canReuse = this.activeUser && (promptIndex === null || this.activeUserPromptIndex === null || promptIndex === this.activeUserPromptIndex);
|
|
7417
|
+
if (!canReuse) this.messageCount += 1;
|
|
7418
|
+
if (this.firstUserText === null && part.type === "text") {
|
|
7419
|
+
this.firstUserText = cleanInternalText(part.text) || null;
|
|
7420
|
+
}
|
|
7421
|
+
this.activeUser = true;
|
|
7422
|
+
this.activeUserPromptIndex = promptIndex;
|
|
7423
|
+
this.activeAssistant = false;
|
|
7424
|
+
this.activeAssistantPromptId = null;
|
|
7425
|
+
}
|
|
7426
|
+
appendAssistant(envelope) {
|
|
7427
|
+
const promptId = asString(asRecord(envelope.params._meta)?.promptId)?.trim() || null;
|
|
7428
|
+
if (promptId && this.activeAssistantPromptId && promptId !== this.activeAssistantPromptId) {
|
|
7429
|
+
this.activeAssistant = false;
|
|
7430
|
+
}
|
|
7431
|
+
if (promptId) this.activeAssistantPromptId = promptId;
|
|
7432
|
+
this.activeUser = false;
|
|
7433
|
+
this.activeUserPromptIndex = null;
|
|
7434
|
+
if (!this.activeAssistant) this.messageCount += 1;
|
|
7435
|
+
this.activeAssistant = true;
|
|
7436
|
+
}
|
|
7437
|
+
};
|
|
7438
|
+
function scanCanonicalMessages(updatesPath, fallbackTimestampMs) {
|
|
7439
|
+
const rewindIndex = new RewindIndex();
|
|
7440
|
+
let recordIndex = 0;
|
|
7441
|
+
for (const record of readJsonlFile(updatesPath)) {
|
|
7442
|
+
rewindIndex.process(record, recordIndex, fallbackTimestampMs);
|
|
7443
|
+
recordIndex += 1;
|
|
7444
|
+
}
|
|
7445
|
+
const survivingIndexes = new Set(rewindIndex.survivingRecordIndexes);
|
|
7446
|
+
const counter = new GrokMessageCounter();
|
|
7447
|
+
recordIndex = 0;
|
|
7448
|
+
for (const record of readJsonlFile(updatesPath)) {
|
|
7449
|
+
if (survivingIndexes.has(recordIndex)) {
|
|
7450
|
+
const envelope = unpackUpdate(record, fallbackTimestampMs);
|
|
7451
|
+
if (envelope) counter.process(envelope);
|
|
7452
|
+
}
|
|
7453
|
+
recordIndex += 1;
|
|
7454
|
+
}
|
|
7455
|
+
return counter;
|
|
7456
|
+
}
|
|
7457
|
+
function scanHeadData(updatesPath, fallbackTimestampMs) {
|
|
7458
|
+
let totalInputTokens = 0;
|
|
7459
|
+
let totalOutputTokens = 0;
|
|
7460
|
+
let totalCacheReadTokens = 0;
|
|
7461
|
+
let totalCacheCreateTokens = 0;
|
|
7462
|
+
let totalTokens = 0;
|
|
7463
|
+
let totalCost = 0;
|
|
7464
|
+
let hasUnknownCost = false;
|
|
7465
|
+
let hasRewinds = false;
|
|
7466
|
+
const modelUsage = {};
|
|
7467
|
+
let messageCounter = new GrokMessageCounter();
|
|
7468
|
+
if (updatesPath && existsSync12(updatesPath)) {
|
|
7469
|
+
for (const line of readJsonlFileLines(updatesPath)) {
|
|
7470
|
+
const affectsMessages = line.includes('"user_message_chunk"') || line.includes('"agent_thought_chunk"') || line.includes('"agent_message_chunk"') || line.includes('"tool_call"') || line.includes('"plan"');
|
|
7471
|
+
const isTurnCompleted = line.includes('"turn_completed"');
|
|
7472
|
+
const isRewind = line.includes('"rewind_marker"');
|
|
7473
|
+
if (!affectsMessages && !isTurnCompleted && !isRewind) continue;
|
|
7474
|
+
let record;
|
|
7475
|
+
try {
|
|
7476
|
+
record = asRecord(JSON.parse(line)) ?? {};
|
|
7477
|
+
} catch {
|
|
7478
|
+
continue;
|
|
7479
|
+
}
|
|
7480
|
+
const envelope = unpackUpdate(record, fallbackTimestampMs);
|
|
7481
|
+
if (!envelope) continue;
|
|
7482
|
+
const type = updateType(envelope);
|
|
7483
|
+
if (affectsMessages) messageCounter.process(envelope);
|
|
7484
|
+
if (envelope.method === XAI_UPDATE_METHOD && type === "rewind_marker") {
|
|
7485
|
+
hasRewinds = true;
|
|
7486
|
+
}
|
|
7487
|
+
if (envelope.method !== XAI_UPDATE_METHOD || type !== "turn_completed") continue;
|
|
7488
|
+
const usage = parseUsage(envelope.update);
|
|
7489
|
+
if (!usage) continue;
|
|
7490
|
+
totalInputTokens = addCount(totalInputTokens, usage.tokens.input ?? 0);
|
|
7491
|
+
totalOutputTokens = addCount(totalOutputTokens, usage.tokens.output ?? 0);
|
|
7492
|
+
totalCacheReadTokens = addCount(totalCacheReadTokens, usage.tokens.cache_read ?? 0);
|
|
7493
|
+
totalCacheCreateTokens = addCount(totalCacheCreateTokens, usage.tokens.cache_create ?? 0);
|
|
7494
|
+
totalTokens = addCount(totalTokens, usage.totalTokens);
|
|
7495
|
+
if (usage.cost === null && usage.totalTokens > 0) hasUnknownCost = true;
|
|
7496
|
+
else totalCost += usage.cost ?? 0;
|
|
7497
|
+
for (const [model, tokens] of Object.entries(usage.modelUsage)) {
|
|
7498
|
+
modelUsage[model] = addCount(modelUsage[model] ?? 0, tokens);
|
|
7499
|
+
}
|
|
7500
|
+
}
|
|
7501
|
+
if (hasRewinds) messageCounter = scanCanonicalMessages(updatesPath, fallbackTimestampMs);
|
|
7502
|
+
}
|
|
7503
|
+
return {
|
|
7504
|
+
firstUserText: messageCounter.firstUserText,
|
|
7505
|
+
visibleMessageCount: messageCounter.messageCount,
|
|
7506
|
+
stats: {
|
|
7507
|
+
total_input_tokens: totalInputTokens,
|
|
7508
|
+
total_output_tokens: totalOutputTokens,
|
|
7509
|
+
total_cache_read_tokens: totalCacheReadTokens || void 0,
|
|
7510
|
+
total_cache_create_tokens: totalCacheCreateTokens || void 0,
|
|
7511
|
+
total_tokens: totalTokens || addCount(totalInputTokens, totalOutputTokens),
|
|
7512
|
+
total_cost: totalCost,
|
|
7513
|
+
cost_source: totalCost > 0 && !hasUnknownCost ? "recorded" : void 0
|
|
7514
|
+
},
|
|
7515
|
+
modelUsage
|
|
7516
|
+
};
|
|
7517
|
+
}
|
|
7518
|
+
function toolTitle(toolName) {
|
|
7519
|
+
return GROK_TOOL_TITLE_MAP[toolName] ?? toolName;
|
|
7520
|
+
}
|
|
7521
|
+
function toolStatus(value) {
|
|
7522
|
+
switch (asString(value)?.toLowerCase()) {
|
|
7523
|
+
case "completed":
|
|
7524
|
+
return "completed";
|
|
7525
|
+
case "failed":
|
|
7526
|
+
return "error";
|
|
7527
|
+
case "in_progress":
|
|
7528
|
+
case "pending":
|
|
7529
|
+
return "running";
|
|
7530
|
+
default:
|
|
7531
|
+
return null;
|
|
7532
|
+
}
|
|
7533
|
+
}
|
|
7534
|
+
function toolOutput(update) {
|
|
7535
|
+
if (update.rawOutput !== void 0 && update.rawOutput !== null) return update.rawOutput;
|
|
7536
|
+
const content = asArray(update.content);
|
|
7537
|
+
if (!content) return void 0;
|
|
7538
|
+
const texts = content.flatMap((item) => {
|
|
7539
|
+
const wrapper = asRecord(item);
|
|
7540
|
+
const block = wrapper?.type === "content" ? wrapper.content : item;
|
|
7541
|
+
const text = textFromContentBlock(block);
|
|
7542
|
+
return text ? [text] : [];
|
|
7543
|
+
});
|
|
7544
|
+
if (texts.length === 0) return content;
|
|
7545
|
+
return texts.join("\n");
|
|
7546
|
+
}
|
|
7547
|
+
function planPart(update, timestampMs) {
|
|
7548
|
+
const entries = asArray(update.entries)?.flatMap((value) => {
|
|
7549
|
+
const entry = asRecord(value);
|
|
7550
|
+
const content = cleanInternalText(asString(entry?.content) ?? "");
|
|
7551
|
+
if (!entry || !content) return [];
|
|
7552
|
+
return [{ content, status: asString(entry.status) ?? "pending" }];
|
|
7553
|
+
});
|
|
7554
|
+
if (!entries || entries.length === 0) return null;
|
|
7555
|
+
const text = entries.map(({ content, status }) => `- [${status === "completed" ? "x" : " "}] ${content}`).join("\n");
|
|
7556
|
+
return {
|
|
7557
|
+
type: "plan",
|
|
7558
|
+
text,
|
|
7559
|
+
approval_status: entries.every(({ status }) => status === "completed") ? "success" : "fail",
|
|
7560
|
+
time_created: timestampMs
|
|
7561
|
+
};
|
|
7562
|
+
}
|
|
7563
|
+
var GrokTranscriptReducer = class {
|
|
7564
|
+
constructor(sessionId, currentModel, fallbackTimestampMs) {
|
|
7565
|
+
this.sessionId = sessionId;
|
|
7566
|
+
this.fallbackTimestampMs = fallbackTimestampMs;
|
|
7567
|
+
this.currentModel = currentModel;
|
|
7568
|
+
}
|
|
7569
|
+
sessionId;
|
|
7570
|
+
fallbackTimestampMs;
|
|
7571
|
+
builder = new TranscriptBuilder();
|
|
7572
|
+
activeAssistant = null;
|
|
7573
|
+
activeAssistantPromptId = null;
|
|
7574
|
+
activeUser = null;
|
|
7575
|
+
activeUserPromptIndex = null;
|
|
7576
|
+
latestPlan = null;
|
|
7577
|
+
currentMode = null;
|
|
7578
|
+
currentModel;
|
|
7579
|
+
process(record) {
|
|
7580
|
+
const envelope = unpackUpdate(record, this.fallbackTimestampMs);
|
|
7581
|
+
if (!envelope) return;
|
|
7582
|
+
if (envelope.method === XAI_UPDATE_METHOD) {
|
|
7583
|
+
this.processXaiUpdate(envelope);
|
|
7584
|
+
return;
|
|
7585
|
+
}
|
|
7586
|
+
this.processAcpUpdate(envelope);
|
|
7587
|
+
}
|
|
7588
|
+
finish(stats) {
|
|
7589
|
+
return this.builder.finish(stats);
|
|
7590
|
+
}
|
|
7591
|
+
processAcpUpdate(envelope) {
|
|
7592
|
+
switch (updateType(envelope)) {
|
|
7593
|
+
case "user_message_chunk":
|
|
7594
|
+
this.appendUserChunk(envelope);
|
|
7595
|
+
break;
|
|
7596
|
+
case "agent_thought_chunk":
|
|
7597
|
+
this.appendAssistantText(envelope, "reasoning");
|
|
7598
|
+
break;
|
|
7599
|
+
case "agent_message_chunk":
|
|
7600
|
+
this.appendAssistantText(envelope, "text");
|
|
7601
|
+
break;
|
|
7602
|
+
case "tool_call":
|
|
7603
|
+
this.appendToolCall(envelope);
|
|
7604
|
+
break;
|
|
7605
|
+
case "tool_call_update":
|
|
7606
|
+
this.updateToolCall(envelope);
|
|
7607
|
+
break;
|
|
7608
|
+
case "plan":
|
|
7609
|
+
this.updatePlan(envelope);
|
|
7610
|
+
break;
|
|
7611
|
+
case "current_mode_update":
|
|
7612
|
+
this.currentMode = asString(envelope.update.currentModeId)?.trim() || null;
|
|
7613
|
+
break;
|
|
7614
|
+
}
|
|
7615
|
+
}
|
|
7616
|
+
processXaiUpdate(envelope) {
|
|
7617
|
+
switch (updateType(envelope)) {
|
|
7618
|
+
case "turn_completed": {
|
|
7619
|
+
const usage = parseUsage(envelope.update);
|
|
7620
|
+
if (!usage) return;
|
|
7621
|
+
this.builder.attachUsageToLatestAssistant(usage.tokens, {
|
|
7622
|
+
model: usage.primaryModel ?? this.currentModel,
|
|
7623
|
+
cost: usage.cost ?? void 0,
|
|
7624
|
+
costSource: usage.cost === null ? void 0 : "recorded"
|
|
7625
|
+
});
|
|
7626
|
+
return;
|
|
7627
|
+
}
|
|
7628
|
+
case "model_changed":
|
|
7629
|
+
this.currentModel = asString(envelope.update.model_id)?.trim() || this.currentModel;
|
|
7630
|
+
return;
|
|
7631
|
+
case "model_auto_switched":
|
|
7632
|
+
this.currentModel = asString(envelope.update.new_model_id)?.trim() || this.currentModel;
|
|
7633
|
+
return;
|
|
7634
|
+
case "subagent_spawned": {
|
|
7635
|
+
const childSessionId = asString(envelope.update.child_session_id)?.trim();
|
|
7636
|
+
if (childSessionId && this.activeAssistant && !this.activeAssistant.subagent_id) {
|
|
7637
|
+
this.activeAssistant.subagent_id = childSessionId;
|
|
7638
|
+
}
|
|
7639
|
+
}
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
appendUserChunk(envelope) {
|
|
7643
|
+
if (isHostTurn(envelope.update)) return;
|
|
7644
|
+
const part = messagePartFromContentBlock(envelope.update.content, envelope.timestampMs);
|
|
7645
|
+
if (!part) return;
|
|
7646
|
+
const promptIndexValue = asNumber(asRecord(envelope.update._meta)?.promptIndex);
|
|
7647
|
+
const promptIndex = promptIndexValue !== void 0 && Number.isSafeInteger(promptIndexValue) ? promptIndexValue : null;
|
|
7648
|
+
const canReuse = this.activeUser !== null && (promptIndex === null || this.activeUserPromptIndex === null || promptIndex === this.activeUserPromptIndex);
|
|
7649
|
+
if (canReuse) {
|
|
7650
|
+
const tail = this.activeUser.parts.at(-1);
|
|
7651
|
+
if (tail?.type === "text" && part.type === "text") tail.text += part.text;
|
|
7652
|
+
else this.activeUser.parts.push(part);
|
|
7653
|
+
} else {
|
|
7654
|
+
const eventId = asString(asRecord(envelope.params._meta)?.eventId);
|
|
7655
|
+
this.activeUser = this.builder.appendMessage({
|
|
7656
|
+
id: eventId || `${this.sessionId}-user-${envelope.timestampMs}`,
|
|
7657
|
+
role: "user",
|
|
7658
|
+
timestampMs: envelope.timestampMs,
|
|
7659
|
+
parts: [part]
|
|
7660
|
+
});
|
|
7661
|
+
}
|
|
7662
|
+
this.activeUserPromptIndex = promptIndex;
|
|
7663
|
+
this.activeAssistant = null;
|
|
7664
|
+
this.activeAssistantPromptId = null;
|
|
7665
|
+
this.latestPlan = null;
|
|
7666
|
+
}
|
|
7667
|
+
prepareAssistant(envelope) {
|
|
7668
|
+
const promptId = asString(asRecord(envelope.params._meta)?.promptId)?.trim() || null;
|
|
7669
|
+
if (promptId && this.activeAssistantPromptId && promptId !== this.activeAssistantPromptId) {
|
|
7670
|
+
this.builder.beginTurn();
|
|
7671
|
+
this.activeAssistant = null;
|
|
7672
|
+
this.latestPlan = null;
|
|
7673
|
+
}
|
|
7674
|
+
if (promptId) this.activeAssistantPromptId = promptId;
|
|
7675
|
+
this.activeUser = null;
|
|
7676
|
+
this.activeUserPromptIndex = null;
|
|
7677
|
+
}
|
|
7678
|
+
assistantInput(envelope) {
|
|
7679
|
+
const paramsMeta = asRecord(envelope.params._meta);
|
|
7680
|
+
return {
|
|
7681
|
+
id: asString(paramsMeta?.promptId) || asString(paramsMeta?.eventId) || `${this.sessionId}-assistant-${envelope.timestampMs}`,
|
|
7682
|
+
timestampMs: envelope.timestampMs,
|
|
7683
|
+
agent: "grok",
|
|
7684
|
+
mode: this.currentMode,
|
|
7685
|
+
model: this.currentModel,
|
|
7686
|
+
provider: "xai"
|
|
7687
|
+
};
|
|
7688
|
+
}
|
|
7689
|
+
appendAssistantText(envelope, type) {
|
|
7690
|
+
const text = textFromContentBlock(envelope.update.content);
|
|
7691
|
+
if (!text) return;
|
|
7692
|
+
this.prepareAssistant(envelope);
|
|
7693
|
+
const tail = this.activeAssistant?.parts.at(-1);
|
|
7694
|
+
if (tail?.type === type) {
|
|
7695
|
+
tail.text += text;
|
|
7696
|
+
return;
|
|
7697
|
+
}
|
|
7698
|
+
this.activeAssistant = this.builder.appendAssistantPart(
|
|
7699
|
+
{ type, text, time_created: envelope.timestampMs },
|
|
7700
|
+
this.assistantInput(envelope),
|
|
7701
|
+
{ grouping: "current" }
|
|
7702
|
+
);
|
|
7703
|
+
}
|
|
7704
|
+
appendToolCall(envelope) {
|
|
7705
|
+
const callId = asString(envelope.update.toolCallId)?.trim();
|
|
7706
|
+
const updateMeta = asRecord(envelope.update._meta);
|
|
7707
|
+
const nativeTool = asRecord(updateMeta?.["x.ai/tool"]);
|
|
7708
|
+
const name = asString(nativeTool?.name)?.trim() || asString(envelope.update.title)?.trim() || "tool";
|
|
7709
|
+
if (!callId) return;
|
|
7710
|
+
this.prepareAssistant(envelope);
|
|
7711
|
+
const metadata = {
|
|
7712
|
+
kind: asString(nativeTool?.kind) ?? asString(envelope.update.kind),
|
|
7713
|
+
locations: envelope.update.locations
|
|
7714
|
+
};
|
|
7715
|
+
const part = {
|
|
7716
|
+
type: "tool",
|
|
7717
|
+
tool: name,
|
|
7718
|
+
title: toolTitle(name),
|
|
7719
|
+
callID: callId,
|
|
7720
|
+
state: {
|
|
7721
|
+
status: toolStatus(envelope.update.status) ?? "running",
|
|
7722
|
+
input: envelope.update.rawInput,
|
|
7723
|
+
output: null,
|
|
7724
|
+
metadata
|
|
7725
|
+
},
|
|
7726
|
+
time_created: envelope.timestampMs
|
|
7727
|
+
};
|
|
7728
|
+
this.activeAssistant = this.builder.appendToolCall(part, this.assistantInput(envelope), {
|
|
7729
|
+
markModeAsTool: true,
|
|
7730
|
+
target: "current"
|
|
7731
|
+
});
|
|
7732
|
+
}
|
|
7733
|
+
updateToolCall(envelope) {
|
|
7734
|
+
const callId = asString(envelope.update.toolCallId)?.trim();
|
|
7735
|
+
if (!callId) return;
|
|
7736
|
+
this.builder.updateToolCall(callId, (part) => {
|
|
7737
|
+
const status = toolStatus(envelope.update.status);
|
|
7738
|
+
if (status) part.state.status = status;
|
|
7739
|
+
if (envelope.update.rawInput !== void 0) part.state.input = envelope.update.rawInput;
|
|
7740
|
+
const output = toolOutput(envelope.update);
|
|
7741
|
+
if (output !== void 0) {
|
|
7742
|
+
if (status === "error") part.state.error = output;
|
|
7743
|
+
else part.state.output = output;
|
|
7744
|
+
}
|
|
7745
|
+
const metadata = asRecord(part.state.metadata) ?? {};
|
|
7746
|
+
if (envelope.update.kind !== void 0) metadata.kind = envelope.update.kind;
|
|
7747
|
+
if (envelope.update.locations !== void 0) metadata.locations = envelope.update.locations;
|
|
7748
|
+
part.state.metadata = metadata;
|
|
7749
|
+
});
|
|
7750
|
+
}
|
|
7751
|
+
updatePlan(envelope) {
|
|
7752
|
+
const part = planPart(envelope.update, envelope.timestampMs);
|
|
7753
|
+
if (!part) return;
|
|
7754
|
+
this.prepareAssistant(envelope);
|
|
7755
|
+
if (this.latestPlan) {
|
|
7756
|
+
this.latestPlan.text = part.text;
|
|
7757
|
+
this.latestPlan.approval_status = part.approval_status;
|
|
7758
|
+
this.latestPlan.time_created = part.time_created;
|
|
7759
|
+
return;
|
|
7760
|
+
}
|
|
7761
|
+
this.latestPlan = part;
|
|
7762
|
+
this.activeAssistant = this.builder.appendAssistantPart(part, this.assistantInput(envelope), {
|
|
7763
|
+
grouping: "current"
|
|
7764
|
+
});
|
|
7765
|
+
}
|
|
7766
|
+
};
|
|
7767
|
+
var UserRunTracker = class {
|
|
7768
|
+
hasSeenPromptIndex = false;
|
|
7769
|
+
isInUserRun = false;
|
|
7770
|
+
currentPromptIndex = null;
|
|
7771
|
+
onUser(promptIndex) {
|
|
7772
|
+
if (promptIndex !== null) this.hasSeenPromptIndex = true;
|
|
7773
|
+
const isCounted = this.hasSeenPromptIndex ? promptIndex !== null : true;
|
|
7774
|
+
const isNewRun = !this.isInUserRun || (this.hasSeenPromptIndex || promptIndex !== null) && promptIndex !== this.currentPromptIndex;
|
|
7775
|
+
this.isInUserRun = true;
|
|
7776
|
+
if (!isNewRun) return false;
|
|
7777
|
+
this.currentPromptIndex = promptIndex;
|
|
7778
|
+
return isCounted;
|
|
7779
|
+
}
|
|
7780
|
+
onNonUser() {
|
|
7781
|
+
this.isInUserRun = false;
|
|
7782
|
+
this.currentPromptIndex = null;
|
|
7783
|
+
}
|
|
7784
|
+
};
|
|
7785
|
+
var RewindIndex = class {
|
|
7786
|
+
survivingRecordIndexes = [];
|
|
7787
|
+
hasRewinds = false;
|
|
7788
|
+
promptStarts = [];
|
|
7789
|
+
userRuns = new UserRunTracker();
|
|
7790
|
+
process(record, recordIndex, fallbackTimestampMs) {
|
|
7791
|
+
const envelope = unpackUpdate(record, fallbackTimestampMs);
|
|
7792
|
+
if (!envelope) {
|
|
7793
|
+
this.userRuns.onNonUser();
|
|
7794
|
+
this.survivingRecordIndexes.push(recordIndex);
|
|
7795
|
+
return;
|
|
7796
|
+
}
|
|
7797
|
+
const type = updateType(envelope);
|
|
7798
|
+
if (envelope.method === XAI_UPDATE_METHOD && type === "rewind_marker") {
|
|
7799
|
+
const target = asNumber(envelope.update.target_prompt_index);
|
|
7800
|
+
if (target === void 0 || !Number.isSafeInteger(target) || target < 0) {
|
|
7801
|
+
this.userRuns.onNonUser();
|
|
7802
|
+
this.survivingRecordIndexes.push(recordIndex);
|
|
7803
|
+
return;
|
|
7804
|
+
}
|
|
7805
|
+
const truncateAt = this.promptStarts[target] ?? this.survivingRecordIndexes.length;
|
|
7806
|
+
this.survivingRecordIndexes.length = truncateAt;
|
|
7807
|
+
this.promptStarts.length = Math.min(this.promptStarts.length, target);
|
|
7808
|
+
this.userRuns.onNonUser();
|
|
7809
|
+
this.hasRewinds = true;
|
|
7810
|
+
return;
|
|
7811
|
+
}
|
|
7812
|
+
if (envelope.method !== XAI_UPDATE_METHOD && type === "user_message_chunk" && !isHostTurn(envelope.update)) {
|
|
7813
|
+
const rawPromptIndex = asNumber(asRecord(envelope.update._meta)?.promptIndex);
|
|
7814
|
+
const promptIndex = rawPromptIndex !== void 0 && Number.isSafeInteger(rawPromptIndex) && rawPromptIndex >= 0 ? rawPromptIndex : null;
|
|
7815
|
+
if (this.userRuns.onUser(promptIndex)) {
|
|
7816
|
+
this.promptStarts.push(this.survivingRecordIndexes.length);
|
|
7817
|
+
}
|
|
7818
|
+
} else {
|
|
7819
|
+
this.userRuns.onNonUser();
|
|
7820
|
+
}
|
|
7821
|
+
this.survivingRecordIndexes.push(recordIndex);
|
|
7822
|
+
}
|
|
7823
|
+
};
|
|
7824
|
+
function parseTranscript(meta) {
|
|
7825
|
+
const reducer = new GrokTranscriptReducer(meta.id, meta.currentModel, meta.createdAt);
|
|
7826
|
+
if (!meta.updatesPath || !existsSync12(meta.updatesPath)) return reducer.finish(meta.stats);
|
|
7827
|
+
const rewindIndex = new RewindIndex();
|
|
7828
|
+
let recordIndex = 0;
|
|
7829
|
+
for (const record of readJsonlFile(meta.updatesPath)) {
|
|
7830
|
+
rewindIndex.process(record, recordIndex, meta.createdAt);
|
|
7831
|
+
reducer.process(record);
|
|
7832
|
+
recordIndex += 1;
|
|
7833
|
+
}
|
|
7834
|
+
if (!rewindIndex.hasRewinds) return reducer.finish(meta.stats);
|
|
7835
|
+
const survivingIndexes = new Set(rewindIndex.survivingRecordIndexes);
|
|
7836
|
+
const replay = new GrokTranscriptReducer(meta.id, meta.currentModel, meta.createdAt);
|
|
7837
|
+
recordIndex = 0;
|
|
7838
|
+
for (const record of readJsonlFile(meta.updatesPath)) {
|
|
7839
|
+
if (survivingIndexes.has(recordIndex)) replay.process(record);
|
|
7840
|
+
recordIndex += 1;
|
|
7841
|
+
}
|
|
7842
|
+
return replay.finish(meta.stats);
|
|
7843
|
+
}
|
|
7844
|
+
var GrokAgent = class extends FileSystemSessionSource {
|
|
7845
|
+
name = "grok";
|
|
7846
|
+
displayName = "Grok";
|
|
7847
|
+
basePath = null;
|
|
7848
|
+
findBasePath() {
|
|
7849
|
+
return firstExisting(join14(resolveGrokDataRoot(), "sessions"), "data/grok");
|
|
7850
|
+
}
|
|
7851
|
+
isAvailable() {
|
|
7852
|
+
this.basePath = this.findBasePath();
|
|
7853
|
+
return this.basePath !== null && this.listSessionSources().length > 0;
|
|
7854
|
+
}
|
|
7855
|
+
getSessionWatchPlan() {
|
|
7856
|
+
const dataRoot = resolveGrokDataRoot();
|
|
7857
|
+
return {
|
|
7858
|
+
status: "supported",
|
|
7859
|
+
targets: [{ root: dataRoot, path: join14(dataRoot, "sessions") }, { path: "data/grok" }]
|
|
7860
|
+
};
|
|
7861
|
+
}
|
|
7862
|
+
listSessionSources(options) {
|
|
7863
|
+
this.basePath ??= this.findBasePath();
|
|
7864
|
+
if (!this.basePath) return [];
|
|
7865
|
+
const sources = this.walkFiles(this.basePath, (entry) => entry.name === SUMMARY_FILE);
|
|
7866
|
+
return sources.flatMap((source) => {
|
|
7867
|
+
const summary = parseSummary(source);
|
|
7868
|
+
if (!summary || !matchesScanWindow(summary.updatedAt, options)) return [];
|
|
7869
|
+
return [
|
|
7870
|
+
{
|
|
7871
|
+
sessionId: summary.id,
|
|
7872
|
+
sourcePath: source.file,
|
|
7873
|
+
fingerprint: this.sourceFingerprint(source)
|
|
7874
|
+
}
|
|
7875
|
+
];
|
|
7876
|
+
});
|
|
7877
|
+
}
|
|
7878
|
+
scanSessionSource(sourcePath) {
|
|
7879
|
+
const source = this.sessionSourceFile(sourcePath);
|
|
7880
|
+
const summary = parseSummary(source);
|
|
7881
|
+
if (!summary) return null;
|
|
7882
|
+
const sessionDir = dirname6(source.file);
|
|
7883
|
+
const updatesPath = join14(sessionDir, UPDATES_FILE);
|
|
7884
|
+
const existingUpdatesPath = existsSync12(updatesPath) ? updatesPath : null;
|
|
7885
|
+
const headData = scanHeadData(existingUpdatesPath, summary.createdAt);
|
|
7886
|
+
const messageCount = headData.visibleMessageCount || summary.messageCount;
|
|
7887
|
+
if (messageCount === 0) return null;
|
|
7888
|
+
const title = resolveSessionTitle(
|
|
7889
|
+
summary.title,
|
|
7890
|
+
headData.firstUserText,
|
|
7891
|
+
basenameTitle(summary.cwd)
|
|
7892
|
+
);
|
|
7893
|
+
const stats = { message_count: messageCount, ...headData.stats };
|
|
7894
|
+
const fingerprint = this.sourceFingerprint(source);
|
|
7895
|
+
const head = {
|
|
7896
|
+
id: summary.id,
|
|
7897
|
+
slug: `grok/${summary.id}`,
|
|
7898
|
+
title,
|
|
7899
|
+
directory: summary.cwd,
|
|
7900
|
+
parent_reference: summary.parentSessionId ? { agentName: this.name, sessionId: summary.parentSessionId } : void 0,
|
|
7901
|
+
time_created: summary.createdAt,
|
|
7902
|
+
time_updated: summary.updatedAt,
|
|
7903
|
+
stats,
|
|
7904
|
+
model_usage: Object.keys(headData.modelUsage).length > 0 ? headData.modelUsage : void 0
|
|
7905
|
+
};
|
|
7906
|
+
this.sessionMetaMap.set(summary.id, {
|
|
7907
|
+
id: summary.id,
|
|
7908
|
+
title,
|
|
7909
|
+
sourcePath: source.file,
|
|
7910
|
+
sourceFingerprint: fingerprint,
|
|
7911
|
+
sourceMtimeMs: summary.updatedAt,
|
|
7912
|
+
directory: summary.cwd,
|
|
7913
|
+
messageCount,
|
|
7914
|
+
createdAt: summary.createdAt,
|
|
7915
|
+
updatedAt: summary.updatedAt,
|
|
7916
|
+
currentModel: summary.currentModel,
|
|
7917
|
+
parentSessionId: summary.parentSessionId,
|
|
7918
|
+
updatesPath: existingUpdatesPath,
|
|
7919
|
+
stats
|
|
7920
|
+
});
|
|
7921
|
+
return head;
|
|
7922
|
+
}
|
|
7923
|
+
getSessionData(sessionId) {
|
|
7924
|
+
const meta = this.sessionMetaMap.get(sessionId);
|
|
7925
|
+
if (!meta) throw new Error(`Session not found: ${sessionId}`);
|
|
7926
|
+
const transcript = parseTranscript(meta);
|
|
7927
|
+
return {
|
|
7928
|
+
reference: { agentName: this.name, sessionId: meta.id },
|
|
7929
|
+
id: meta.id,
|
|
7930
|
+
title: meta.title,
|
|
7931
|
+
slug: `grok/${meta.id}`,
|
|
7932
|
+
directory: meta.directory,
|
|
7933
|
+
parent_reference: meta.parentSessionId ? { agentName: this.name, sessionId: meta.parentSessionId } : void 0,
|
|
7934
|
+
version: void 0,
|
|
7935
|
+
time_created: meta.createdAt,
|
|
7936
|
+
time_updated: meta.updatedAt,
|
|
7937
|
+
stats: transcript.stats,
|
|
7938
|
+
messages: transcript.messages
|
|
7939
|
+
};
|
|
7940
|
+
}
|
|
7941
|
+
sourceFingerprint(source) {
|
|
7942
|
+
const sessionDir = dirname6(source.file);
|
|
7943
|
+
return JSON.stringify([
|
|
7944
|
+
HEAD_INDEX_VERSION4,
|
|
7945
|
+
PARSER_VERSION3,
|
|
7946
|
+
source.stat.mtimeMs,
|
|
7947
|
+
source.stat.size,
|
|
7948
|
+
optionalFileFingerprint(join14(sessionDir, UPDATES_FILE))
|
|
7949
|
+
]);
|
|
7950
|
+
}
|
|
7951
|
+
};
|
|
7084
7952
|
registerAgent({
|
|
7085
7953
|
icon: "/icon/agent/claudecode.svg",
|
|
7086
7954
|
iconColored: true,
|
|
@@ -7124,6 +7992,13 @@ registerAgent({
|
|
|
7124
7992
|
toolStrategy: "custom",
|
|
7125
7993
|
create: () => new CodexAgent()
|
|
7126
7994
|
});
|
|
7995
|
+
registerAgent({
|
|
7996
|
+
icon: "/icon/agent/grok.svg",
|
|
7997
|
+
resolveDataRoot: resolveGrokDataRoot,
|
|
7998
|
+
resumeCommandPrefix: "grok --resume",
|
|
7999
|
+
toolStrategy: "custom",
|
|
8000
|
+
create: () => new GrokAgent()
|
|
8001
|
+
});
|
|
7127
8002
|
registerAgent({
|
|
7128
8003
|
icon: "/icon/agent/pi.svg",
|
|
7129
8004
|
resolveDataRoot: resolvePiDataRoot,
|
|
@@ -7146,11 +8021,11 @@ function fallbackDisplayName(input) {
|
|
|
7146
8021
|
}
|
|
7147
8022
|
var realFs = {
|
|
7148
8023
|
exists(path2) {
|
|
7149
|
-
return
|
|
8024
|
+
return existsSync13(path2);
|
|
7150
8025
|
},
|
|
7151
8026
|
readText(path2) {
|
|
7152
8027
|
try {
|
|
7153
|
-
return
|
|
8028
|
+
return readFileSync8(path2, "utf8");
|
|
7154
8029
|
} catch {
|
|
7155
8030
|
return null;
|
|
7156
8031
|
}
|
|
@@ -7320,8 +8195,9 @@ function parseManifestName(file, text) {
|
|
|
7320
8195
|
}
|
|
7321
8196
|
function buildProjectGroups(sessions) {
|
|
7322
8197
|
const groups = /* @__PURE__ */ new Map();
|
|
8198
|
+
const tree = buildSessionTree(sessions);
|
|
7323
8199
|
for (const session of sessions) {
|
|
7324
|
-
if (
|
|
8200
|
+
if (tree.mountStateOf(session) === "mounted-child") continue;
|
|
7325
8201
|
const identity = session.project_identity;
|
|
7326
8202
|
if (!identity) continue;
|
|
7327
8203
|
const activity = session.time_updated ?? session.time_created;
|
|
@@ -7649,16 +8525,16 @@ function setSchemaEnsuredPath(path2) {
|
|
|
7649
8525
|
schemaEnsuredPath = path2;
|
|
7650
8526
|
}
|
|
7651
8527
|
function getCacheDir2() {
|
|
7652
|
-
return
|
|
8528
|
+
return join15(homedir6(), ".cache", "codesesh");
|
|
7653
8529
|
}
|
|
7654
8530
|
function getCachePath2() {
|
|
7655
|
-
return
|
|
8531
|
+
return join15(getCacheDir2(), CACHE_FILENAME);
|
|
7656
8532
|
}
|
|
7657
8533
|
function getLegacyCachePath() {
|
|
7658
|
-
return
|
|
8534
|
+
return join15(getCacheDir2(), LEGACY_CACHE_FILENAME);
|
|
7659
8535
|
}
|
|
7660
8536
|
function hasCacheStorage() {
|
|
7661
|
-
return
|
|
8537
|
+
return existsSync14(getCachePath2());
|
|
7662
8538
|
}
|
|
7663
8539
|
function likePattern(value) {
|
|
7664
8540
|
return `%${value.trim().toLowerCase().replace(/[\\%_]/g, "\\$&")}%`;
|
|
@@ -7806,7 +8682,7 @@ function prepareUpsertIndexedSession(db) {
|
|
|
7806
8682
|
}
|
|
7807
8683
|
function upsertSessionRow(statement, agentName, session, metaJson, sortIndex, sourcePath) {
|
|
7808
8684
|
const identity = session.project_identity ?? computeIdentity(session.directory, realFs);
|
|
7809
|
-
const
|
|
8685
|
+
const activityTime2 = session.time_updated ?? session.time_created;
|
|
7810
8686
|
statement.run(
|
|
7811
8687
|
agentName,
|
|
7812
8688
|
session.id,
|
|
@@ -7822,7 +8698,7 @@ function upsertSessionRow(statement, agentName, session, metaJson, sortIndex, so
|
|
|
7822
8698
|
identity.displayName,
|
|
7823
8699
|
session.time_created,
|
|
7824
8700
|
session.time_updated ?? null,
|
|
7825
|
-
|
|
8701
|
+
activityTime2,
|
|
7826
8702
|
session.stats.message_count,
|
|
7827
8703
|
session.stats.total_input_tokens,
|
|
7828
8704
|
session.stats.total_output_tokens,
|
|
@@ -8130,7 +9006,9 @@ function withCacheDb(fn) {
|
|
|
8130
9006
|
return fn(db);
|
|
8131
9007
|
} catch (error) {
|
|
8132
9008
|
getCoreDiagnostics()?.warn("cache.write_failed", {
|
|
8133
|
-
message: error instanceof Error ? error.message : String(error)
|
|
9009
|
+
message: error instanceof Error ? error.message : String(error),
|
|
9010
|
+
code: error?.code,
|
|
9011
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
8134
9012
|
});
|
|
8135
9013
|
return null;
|
|
8136
9014
|
} finally {
|
|
@@ -8171,7 +9049,7 @@ function runSearchIndexWrite(db, rebuild, write) {
|
|
|
8171
9049
|
createMessageSearchTriggers(db);
|
|
8172
9050
|
}
|
|
8173
9051
|
return { value, rebuildDurationMs };
|
|
8174
|
-
})();
|
|
9052
|
+
}).immediate();
|
|
8175
9053
|
}
|
|
8176
9054
|
function createCacheTables(db) {
|
|
8177
9055
|
db.exec(`
|
|
@@ -9182,7 +10060,7 @@ function ensureSchema(db, dbPath) {
|
|
|
9182
10060
|
]
|
|
9183
10061
|
});
|
|
9184
10062
|
createLatestCacheSchema(db);
|
|
9185
|
-
if (getUserVersion(db)
|
|
10063
|
+
if (getUserVersion(db) < CACHE_SCHEMA_VERSION) {
|
|
9186
10064
|
setCacheSchemaVersion(db);
|
|
9187
10065
|
}
|
|
9188
10066
|
migrateCodexExecDecode(db);
|
|
@@ -10240,7 +11118,7 @@ function parseCachedSessionMeta(value) {
|
|
|
10240
11118
|
}
|
|
10241
11119
|
function deleteLegacyCacheFile() {
|
|
10242
11120
|
const legacyPath = getLegacyCachePath();
|
|
10243
|
-
if (!
|
|
11121
|
+
if (!existsSync15(legacyPath)) {
|
|
10244
11122
|
return;
|
|
10245
11123
|
}
|
|
10246
11124
|
try {
|
|
@@ -10532,7 +11410,7 @@ function saveCachedSessions(agentName, sessions, meta = {}) {
|
|
|
10532
11410
|
);
|
|
10533
11411
|
});
|
|
10534
11412
|
});
|
|
10535
|
-
write();
|
|
11413
|
+
write.immediate();
|
|
10536
11414
|
deleteLegacyCacheFile();
|
|
10537
11415
|
return true;
|
|
10538
11416
|
});
|
|
@@ -10583,7 +11461,7 @@ function saveCachedSessionChanges(agentName, changes, removedSessionIds, meta =
|
|
|
10583
11461
|
);
|
|
10584
11462
|
}
|
|
10585
11463
|
});
|
|
10586
|
-
write();
|
|
11464
|
+
write.immediate();
|
|
10587
11465
|
deleteLegacyCacheFile();
|
|
10588
11466
|
return true;
|
|
10589
11467
|
});
|
|
@@ -10613,7 +11491,7 @@ function clearCache() {
|
|
|
10613
11491
|
const walPath = `${cachePath}-wal`;
|
|
10614
11492
|
const shmPath = `${cachePath}-shm`;
|
|
10615
11493
|
for (const filePath of [walPath, shmPath]) {
|
|
10616
|
-
if (!
|
|
11494
|
+
if (!existsSync15(filePath)) {
|
|
10617
11495
|
continue;
|
|
10618
11496
|
}
|
|
10619
11497
|
try {
|
|
@@ -11184,6 +12062,66 @@ function listCachedProjectGroups(sessions) {
|
|
|
11184
12062
|
lastActivity: row.last_activity == null ? null : Number(row.last_activity)
|
|
11185
12063
|
}));
|
|
11186
12064
|
}
|
|
12065
|
+
var DEFAULT_MODEL_COST_LIMIT = 20;
|
|
12066
|
+
function buildModelCostWhere(options) {
|
|
12067
|
+
const clauses = ["m.model IS NOT NULL", "m.model <> ''"];
|
|
12068
|
+
const params = [];
|
|
12069
|
+
if (options.agent != null) {
|
|
12070
|
+
clauses.push("s.agent_name = ?");
|
|
12071
|
+
params.push(options.agent);
|
|
12072
|
+
}
|
|
12073
|
+
if (options.projectKind != null || options.projectKey != null) {
|
|
12074
|
+
if (options.projectKind != null && options.projectKey != null) {
|
|
12075
|
+
clauses.push("s.project_identity_kind = ? AND s.project_identity_key = ?");
|
|
12076
|
+
params.push(options.projectKind, options.projectKey);
|
|
12077
|
+
} else {
|
|
12078
|
+
clauses.push("0");
|
|
12079
|
+
}
|
|
12080
|
+
}
|
|
12081
|
+
if (options.from != null) {
|
|
12082
|
+
clauses.push("s.activity_time >= ?");
|
|
12083
|
+
params.push(options.from);
|
|
12084
|
+
}
|
|
12085
|
+
if (options.to != null) {
|
|
12086
|
+
clauses.push("s.activity_time <= ?");
|
|
12087
|
+
params.push(options.to);
|
|
12088
|
+
}
|
|
12089
|
+
return { where: `WHERE ${clauses.join(" AND ")}`, params };
|
|
12090
|
+
}
|
|
12091
|
+
var MODEL_COST_SQL = `
|
|
12092
|
+
SELECT
|
|
12093
|
+
m.model AS model,
|
|
12094
|
+
SUM(COALESCE(m.cost, 0)) AS cost,
|
|
12095
|
+
SUM(CASE WHEN m.cost_source = 'recorded' THEN COALESCE(m.cost, 0) ELSE 0 END) AS cost_recorded,
|
|
12096
|
+
SUM(CASE WHEN m.cost_source = 'recorded' THEN 0 ELSE COALESCE(m.cost, 0) END) AS cost_estimated
|
|
12097
|
+
FROM messages m
|
|
12098
|
+
JOIN sessions s ON s.agent_name = m.agent_name AND s.session_id = m.session_id
|
|
12099
|
+
`;
|
|
12100
|
+
function listModelCostDistribution(options = {}) {
|
|
12101
|
+
if (!hasCacheStorage()) {
|
|
12102
|
+
return null;
|
|
12103
|
+
}
|
|
12104
|
+
const { where, params } = buildModelCostWhere(options);
|
|
12105
|
+
const sql = `
|
|
12106
|
+
${MODEL_COST_SQL}
|
|
12107
|
+
${where}
|
|
12108
|
+
GROUP BY m.model
|
|
12109
|
+
ORDER BY cost DESC, m.model
|
|
12110
|
+
LIMIT ?
|
|
12111
|
+
`;
|
|
12112
|
+
const rows = withCacheDbReadOnly(
|
|
12113
|
+
(db) => db.prepare(sql).all(...params, options.limit ?? DEFAULT_MODEL_COST_LIMIT)
|
|
12114
|
+
);
|
|
12115
|
+
if (rows == null) {
|
|
12116
|
+
return null;
|
|
12117
|
+
}
|
|
12118
|
+
return rows.map((row) => ({
|
|
12119
|
+
model: String(row.model ?? ""),
|
|
12120
|
+
cost: Number(row.cost ?? 0),
|
|
12121
|
+
costRecorded: Number(row.cost_recorded ?? 0),
|
|
12122
|
+
costEstimated: Number(row.cost_estimated ?? 0)
|
|
12123
|
+
}));
|
|
12124
|
+
}
|
|
11187
12125
|
var STATE_DB_FILENAME = "state.db";
|
|
11188
12126
|
var STATE_SCHEMA_VERSION = 2;
|
|
11189
12127
|
var MEMORY_STATE_STORE = "memory";
|
|
@@ -11204,16 +12142,16 @@ function getStateDir() {
|
|
|
11204
12142
|
if (process.env.CODESESH_STATE_DIR) return process.env.CODESESH_STATE_DIR;
|
|
11205
12143
|
const currentPlatform = platform4();
|
|
11206
12144
|
if (currentPlatform === "darwin") {
|
|
11207
|
-
return
|
|
12145
|
+
return join16(homedir7(), "Library", "Application Support", "codesesh");
|
|
11208
12146
|
}
|
|
11209
12147
|
if (currentPlatform === "win32") {
|
|
11210
12148
|
const appData = process.env.APPDATA ?? process.env.LOCALAPPDATA;
|
|
11211
|
-
return
|
|
12149
|
+
return join16(appData ?? join16(homedir7(), "AppData", "Roaming"), "codesesh");
|
|
11212
12150
|
}
|
|
11213
|
-
return
|
|
12151
|
+
return join16(process.env.XDG_DATA_HOME ?? join16(homedir7(), ".local", "share"), "codesesh");
|
|
11214
12152
|
}
|
|
11215
12153
|
function getStateDbPath() {
|
|
11216
|
-
return
|
|
12154
|
+
return join16(getStateDir(), STATE_DB_FILENAME);
|
|
11217
12155
|
}
|
|
11218
12156
|
function useMemoryStateStore() {
|
|
11219
12157
|
return process.env.CODESESH_STATE_STORE === MEMORY_STATE_STORE;
|
|
@@ -11503,7 +12441,7 @@ function importBookmarks(bookmarks) {
|
|
|
11503
12441
|
);
|
|
11504
12442
|
}
|
|
11505
12443
|
});
|
|
11506
|
-
write();
|
|
12444
|
+
write.immediate();
|
|
11507
12445
|
const rows = db.prepare(
|
|
11508
12446
|
`
|
|
11509
12447
|
SELECT
|
|
@@ -11621,160 +12559,267 @@ function deleteSessionAlias(reference) {
|
|
|
11621
12559
|
});
|
|
11622
12560
|
}
|
|
11623
12561
|
var DASHBOARD_RECENT_LIMIT = 10;
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
}
|
|
12562
|
+
var DASHBOARD_PROJECT_LIMIT = 12;
|
|
12563
|
+
var PROJECT_SPARKLINE_DAYS = 14;
|
|
11627
12564
|
function getSessionAgentName(session) {
|
|
11628
12565
|
return getSessionAgentKey(session);
|
|
11629
12566
|
}
|
|
11630
12567
|
function getSessionActivityTime(session) {
|
|
11631
12568
|
return session.time_updated ?? session.time_created;
|
|
11632
12569
|
}
|
|
11633
|
-
function
|
|
11634
|
-
|
|
11635
|
-
|
|
11636
|
-
const
|
|
12570
|
+
function matchesScope(session, scope) {
|
|
12571
|
+
if (scope.agent && getSessionAgentName(session) !== scope.agent) return false;
|
|
12572
|
+
if (scope.projectKind == null && scope.projectKey == null) return true;
|
|
12573
|
+
const identity = session.project_identity;
|
|
12574
|
+
return identity != null && identity.kind === scope.projectKind && identity.key === scope.projectKey;
|
|
12575
|
+
}
|
|
12576
|
+
function scopedEntries(sessions, scope, from, to) {
|
|
12577
|
+
const tree = buildSessionTree(filterSessionTreeByActivityWindow(sessions, from, to));
|
|
12578
|
+
return tree.entries.filter((node) => matchesScope(node.session, scope));
|
|
12579
|
+
}
|
|
12580
|
+
function emptyDailyBucket(date) {
|
|
12581
|
+
return {
|
|
12582
|
+
date,
|
|
12583
|
+
sessions: 0,
|
|
12584
|
+
messages: 0,
|
|
12585
|
+
cost: 0,
|
|
12586
|
+
input: 0,
|
|
12587
|
+
output: 0,
|
|
12588
|
+
cache_read: 0,
|
|
12589
|
+
cache_create: 0
|
|
12590
|
+
};
|
|
12591
|
+
}
|
|
12592
|
+
function createAccumulator(byAgentNames, scope, to) {
|
|
12593
|
+
const agents = /* @__PURE__ */ new Map();
|
|
11637
12594
|
for (const name of byAgentNames) {
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
|
|
12595
|
+
const key = name.toLowerCase();
|
|
12596
|
+
if (scope.agent && key !== scope.agent) continue;
|
|
12597
|
+
agents.set(key, { name, sessions: 0, messages: 0, tokens: 0, cost: 0 });
|
|
11641
12598
|
}
|
|
11642
|
-
|
|
11643
|
-
let
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
11650
|
-
|
|
11651
|
-
|
|
12599
|
+
const sparklineSlots = /* @__PURE__ */ new Map();
|
|
12600
|
+
for (let slot = 0; slot < PROJECT_SPARKLINE_DAYS; slot += 1) {
|
|
12601
|
+
const day = addCalendarDays(to, slot - (PROJECT_SPARKLINE_DAYS - 1));
|
|
12602
|
+
sparklineSlots.set(toCalendarDayKey(day), slot);
|
|
12603
|
+
}
|
|
12604
|
+
return {
|
|
12605
|
+
sessions: 0,
|
|
12606
|
+
messages: 0,
|
|
12607
|
+
tokens: 0,
|
|
12608
|
+
cost: 0,
|
|
12609
|
+
costRecorded: 0,
|
|
12610
|
+
costEstimated: 0,
|
|
12611
|
+
cacheReadTokens: 0,
|
|
12612
|
+
hasEstimatedCost: false,
|
|
12613
|
+
agents,
|
|
12614
|
+
agentKeys: /* @__PURE__ */ new Set(),
|
|
12615
|
+
daily: /* @__PURE__ */ new Map(),
|
|
12616
|
+
models: /* @__PURE__ */ new Map(),
|
|
12617
|
+
projects: /* @__PURE__ */ new Map(),
|
|
12618
|
+
sparklineSlots,
|
|
12619
|
+
recent: []
|
|
12620
|
+
};
|
|
12621
|
+
}
|
|
12622
|
+
function foldModelUsage(node, into) {
|
|
12623
|
+
if (node.session.model_usage) {
|
|
12624
|
+
for (const [model, tokens] of Object.entries(node.session.model_usage)) {
|
|
12625
|
+
into.set(model, (into.get(model) ?? 0) + tokens);
|
|
12626
|
+
}
|
|
12627
|
+
}
|
|
12628
|
+
for (const child of node.children) foldModelUsage(child, into);
|
|
12629
|
+
}
|
|
12630
|
+
function trackProject(node, acc, dayKey, agentKey) {
|
|
12631
|
+
const identity = node.session.project_identity;
|
|
12632
|
+
if (!identity) return;
|
|
12633
|
+
const key = getProjectIdentityKey(identity);
|
|
12634
|
+
let project = acc.projects.get(key);
|
|
12635
|
+
if (!project) {
|
|
12636
|
+
project = {
|
|
12637
|
+
identityKind: identity.kind,
|
|
12638
|
+
identityKey: identity.key,
|
|
12639
|
+
displayName: identity.displayName,
|
|
12640
|
+
sessions: 0,
|
|
12641
|
+
messages: 0,
|
|
12642
|
+
tokens: 0,
|
|
12643
|
+
cost: 0,
|
|
12644
|
+
hasEstimatedCost: false,
|
|
12645
|
+
agentSessions: /* @__PURE__ */ new Map(),
|
|
12646
|
+
sparkline: Array.from({ length: PROJECT_SPARKLINE_DAYS }, () => 0)
|
|
12647
|
+
};
|
|
12648
|
+
acc.projects.set(key, project);
|
|
12649
|
+
}
|
|
12650
|
+
const stats = node.inclusiveStats;
|
|
12651
|
+
project.sessions += 1;
|
|
12652
|
+
project.messages += stats.messageCount;
|
|
12653
|
+
project.tokens += stats.totalTokens;
|
|
12654
|
+
project.cost += stats.cost;
|
|
12655
|
+
if (stats.costSource === "estimated") project.hasEstimatedCost = true;
|
|
12656
|
+
project.agentSessions.set(agentKey, (project.agentSessions.get(agentKey) ?? 0) + 1);
|
|
12657
|
+
const slot = acc.sparklineSlots.get(dayKey);
|
|
12658
|
+
if (slot != null) project.sparkline[slot] += stats.cost;
|
|
12659
|
+
}
|
|
12660
|
+
function accumulate(node, acc) {
|
|
12661
|
+
const session = node.session;
|
|
12662
|
+
const stats = node.inclusiveStats;
|
|
12663
|
+
const activity = getSessionActivityTime(session);
|
|
12664
|
+
const agentKey = getSessionAgentName(session);
|
|
12665
|
+
acc.sessions += 1;
|
|
12666
|
+
acc.messages += stats.messageCount;
|
|
12667
|
+
acc.tokens += stats.totalTokens;
|
|
12668
|
+
acc.cost += stats.cost;
|
|
12669
|
+
acc.cacheReadTokens += stats.cacheReadTokens;
|
|
12670
|
+
acc.agentKeys.add(agentKey);
|
|
12671
|
+
if (stats.costSource === "recorded") acc.costRecorded += stats.cost;
|
|
12672
|
+
else acc.costEstimated += stats.cost;
|
|
12673
|
+
if (stats.costSource === "estimated") acc.hasEstimatedCost = true;
|
|
12674
|
+
const metric = acc.agents.get(agentKey);
|
|
12675
|
+
if (metric) {
|
|
12676
|
+
metric.sessions += 1;
|
|
12677
|
+
metric.messages += stats.messageCount;
|
|
12678
|
+
metric.tokens += stats.totalTokens;
|
|
12679
|
+
metric.cost += stats.cost;
|
|
12680
|
+
}
|
|
12681
|
+
const dayKey = toCalendarDayKey(activity);
|
|
12682
|
+
let bucket = acc.daily.get(dayKey);
|
|
12683
|
+
if (!bucket) {
|
|
12684
|
+
bucket = emptyDailyBucket(dayKey);
|
|
12685
|
+
acc.daily.set(dayKey, bucket);
|
|
12686
|
+
}
|
|
12687
|
+
bucket.sessions += 1;
|
|
12688
|
+
bucket.messages += stats.messageCount;
|
|
12689
|
+
bucket.cost += stats.cost;
|
|
12690
|
+
bucket.input += Math.max(0, stats.inputTokens - stats.cacheReadTokens - stats.cacheCreateTokens);
|
|
12691
|
+
bucket.output += stats.outputTokens;
|
|
12692
|
+
bucket.cache_read += stats.cacheReadTokens;
|
|
12693
|
+
bucket.cache_create += stats.cacheCreateTokens;
|
|
12694
|
+
const usage = /* @__PURE__ */ new Map();
|
|
12695
|
+
foldModelUsage(node, usage);
|
|
12696
|
+
for (const [model, tokens] of usage) {
|
|
12697
|
+
const entry = acc.models.get(model);
|
|
12698
|
+
if (entry) {
|
|
12699
|
+
entry.tokens += tokens;
|
|
12700
|
+
entry.sessions += 1;
|
|
12701
|
+
} else {
|
|
12702
|
+
acc.models.set(model, { tokens, sessions: 1 });
|
|
12703
|
+
}
|
|
12704
|
+
}
|
|
12705
|
+
trackProject(node, acc, dayKey, agentKey);
|
|
12706
|
+
let recentIndex = acc.recent.length;
|
|
12707
|
+
for (let i = 0; i < acc.recent.length; i += 1) {
|
|
12708
|
+
if (activity > acc.recent[i].activity) {
|
|
12709
|
+
recentIndex = i;
|
|
12710
|
+
break;
|
|
12711
|
+
}
|
|
12712
|
+
}
|
|
12713
|
+
if (recentIndex < DASHBOARD_RECENT_LIMIT) {
|
|
12714
|
+
acc.recent.splice(recentIndex, 0, { session, activity });
|
|
12715
|
+
if (acc.recent.length > DASHBOARD_RECENT_LIMIT) acc.recent.pop();
|
|
12716
|
+
}
|
|
12717
|
+
}
|
|
12718
|
+
function toPreviousTotals(acc) {
|
|
12719
|
+
return { sessions: acc.sessions, messages: acc.messages, tokens: acc.tokens, cost: acc.cost };
|
|
12720
|
+
}
|
|
12721
|
+
function toProjectStat(project) {
|
|
12722
|
+
return {
|
|
12723
|
+
identityKind: project.identityKind,
|
|
12724
|
+
identityKey: project.identityKey,
|
|
12725
|
+
displayName: project.displayName,
|
|
12726
|
+
sessions: project.sessions,
|
|
12727
|
+
messages: project.messages,
|
|
12728
|
+
tokens: project.tokens,
|
|
12729
|
+
cost: project.cost,
|
|
12730
|
+
cost_source: project.cost > 0 ? project.hasEstimatedCost ? "estimated" : "recorded" : void 0,
|
|
12731
|
+
agents: [...project.agentSessions.entries()].sort((a, b) => b[1] - a[1]).map(([agentKey]) => agentKey),
|
|
12732
|
+
sparkline: project.sparkline
|
|
12733
|
+
};
|
|
12734
|
+
}
|
|
12735
|
+
function buildDashboard(sessions, options) {
|
|
12736
|
+
const { byAgentNames, scope, from, to, agentInfoMap, compare } = options;
|
|
12737
|
+
const acc = createAccumulator(byAgentNames, scope, to);
|
|
11652
12738
|
if (from != null) {
|
|
11653
12739
|
const bucketDays = countCalendarDays(from, to);
|
|
11654
12740
|
for (let i = 0; i < bucketDays; i += 1) {
|
|
11655
12741
|
const key = toCalendarDayKey(addCalendarDays(from, i));
|
|
11656
|
-
|
|
11657
|
-
dailyTokenMap.set(key, { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 });
|
|
11658
|
-
}
|
|
11659
|
-
}
|
|
11660
|
-
const visibleSessions = filterSessionTreeByActivityWindow(sessions, from, to);
|
|
11661
|
-
for (const session of visibleSessions) {
|
|
11662
|
-
if (isChildSession(session)) continue;
|
|
11663
|
-
const agentName = getSessionAgentName(session);
|
|
11664
|
-
if (scope.agent && agentName !== scope.agent) continue;
|
|
11665
|
-
if (scope.projectKind || scope.projectKey) {
|
|
11666
|
-
const identity = session.project_identity;
|
|
11667
|
-
if (!identity || !scope.projectKind || !scope.projectKey || identity.kind !== scope.projectKind || identity.key !== scope.projectKey) {
|
|
11668
|
-
continue;
|
|
11669
|
-
}
|
|
11670
|
-
}
|
|
11671
|
-
const activity = getSessionActivityTime(session);
|
|
11672
|
-
const messageCount = session.stats.message_count;
|
|
11673
|
-
const sessionTokens = getTotalTokens(session.stats);
|
|
11674
|
-
totalSessions += 1;
|
|
11675
|
-
totalMessages += messageCount;
|
|
11676
|
-
totalTokens += sessionTokens;
|
|
11677
|
-
totalCost += session.stats.total_cost ?? 0;
|
|
11678
|
-
if (session.stats.cost_source === "estimated") hasEstimatedCost = true;
|
|
11679
|
-
if (activity > latestActivity) latestActivity = activity;
|
|
11680
|
-
const metricKey = agentMetricKeyByName.get(agentName);
|
|
11681
|
-
if (metricKey) {
|
|
11682
|
-
const metric = agentMetrics.get(metricKey);
|
|
11683
|
-
metric.sessions += 1;
|
|
11684
|
-
metric.messages += messageCount;
|
|
11685
|
-
metric.tokens += sessionTokens;
|
|
11686
|
-
}
|
|
11687
|
-
const key = toCalendarDayKey(activity);
|
|
11688
|
-
let bucket = dailyMap.get(key);
|
|
11689
|
-
if (!bucket) {
|
|
11690
|
-
bucket = { date: key, sessions: 0, messages: 0 };
|
|
11691
|
-
dailyMap.set(key, bucket);
|
|
11692
|
-
}
|
|
11693
|
-
bucket.sessions += 1;
|
|
11694
|
-
bucket.messages += messageCount;
|
|
11695
|
-
let tokenBucket = dailyTokenMap.get(key);
|
|
11696
|
-
if (!tokenBucket) {
|
|
11697
|
-
tokenBucket = { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 };
|
|
11698
|
-
dailyTokenMap.set(key, tokenBucket);
|
|
11699
|
-
}
|
|
11700
|
-
const cacheRead = session.stats.total_cache_read_tokens ?? 0;
|
|
11701
|
-
const cacheCreate = session.stats.total_cache_create_tokens ?? 0;
|
|
11702
|
-
const pureInput = session.stats.total_input_tokens - cacheRead - cacheCreate;
|
|
11703
|
-
tokenBucket.input += Math.max(0, pureInput);
|
|
11704
|
-
tokenBucket.output += session.stats.total_output_tokens;
|
|
11705
|
-
tokenBucket.cache_read += cacheRead;
|
|
11706
|
-
tokenBucket.cache_create += cacheCreate;
|
|
11707
|
-
if (session.model_usage) {
|
|
11708
|
-
for (const [model, tokens] of Object.entries(session.model_usage)) {
|
|
11709
|
-
const entry = modelAgg.get(model);
|
|
11710
|
-
if (entry) {
|
|
11711
|
-
entry.tokens += tokens;
|
|
11712
|
-
entry.sessions += 1;
|
|
11713
|
-
} else {
|
|
11714
|
-
modelAgg.set(model, { tokens, sessions: 1 });
|
|
11715
|
-
}
|
|
11716
|
-
}
|
|
12742
|
+
acc.daily.set(key, emptyDailyBucket(key));
|
|
11717
12743
|
}
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
|
|
11724
|
-
|
|
11725
|
-
if (recentIndex < DASHBOARD_RECENT_LIMIT) {
|
|
11726
|
-
recentCandidates.splice(recentIndex, 0, { session, activity });
|
|
11727
|
-
if (recentCandidates.length > DASHBOARD_RECENT_LIMIT) recentCandidates.pop();
|
|
12744
|
+
}
|
|
12745
|
+
for (const node of scopedEntries(sessions, scope, from, to)) accumulate(node, acc);
|
|
12746
|
+
let previous;
|
|
12747
|
+
if (compare) {
|
|
12748
|
+
const compareAcc = createAccumulator(byAgentNames, scope, compare.to);
|
|
12749
|
+
for (const node of scopedEntries(sessions, scope, compare.from, compare.to)) {
|
|
12750
|
+
accumulate(node, compareAcc);
|
|
11728
12751
|
}
|
|
12752
|
+
previous = toPreviousTotals(compareAcc);
|
|
11729
12753
|
}
|
|
11730
|
-
const perAgent = [...
|
|
11731
|
-
const info = agentInfoMap?.get(name);
|
|
12754
|
+
const perAgent = [...acc.agents.values()].map((metrics) => {
|
|
12755
|
+
const info = agentInfoMap?.get(metrics.name);
|
|
11732
12756
|
return {
|
|
11733
|
-
name,
|
|
11734
|
-
displayName: info?.displayName ?? name,
|
|
12757
|
+
name: metrics.name,
|
|
12758
|
+
displayName: info?.displayName ?? metrics.name,
|
|
11735
12759
|
icon: info?.icon ?? "",
|
|
11736
12760
|
iconColored: info?.iconColored,
|
|
11737
12761
|
sessions: metrics.sessions,
|
|
11738
12762
|
messages: metrics.messages,
|
|
11739
|
-
tokens: metrics.tokens
|
|
12763
|
+
tokens: metrics.tokens,
|
|
12764
|
+
cost: metrics.cost
|
|
11740
12765
|
};
|
|
11741
12766
|
}).filter((item) => item.sessions > 0).sort((a, b) => b.sessions - a.sessions);
|
|
11742
|
-
const dailyActivity = [...
|
|
11743
|
-
const
|
|
11744
|
-
|
|
12767
|
+
const dailyActivity = [...acc.daily.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
12768
|
+
const modelDistribution = [...acc.models.entries()].map(([model, { tokens, sessions: count }]) => ({ model, tokens, sessions: count })).sort((a, b) => b.tokens - a.tokens);
|
|
12769
|
+
const rankedProjects = [...acc.projects.values()].sort((a, b) => b.cost - a.cost);
|
|
12770
|
+
const perProject = rankedProjects.slice(0, DASHBOARD_PROJECT_LIMIT).map(toProjectStat);
|
|
12771
|
+
const projectRollup = rankedProjects.slice(DASHBOARD_PROJECT_LIMIT).reduce(
|
|
12772
|
+
(rollup, project) => ({
|
|
12773
|
+
projects: rollup.projects + 1,
|
|
12774
|
+
sessions: rollup.sessions + project.sessions,
|
|
12775
|
+
tokens: rollup.tokens + project.tokens,
|
|
12776
|
+
cost: rollup.cost + project.cost
|
|
12777
|
+
}),
|
|
12778
|
+
{ projects: 0, sessions: 0, tokens: 0, cost: 0 }
|
|
11745
12779
|
);
|
|
11746
|
-
const
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
session
|
|
11752
|
-
};
|
|
11753
|
-
});
|
|
12780
|
+
const recentSessions = acc.recent.map(({ session }) => ({
|
|
12781
|
+
reference: { agentName: getSessionAgentName(session), sessionId: session.id },
|
|
12782
|
+
session
|
|
12783
|
+
}));
|
|
12784
|
+
const latest = acc.recent[0];
|
|
11754
12785
|
return {
|
|
11755
12786
|
totals: {
|
|
11756
|
-
sessions:
|
|
11757
|
-
messages:
|
|
11758
|
-
tokens:
|
|
11759
|
-
cost:
|
|
11760
|
-
|
|
11761
|
-
|
|
12787
|
+
sessions: acc.sessions,
|
|
12788
|
+
messages: acc.messages,
|
|
12789
|
+
tokens: acc.tokens,
|
|
12790
|
+
cost: acc.cost,
|
|
12791
|
+
costRecorded: acc.costRecorded,
|
|
12792
|
+
costEstimated: acc.costEstimated,
|
|
12793
|
+
cacheReadTokens: acc.cacheReadTokens,
|
|
12794
|
+
cost_source: acc.cost > 0 ? acc.hasEstimatedCost ? "estimated" : "recorded" : void 0,
|
|
12795
|
+
latestActivity: latest?.activity || void 0,
|
|
12796
|
+
latestActivityProject: latest?.session.project_identity?.displayName,
|
|
12797
|
+
latestActivityAgent: latest ? getSessionAgentName(latest.session) : void 0,
|
|
12798
|
+
previous
|
|
11762
12799
|
},
|
|
12800
|
+
scopeCounts: { projects: acc.projects.size, agents: acc.agentKeys.size },
|
|
11763
12801
|
perAgent,
|
|
11764
12802
|
dailyActivity,
|
|
11765
|
-
dailyTokenActivity,
|
|
11766
12803
|
modelDistribution,
|
|
12804
|
+
perProject,
|
|
12805
|
+
projectRollup,
|
|
11767
12806
|
recentSessions
|
|
11768
12807
|
};
|
|
11769
12808
|
}
|
|
11770
12809
|
function emptyMetrics() {
|
|
11771
|
-
return {
|
|
12810
|
+
return {
|
|
12811
|
+
sessions: 0,
|
|
12812
|
+
messages: 0,
|
|
12813
|
+
tokens: 0,
|
|
12814
|
+
cost: 0,
|
|
12815
|
+
hasEstimatedCost: false,
|
|
12816
|
+
agentStats: /* @__PURE__ */ new Map()
|
|
12817
|
+
};
|
|
11772
12818
|
}
|
|
11773
12819
|
function attachProjectMetrics(projects, sessions) {
|
|
11774
12820
|
const metrics = /* @__PURE__ */ new Map();
|
|
11775
|
-
for (const
|
|
11776
|
-
|
|
11777
|
-
const identity = session.project_identity;
|
|
12821
|
+
for (const node of buildSessionTree(sessions).entries) {
|
|
12822
|
+
const identity = node.session.project_identity;
|
|
11778
12823
|
if (!identity) continue;
|
|
11779
12824
|
const key = getProjectIdentityKey(identity);
|
|
11780
12825
|
let current = metrics.get(key);
|
|
@@ -11782,26 +12827,26 @@ function attachProjectMetrics(projects, sessions) {
|
|
|
11782
12827
|
current = emptyMetrics();
|
|
11783
12828
|
metrics.set(key, current);
|
|
11784
12829
|
}
|
|
11785
|
-
const
|
|
11786
|
-
|
|
11787
|
-
current.messages +=
|
|
11788
|
-
current.tokens +=
|
|
11789
|
-
current.cost += cost;
|
|
11790
|
-
if (
|
|
11791
|
-
const agentName = getSessionAgentName(session);
|
|
12830
|
+
const stats = node.inclusiveStats;
|
|
12831
|
+
current.sessions += 1;
|
|
12832
|
+
current.messages += stats.messageCount;
|
|
12833
|
+
current.tokens += stats.totalTokens;
|
|
12834
|
+
current.cost += stats.cost;
|
|
12835
|
+
if (stats.costSource === "estimated") current.hasEstimatedCost = true;
|
|
12836
|
+
const agentName = getSessionAgentName(node.session);
|
|
11792
12837
|
const agent = current.agentStats.get(agentName);
|
|
11793
12838
|
if (agent) {
|
|
11794
12839
|
agent.sessions += 1;
|
|
11795
|
-
agent.messages +=
|
|
11796
|
-
agent.tokens +=
|
|
11797
|
-
agent.cost += cost;
|
|
12840
|
+
agent.messages += stats.messageCount;
|
|
12841
|
+
agent.tokens += stats.totalTokens;
|
|
12842
|
+
agent.cost += stats.cost;
|
|
11798
12843
|
} else {
|
|
11799
12844
|
current.agentStats.set(agentName, {
|
|
11800
12845
|
name: agentName,
|
|
11801
12846
|
sessions: 1,
|
|
11802
|
-
messages:
|
|
11803
|
-
tokens,
|
|
11804
|
-
cost
|
|
12847
|
+
messages: stats.messageCount,
|
|
12848
|
+
tokens: stats.totalTokens,
|
|
12849
|
+
cost: stats.cost
|
|
11805
12850
|
});
|
|
11806
12851
|
}
|
|
11807
12852
|
}
|
|
@@ -11811,6 +12856,7 @@ function attachProjectMetrics(projects, sessions) {
|
|
|
11811
12856
|
);
|
|
11812
12857
|
return {
|
|
11813
12858
|
...project,
|
|
12859
|
+
sessionCount: metric?.sessions ?? 0,
|
|
11814
12860
|
messages: metric?.messages ?? 0,
|
|
11815
12861
|
tokens: metric?.tokens ?? 0,
|
|
11816
12862
|
cost: metric?.cost ?? 0,
|
|
@@ -11956,6 +13002,7 @@ export {
|
|
|
11956
13002
|
getSessionAgentKey,
|
|
11957
13003
|
sessionRoutePath,
|
|
11958
13004
|
mergeSortedSessions,
|
|
13005
|
+
getSessionRouteKey,
|
|
11959
13006
|
isChildSession,
|
|
11960
13007
|
getRootSessions,
|
|
11961
13008
|
filterSessionTreeByActivityWindow,
|
|
@@ -12004,6 +13051,7 @@ export {
|
|
|
12004
13051
|
scanSessions,
|
|
12005
13052
|
materializeSessionDetailResponse,
|
|
12006
13053
|
listCachedProjectGroups,
|
|
13054
|
+
listModelCostDistribution,
|
|
12007
13055
|
StateStorageUnavailableError,
|
|
12008
13056
|
listBookmarks,
|
|
12009
13057
|
upsertBookmark,
|
|
@@ -12019,4 +13067,4 @@ export {
|
|
|
12019
13067
|
executeSessionSearch,
|
|
12020
13068
|
filterSessionSearchCandidates
|
|
12021
13069
|
};
|
|
12022
|
-
//# sourceMappingURL=chunk-
|
|
13070
|
+
//# sourceMappingURL=chunk-BEF6LLRG.js.map
|