fleetlens 0.7.1 → 0.9.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.
Files changed (51) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/build-manifest.json +3 -3
  3. package/app/apps/web/.next/prerender-manifest.json +3 -3
  4. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  5. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  6. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  13. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  14. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  15. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  16. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  17. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  18. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  19. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  20. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  21. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  22. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  23. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  24. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  25. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  26. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  27. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  28. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0.z48ue._.js +1 -1
  29. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0dctov1._.js +2 -2
  30. package/app/apps/web/.next/server/chunks/packages_09hmrqx._.js +1 -1
  31. package/app/apps/web/.next/server/chunks/packages_118y1lp._.js +1 -1
  32. package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_122oe0-.js +1 -1
  33. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ytdqxt._.js +1 -1
  34. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  35. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0m67-xi._.js +1 -1
  36. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_10_oegc._.js +1 -1
  37. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  38. package/app/apps/web/.next/server/pages/500.html +1 -1
  39. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  40. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  41. package/app/apps/web/.next/static/chunks/0cxyt4-24..b7.js +14 -0
  42. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  43. package/app/apps/web/package.json +1 -1
  44. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  45. package/dist/daemon-worker.js +562 -37
  46. package/dist/index.js +589 -64
  47. package/package.json +1 -1
  48. package/app/apps/web/.next/static/chunks/179_t_igg8ghh.js +0 -14
  49. /package/app/apps/web/.next/static/{tiK9aMHXkgnKLNmxj9J1P → u6-8f8u1tspYCacGAz53R}/_buildManifest.js +0 -0
  50. /package/app/apps/web/.next/static/{tiK9aMHXkgnKLNmxj9J1P → u6-8f8u1tspYCacGAz53R}/_clientMiddlewareManifest.js +0 -0
  51. /package/app/apps/web/.next/static/{tiK9aMHXkgnKLNmxj9J1P → u6-8f8u1tspYCacGAz53R}/_ssgManifest.js +0 -0
@@ -538,7 +538,7 @@ function getAgentMetadata(kind) {
538
538
  function isAgentKind(s) {
539
539
  return typeof s === "string" && KNOWN_AGENT_KINDS.has(s);
540
540
  }
541
- var CLAUDE_CODE_METADATA, CODEX_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
541
+ var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
542
542
  var init_agent_metadata = __esm({
543
543
  "../parser/dist/agent-metadata.js"() {
544
544
  "use strict";
@@ -556,9 +556,17 @@ var init_agent_metadata = __esm({
556
556
  accentColor: "rgb(16, 163, 127)",
557
557
  iconChar: "\u25C6"
558
558
  };
559
+ GEMINI_METADATA = {
560
+ kind: "gemini",
561
+ displayName: "Gemini CLI",
562
+ shortLabel: "Gemini",
563
+ accentColor: "rgb(124, 92, 246)",
564
+ iconChar: "\u273A"
565
+ };
559
566
  agentMetadata = [
560
567
  CLAUDE_CODE_METADATA,
561
- CODEX_METADATA
568
+ CODEX_METADATA,
569
+ GEMINI_METADATA
562
570
  ];
563
571
  KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
564
572
  }
@@ -2342,10 +2350,510 @@ var init_codex = __esm({
2342
2350
  }
2343
2351
  });
2344
2352
 
2353
+ // ../parser/dist/gemini.js
2354
+ import { promises as fs3 } from "node:fs";
2355
+ import os3 from "node:os";
2356
+ import path3 from "node:path";
2357
+ async function safeReaddir2(p) {
2358
+ return fs3.readdir(p).catch(() => []);
2359
+ }
2360
+ async function listSessionFiles(root) {
2361
+ const out = [];
2362
+ const slugs = await safeReaddir2(root);
2363
+ for (const slug of slugs) {
2364
+ const chatsDir = path3.join(root, slug, "chats");
2365
+ const entries = await safeReaddir2(chatsDir);
2366
+ for (const entry of entries) {
2367
+ if (!SESSION_FILE_RE.test(entry))
2368
+ continue;
2369
+ const full = path3.join(chatsDir, entry);
2370
+ const stat = await fs3.stat(full).catch(() => null);
2371
+ if (!stat || !stat.isFile())
2372
+ continue;
2373
+ const filenameId = entry.replace(/\.(jsonl|json)$/, "").split("-").pop() ?? entry;
2374
+ out.push({
2375
+ filePath: full,
2376
+ slug,
2377
+ filenameId,
2378
+ format: entry.endsWith(".jsonl") ? "jsonl" : "legacy-json",
2379
+ mtimeMs: stat.mtimeMs,
2380
+ sizeBytes: stat.size
2381
+ });
2382
+ }
2383
+ }
2384
+ return out;
2385
+ }
2386
+ async function loadSlugToCwd() {
2387
+ const stat = await fs3.stat(GEMINI_PROJECTS_FILE).catch(() => null);
2388
+ if (!stat)
2389
+ return /* @__PURE__ */ new Map();
2390
+ if (projectsCache && projectsCache.mtimeMs === stat.mtimeMs) {
2391
+ return projectsCache.slugToCwd;
2392
+ }
2393
+ const raw = await fs3.readFile(GEMINI_PROJECTS_FILE, "utf8").catch(() => "");
2394
+ let parsed;
2395
+ try {
2396
+ parsed = JSON.parse(raw);
2397
+ } catch {
2398
+ parsed = {};
2399
+ }
2400
+ const slugToCwd = /* @__PURE__ */ new Map();
2401
+ for (const [cwd, slug] of Object.entries(parsed.projects ?? {})) {
2402
+ if (typeof slug === "string")
2403
+ slugToCwd.set(slug, cwd);
2404
+ }
2405
+ projectsCache = { mtimeMs: stat.mtimeMs, slugToCwd };
2406
+ return slugToCwd;
2407
+ }
2408
+ function isRewindMarker(o) {
2409
+ return !!o && typeof o === "object" && "$rewindTo" in o;
2410
+ }
2411
+ function isSetMarker(o) {
2412
+ return !!o && typeof o === "object" && "$set" in o;
2413
+ }
2414
+ function isMessageRecord(o) {
2415
+ return !!o && typeof o === "object" && typeof o.id === "string" && typeof o.type === "string";
2416
+ }
2417
+ async function readAndReplay(file) {
2418
+ const raw = await fs3.readFile(file.filePath, "utf8");
2419
+ if (file.format === "legacy-json") {
2420
+ let blob;
2421
+ try {
2422
+ blob = JSON.parse(raw);
2423
+ } catch {
2424
+ return { meta: {}, messages: [] };
2425
+ }
2426
+ const meta2 = {
2427
+ sessionId: typeof blob.sessionId === "string" ? blob.sessionId : void 0,
2428
+ projectHash: typeof blob.projectHash === "string" ? blob.projectHash : void 0,
2429
+ startTime: typeof blob.startTime === "string" ? blob.startTime : void 0,
2430
+ lastUpdated: typeof blob.lastUpdated === "string" ? blob.lastUpdated : void 0,
2431
+ summary: typeof blob.summary === "string" ? blob.summary : void 0
2432
+ };
2433
+ const msgs = Array.isArray(blob.messages) ? blob.messages : [];
2434
+ const messages2 = msgs.filter(isMessageRecord);
2435
+ return { meta: meta2, messages: messages2 };
2436
+ }
2437
+ const meta = {};
2438
+ const byId = /* @__PURE__ */ new Map();
2439
+ const order = [];
2440
+ for (const line of raw.split("\n")) {
2441
+ const trimmed = line.trim();
2442
+ if (!trimmed)
2443
+ continue;
2444
+ let obj;
2445
+ try {
2446
+ obj = JSON.parse(trimmed);
2447
+ } catch {
2448
+ continue;
2449
+ }
2450
+ if (isRewindMarker(obj)) {
2451
+ const target = obj.$rewindTo;
2452
+ const idx = order.indexOf(target);
2453
+ if (idx >= 0) {
2454
+ for (const id of order.slice(idx))
2455
+ byId.delete(id);
2456
+ order.length = idx;
2457
+ }
2458
+ continue;
2459
+ }
2460
+ if (isSetMarker(obj)) {
2461
+ Object.assign(meta, obj.$set);
2462
+ continue;
2463
+ }
2464
+ if (isMessageRecord(obj)) {
2465
+ if (!byId.has(obj.id))
2466
+ order.push(obj.id);
2467
+ byId.set(obj.id, obj);
2468
+ continue;
2469
+ }
2470
+ if (typeof obj === "object" && obj !== null) {
2471
+ const m = obj;
2472
+ if (typeof m.sessionId === "string" && !meta.sessionId) {
2473
+ meta.sessionId = m.sessionId;
2474
+ if (typeof m.projectHash === "string")
2475
+ meta.projectHash = m.projectHash;
2476
+ if (typeof m.startTime === "string")
2477
+ meta.startTime = m.startTime;
2478
+ if (typeof m.lastUpdated === "string")
2479
+ meta.lastUpdated = m.lastUpdated;
2480
+ if (typeof m.summary === "string")
2481
+ meta.summary = m.summary;
2482
+ }
2483
+ }
2484
+ }
2485
+ const messages = [];
2486
+ for (const id of order) {
2487
+ const m = byId.get(id);
2488
+ if (m)
2489
+ messages.push(m);
2490
+ }
2491
+ return { meta, messages };
2492
+ }
2493
+ function emptyUsage2() {
2494
+ return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
2495
+ }
2496
+ function previewOf2(text) {
2497
+ return text.replace(/\s+/g, " ").trim().slice(0, 200);
2498
+ }
2499
+ function flattenContent(c) {
2500
+ if (!c)
2501
+ return "";
2502
+ if (typeof c === "string")
2503
+ return c;
2504
+ const parts = Array.isArray(c) ? c : [c];
2505
+ const out = [];
2506
+ for (const p of parts) {
2507
+ if (!p || typeof p !== "object")
2508
+ continue;
2509
+ const part = p;
2510
+ if (typeof part.text === "string") {
2511
+ out.push(part.text);
2512
+ continue;
2513
+ }
2514
+ const fr = part.functionResponse;
2515
+ if (fr) {
2516
+ const resp = fr.response;
2517
+ if (typeof resp === "string") {
2518
+ out.push(resp);
2519
+ } else if (resp && typeof resp === "object") {
2520
+ const r = resp;
2521
+ if (typeof r.output === "string")
2522
+ out.push(r.output);
2523
+ else if (typeof r.error === "string")
2524
+ out.push(`error: ${r.error}`);
2525
+ else
2526
+ out.push(JSON.stringify(r));
2527
+ }
2528
+ }
2529
+ }
2530
+ return out.join("\n");
2531
+ }
2532
+ function truncate3(s, n) {
2533
+ return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
2534
+ }
2535
+ async function parseSession(file) {
2536
+ const { meta: metaRec, messages } = await readAndReplay(file);
2537
+ const slugToCwd = await loadSlugToCwd();
2538
+ const cwd = slugToCwd.get(file.slug);
2539
+ const events = [];
2540
+ const totalUsage = emptyUsage2();
2541
+ let firstTimestamp;
2542
+ let lastTimestamp;
2543
+ let model;
2544
+ let toolCallCount = 0;
2545
+ let turnCount = 0;
2546
+ let firstUserPreview;
2547
+ let lastUserPreview;
2548
+ let lastAgentPreview;
2549
+ const tsMs = [];
2550
+ let idx = 0;
2551
+ function pushEvent(e) {
2552
+ events.push(e);
2553
+ if (e.timestamp && e.role !== "meta") {
2554
+ if (!firstTimestamp)
2555
+ firstTimestamp = e.timestamp;
2556
+ lastTimestamp = e.timestamp;
2557
+ const ms = Date.parse(e.timestamp);
2558
+ if (Number.isFinite(ms))
2559
+ tsMs.push(ms);
2560
+ }
2561
+ }
2562
+ for (const msg of messages) {
2563
+ const ts = msg.timestamp;
2564
+ if (msg.type === "user") {
2565
+ const text = flattenContent(msg.displayContent ?? msg.content);
2566
+ const preview = previewOf2(text);
2567
+ if (text) {
2568
+ if (!firstUserPreview)
2569
+ firstUserPreview = preview;
2570
+ lastUserPreview = preview;
2571
+ turnCount += 1;
2572
+ }
2573
+ pushEvent({
2574
+ index: idx++,
2575
+ timestamp: ts,
2576
+ role: "user",
2577
+ rawType: "gemini/user",
2578
+ preview,
2579
+ blocks: text ? [{ type: "text", text }] : [],
2580
+ messageId: msg.id,
2581
+ raw: msg
2582
+ });
2583
+ continue;
2584
+ }
2585
+ if (msg.type === "gemini") {
2586
+ if (typeof msg.model === "string")
2587
+ model = msg.model;
2588
+ const text = flattenContent(msg.content);
2589
+ const preview = previewOf2(text);
2590
+ if (text)
2591
+ lastAgentPreview = preview;
2592
+ let usage;
2593
+ if (msg.tokens) {
2594
+ const t = msg.tokens;
2595
+ const u = {
2596
+ input: t.input ?? 0,
2597
+ output: t.output ?? 0,
2598
+ cacheRead: t.cached ?? 0,
2599
+ cacheWrite: 0
2600
+ };
2601
+ usage = u;
2602
+ totalUsage.input += u.input;
2603
+ totalUsage.output += u.output;
2604
+ totalUsage.cacheRead += u.cacheRead;
2605
+ }
2606
+ for (const th of msg.thoughts ?? []) {
2607
+ const thText = [th.subject, th.description].filter(Boolean).join(": ");
2608
+ if (!thText)
2609
+ continue;
2610
+ pushEvent({
2611
+ index: idx++,
2612
+ timestamp: th.timestamp ?? ts,
2613
+ role: "agent-thinking",
2614
+ rawType: "gemini/thought",
2615
+ preview: previewOf2(thText),
2616
+ blocks: [{ type: "thinking", thinking: thText }],
2617
+ model,
2618
+ raw: th
2619
+ });
2620
+ }
2621
+ if (text) {
2622
+ pushEvent({
2623
+ index: idx++,
2624
+ timestamp: ts,
2625
+ role: "agent",
2626
+ rawType: "gemini/agent",
2627
+ preview,
2628
+ blocks: [{ type: "text", text }],
2629
+ messageId: msg.id,
2630
+ model,
2631
+ usage,
2632
+ raw: msg
2633
+ });
2634
+ } else if (usage) {
2635
+ pushEvent({
2636
+ index: idx++,
2637
+ timestamp: ts,
2638
+ role: "agent",
2639
+ rawType: "gemini/agent",
2640
+ preview: "",
2641
+ blocks: [],
2642
+ messageId: msg.id,
2643
+ model,
2644
+ usage,
2645
+ raw: msg
2646
+ });
2647
+ }
2648
+ for (const tc of msg.toolCalls ?? []) {
2649
+ toolCallCount += 1;
2650
+ const argsStr = tc.args ? JSON.stringify(tc.args) : "";
2651
+ pushEvent({
2652
+ index: idx++,
2653
+ timestamp: tc.timestamp ?? ts,
2654
+ role: "tool-call",
2655
+ rawType: "gemini/tool_call",
2656
+ preview: `${tc.name}(${truncate3(argsStr, 80)})`,
2657
+ blocks: [{ type: "tool_use", id: tc.id, name: tc.name, input: tc.args ?? {} }],
2658
+ toolName: tc.name,
2659
+ toolUseId: tc.id,
2660
+ model,
2661
+ raw: tc
2662
+ });
2663
+ const status = (tc.status ?? "").toLowerCase();
2664
+ const isTerminal = status === "success" || status === "error" || status === "cancelled";
2665
+ if (isTerminal) {
2666
+ const resultText = flattenContent(tc.result);
2667
+ pushEvent({
2668
+ index: idx++,
2669
+ timestamp: tc.timestamp ?? ts,
2670
+ role: "tool-result",
2671
+ rawType: "gemini/tool_result",
2672
+ preview: previewOf2(resultText),
2673
+ blocks: [
2674
+ {
2675
+ type: "tool_result",
2676
+ tool_use_id: tc.id,
2677
+ content: resultText,
2678
+ is_error: status === "error" || status === "cancelled"
2679
+ }
2680
+ ],
2681
+ toolUseId: tc.id,
2682
+ toolResult: resultText,
2683
+ raw: tc
2684
+ });
2685
+ }
2686
+ }
2687
+ continue;
2688
+ }
2689
+ if (msg.type === "info" || msg.type === "warning" || msg.type === "error") {
2690
+ const text = flattenContent(msg.content);
2691
+ pushEvent({
2692
+ index: idx++,
2693
+ timestamp: ts,
2694
+ role: "meta",
2695
+ rawType: `gemini/${msg.type}`,
2696
+ preview: previewOf2(text),
2697
+ blocks: text ? [{ type: "text", text }] : [],
2698
+ raw: msg
2699
+ });
2700
+ continue;
2701
+ }
2702
+ }
2703
+ const startMs = firstTimestamp ? Date.parse(firstTimestamp) : void 0;
2704
+ if (startMs !== void 0 && Number.isFinite(startMs)) {
2705
+ let prevMs;
2706
+ for (const ev of events) {
2707
+ if (!ev.timestamp)
2708
+ continue;
2709
+ const ms = Date.parse(ev.timestamp);
2710
+ if (!Number.isFinite(ms))
2711
+ continue;
2712
+ ev.tOffsetMs = Math.max(0, ms - startMs);
2713
+ if (prevMs !== void 0)
2714
+ ev.gapMs = Math.max(0, ms - prevMs);
2715
+ prevMs = ms;
2716
+ }
2717
+ }
2718
+ const activeSegments = computeActiveSegments3(tsMs);
2719
+ const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
2720
+ const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
2721
+ const sessionId = metaRec.sessionId ?? file.filenameId;
2722
+ const projectName = cwd ? canonicalProjectName(cwd) : file.slug;
2723
+ const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.slug;
2724
+ const meta = {
2725
+ agent: "gemini",
2726
+ id: sessionId,
2727
+ filePath: file.filePath,
2728
+ projectName,
2729
+ projectDir,
2730
+ sessionId,
2731
+ firstTimestamp,
2732
+ lastTimestamp,
2733
+ durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
2734
+ eventCount: events.length,
2735
+ model,
2736
+ cwd,
2737
+ totalUsage,
2738
+ status: "idle",
2739
+ firstUserPreview,
2740
+ lastUserPreview,
2741
+ lastAgentPreview,
2742
+ toolCallCount,
2743
+ turnCount,
2744
+ airTimeMs,
2745
+ activeSegments
2746
+ };
2747
+ return { meta, events };
2748
+ }
2749
+ function computeActiveSegments3(tsMs) {
2750
+ if (tsMs.length === 0)
2751
+ return [];
2752
+ const sorted = [...tsMs].sort((a, b) => a - b);
2753
+ const out = [];
2754
+ let segStart = sorted[0];
2755
+ let segEnd = sorted[0];
2756
+ for (let i = 1; i < sorted.length; i++) {
2757
+ if (sorted[i] - segEnd > IDLE_GAP_MS2) {
2758
+ out.push({ startMs: segStart, endMs: segEnd });
2759
+ segStart = sorted[i];
2760
+ }
2761
+ segEnd = sorted[i];
2762
+ }
2763
+ out.push({ startMs: segStart, endMs: segEnd });
2764
+ return out;
2765
+ }
2766
+ function clearGeminiCaches() {
2767
+ metaCache3.clear();
2768
+ detailCache3.clear();
2769
+ projectsCache = null;
2770
+ }
2771
+ async function listGeminiSessions(opts = {}) {
2772
+ const root = opts.root ?? DEFAULT_GEMINI_ROOT;
2773
+ const files = await listSessionFiles(root);
2774
+ const out = [];
2775
+ for (const file of files) {
2776
+ const cached = metaCache3.get(file.filePath);
2777
+ if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
2778
+ out.push(cached.meta);
2779
+ continue;
2780
+ }
2781
+ try {
2782
+ const { meta } = await parseSession(file);
2783
+ metaCache3.set(file.filePath, {
2784
+ meta,
2785
+ mtimeMs: file.mtimeMs,
2786
+ sizeBytes: file.sizeBytes
2787
+ });
2788
+ out.push(meta);
2789
+ } catch {
2790
+ }
2791
+ }
2792
+ out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
2793
+ if (opts.limit !== void 0)
2794
+ return out.slice(0, opts.limit);
2795
+ return out;
2796
+ }
2797
+ async function getGeminiSession(id, opts = {}) {
2798
+ const root = opts.root ?? DEFAULT_GEMINI_ROOT;
2799
+ const files = await listSessionFiles(root);
2800
+ let chosen;
2801
+ for (const file of files) {
2802
+ if (file.filenameId === id || id.startsWith(file.filenameId)) {
2803
+ chosen = file;
2804
+ break;
2805
+ }
2806
+ }
2807
+ if (!chosen) {
2808
+ for (const file of files) {
2809
+ const { meta: meta2 } = await parseSession(file).catch(() => ({ meta: { id: "" } }));
2810
+ if (meta2.id === id) {
2811
+ chosen = file;
2812
+ break;
2813
+ }
2814
+ }
2815
+ }
2816
+ if (!chosen)
2817
+ return null;
2818
+ const cached = detailCache3.get(chosen.filePath);
2819
+ if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
2820
+ return cached.detail;
2821
+ }
2822
+ const { meta, events } = await parseSession(chosen);
2823
+ const detail = { ...meta, events };
2824
+ detailCache3.set(chosen.filePath, {
2825
+ detail,
2826
+ mtimeMs: chosen.mtimeMs,
2827
+ sizeBytes: chosen.sizeBytes
2828
+ });
2829
+ return detail;
2830
+ }
2831
+ function geminiSessionLocalDay(meta) {
2832
+ if (!meta.firstTimestamp)
2833
+ return void 0;
2834
+ const ms = Date.parse(meta.firstTimestamp);
2835
+ return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
2836
+ }
2837
+ var DEFAULT_GEMINI_ROOT, GEMINI_PROJECTS_FILE, SESSION_FILE_RE, IDLE_GAP_MS2, projectsCache, metaCache3, detailCache3;
2838
+ var init_gemini = __esm({
2839
+ "../parser/dist/gemini.js"() {
2840
+ "use strict";
2841
+ init_analytics();
2842
+ DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
2843
+ GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
2844
+ SESSION_FILE_RE = /^session-.+\.(jsonl|json)$/;
2845
+ IDLE_GAP_MS2 = 3 * 60 * 1e3;
2846
+ projectsCache = null;
2847
+ metaCache3 = /* @__PURE__ */ new Map();
2848
+ detailCache3 = /* @__PURE__ */ new Map();
2849
+ }
2850
+ });
2851
+
2345
2852
  // ../parser/dist/fs.js
2346
2853
  var fs_exports = {};
2347
2854
  __export(fs_exports, {
2348
2855
  DEFAULT_CODEX_ROOT: () => DEFAULT_CODEX_ROOT,
2856
+ DEFAULT_GEMINI_ROOT: () => DEFAULT_GEMINI_ROOT,
2349
2857
  DEFAULT_ROOT: () => DEFAULT_ROOT,
2350
2858
  agentSources: () => agentSources,
2351
2859
  buildCalibrationCurve: () => buildCalibrationCurve,
@@ -2354,14 +2862,17 @@ __export(fs_exports, {
2354
2862
  codexSessionLocalDay: () => codexSessionLocalDay,
2355
2863
  decodeProjectName: () => decodeProjectName,
2356
2864
  findTeamLead: () => findTeamLead,
2865
+ geminiSessionLocalDay: () => geminiSessionLocalDay,
2357
2866
  getAgentSource: () => getAgentSource,
2358
2867
  getAnySession: () => getAnySession,
2359
2868
  getCodexSession: () => getCodexSession,
2869
+ getGeminiSession: () => getGeminiSession,
2360
2870
  getLatestCodexUsage: () => getLatestCodexUsage,
2361
2871
  getSession: () => getSession,
2362
2872
  invalidateFile: () => invalidateFile,
2363
2873
  listAllSessions: () => listAllSessions,
2364
2874
  listCodexSessions: () => listCodexSessions,
2875
+ listGeminiSessions: () => listGeminiSessions,
2365
2876
  listProjects: () => listProjects,
2366
2877
  listSessions: () => listSessions,
2367
2878
  loadCalibrationCurve: () => loadCalibrationCurve,
@@ -2373,15 +2884,16 @@ __export(fs_exports, {
2373
2884
  sessionIdFromFileName: () => sessionIdFromFileName,
2374
2885
  walkJsonlFiles: () => walkJsonlFiles
2375
2886
  });
2376
- import { promises as fs3 } from "node:fs";
2377
- import os3 from "node:os";
2378
- import path3 from "node:path";
2887
+ import { promises as fs4 } from "node:fs";
2888
+ import os4 from "node:os";
2889
+ import path4 from "node:path";
2379
2890
  function cacheStats() {
2380
2891
  return claudeCodeCacheStats();
2381
2892
  }
2382
2893
  function clearCaches() {
2383
2894
  clearClaudeCodeCaches();
2384
2895
  clearCodexCaches();
2896
+ clearGeminiCaches();
2385
2897
  }
2386
2898
  function invalidateFile(fullPath) {
2387
2899
  invalidateClaudeCodeFile(fullPath);
@@ -2410,7 +2922,7 @@ async function getAnySession(id) {
2410
2922
  async function loadUsageByDay(start, end) {
2411
2923
  let raw;
2412
2924
  try {
2413
- raw = await fs3.readFile(USAGE_LOG, "utf8");
2925
+ raw = await fs4.readFile(USAGE_LOG, "utf8");
2414
2926
  } catch {
2415
2927
  return { by_day: [] };
2416
2928
  }
@@ -2455,7 +2967,7 @@ async function loadUsageByDay(start, end) {
2455
2967
  async function loadCalibrationSnapshots() {
2456
2968
  let raw;
2457
2969
  try {
2458
- raw = await fs3.readFile(USAGE_LOG, "utf8");
2970
+ raw = await fs4.readFile(USAGE_LOG, "utf8");
2459
2971
  } catch {
2460
2972
  return [];
2461
2973
  }
@@ -2613,7 +3125,7 @@ async function loadCalibrationCurve(tier = "pro-max-20x", root = DEFAULT_ROOT, g
2613
3125
  ]);
2614
3126
  return buildCalibrationCurve(events, snapshots, tier, granularityMin);
2615
3127
  }
2616
- var codexSource, agentSources, USAGE_LOG;
3128
+ var codexSource, geminiSource, agentSources, USAGE_LOG;
2617
3129
  var init_fs = __esm({
2618
3130
  "../parser/dist/fs.js"() {
2619
3131
  "use strict";
@@ -2622,8 +3134,10 @@ var init_fs = __esm({
2622
3134
  init_calibration();
2623
3135
  init_claude_code();
2624
3136
  init_codex();
3137
+ init_gemini();
2625
3138
  init_claude_code();
2626
3139
  init_codex();
3140
+ init_gemini();
2627
3141
  codexSource = {
2628
3142
  ...CODEX_METADATA,
2629
3143
  defaultRoot: DEFAULT_CODEX_ROOT,
@@ -2645,8 +3159,18 @@ var init_fs = __esm({
2645
3159
  };
2646
3160
  }
2647
3161
  };
2648
- agentSources = [claudeCodeSource, codexSource];
2649
- USAGE_LOG = path3.join(os3.homedir(), ".cclens", "usage.jsonl");
3162
+ geminiSource = {
3163
+ ...GEMINI_METADATA,
3164
+ defaultRoot: DEFAULT_GEMINI_ROOT,
3165
+ async listSessions(opts) {
3166
+ return listGeminiSessions(opts);
3167
+ },
3168
+ async getSession(id) {
3169
+ return getGeminiSession(id);
3170
+ }
3171
+ };
3172
+ agentSources = [claudeCodeSource, codexSource, geminiSource];
3173
+ USAGE_LOG = path4.join(os4.homedir(), ".cclens", "usage.jsonl");
2650
3174
  }
2651
3175
  });
2652
3176
 
@@ -3051,6 +3575,7 @@ var dist_exports = {};
3051
3575
  __export(dist_exports, {
3052
3576
  CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
3053
3577
  CODEX_METADATA: () => CODEX_METADATA,
3578
+ GEMINI_METADATA: () => GEMINI_METADATA,
3054
3579
  PRICES: () => PRICES,
3055
3580
  RATE_PER_PCT: () => RATE_PER_PCT,
3056
3581
  RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
@@ -3144,9 +3669,9 @@ function readFromCredentialsFile() {
3144
3669
  join(homedir(), ".claude", ".credentials.json"),
3145
3670
  join(homedir(), ".config", "claude", "credentials.json")
3146
3671
  ];
3147
- for (const path4 of candidates) {
3672
+ for (const path5 of candidates) {
3148
3673
  try {
3149
- const blob = readFileSync(path4, "utf8");
3674
+ const blob = readFileSync(path5, "utf8");
3150
3675
  const creds = extractCredentials(blob);
3151
3676
  if (creds) return creds;
3152
3677
  } catch {
@@ -3964,7 +4489,7 @@ function viewEvent(ev) {
3964
4489
  cwd: rawCwd
3965
4490
  };
3966
4491
  }
3967
- var IDLE_GAP_MS2 = 3 * 60 * 1e3;
4492
+ var IDLE_GAP_MS3 = 3 * 60 * 1e3;
3968
4493
  var INTERRUPT_RE2 = /\[request interrupted|interrupted by user/i;
3969
4494
  var PR_TITLE_RE = /--title\s+["']([^"']+)["']/;
3970
4495
  var BASH_CHAIN_SPLIT_RE = /\|\||&&|;|\|/;
@@ -4076,7 +4601,7 @@ function closeTurn(t, closed, cwd) {
4076
4601
  let active = 0;
4077
4602
  for (let i = 1; i < ts.length; i++) {
4078
4603
  const dt = ts[i] - ts[i - 1];
4079
- if (dt < IDLE_GAP_MS2)
4604
+ if (dt < IDLE_GAP_MS3)
4080
4605
  active += dt;
4081
4606
  }
4082
4607
  closed.push({
@@ -4252,7 +4777,7 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
4252
4777
  let activeMs2 = 0;
4253
4778
  for (let i = 1; i < tsSorted.length; i++) {
4254
4779
  const dt = tsSorted[i] - tsSorted[i - 1];
4255
- if (dt < IDLE_GAP_MS2)
4780
+ if (dt < IDLE_GAP_MS3)
4256
4781
  activeMs2 += dt;
4257
4782
  }
4258
4783
  const tsSortedStrings = dayEvents.map((e) => e.timestamp).filter((t) => !!t).sort();
@@ -5267,8 +5792,8 @@ function getErrorMap() {
5267
5792
 
5268
5793
  // ../../node_modules/zod/v3/helpers/parseUtil.js
5269
5794
  var makeIssue = (params) => {
5270
- const { data, path: path4, errorMaps, issueData } = params;
5271
- const fullPath = [...path4, ...issueData.path || []];
5795
+ const { data, path: path5, errorMaps, issueData } = params;
5796
+ const fullPath = [...path5, ...issueData.path || []];
5272
5797
  const fullIssue = {
5273
5798
  ...issueData,
5274
5799
  path: fullPath
@@ -5384,11 +5909,11 @@ var errorUtil;
5384
5909
 
5385
5910
  // ../../node_modules/zod/v3/types.js
5386
5911
  var ParseInputLazyPath = class {
5387
- constructor(parent, value, path4, key) {
5912
+ constructor(parent, value, path5, key) {
5388
5913
  this._cachedPath = [];
5389
5914
  this.parent = parent;
5390
5915
  this.data = value;
5391
- this._path = path4;
5916
+ this._path = path5;
5392
5917
  this._key = key;
5393
5918
  }
5394
5919
  get path() {
@@ -8958,15 +9483,15 @@ function newRunId(kind) {
8958
9483
  function tracePath(runId) {
8959
9484
  return join9(RUNS_DIR, `${runId}.jsonl`);
8960
9485
  }
8961
- function safeAppend(path4, line) {
9486
+ function safeAppend(path5, line) {
8962
9487
  try {
8963
- appendFileSync3(path4, line);
9488
+ appendFileSync3(path5, line);
8964
9489
  } catch {
8965
9490
  }
8966
9491
  }
8967
- function safeWrite(path4, line) {
9492
+ function safeWrite(path5, line) {
8968
9493
  try {
8969
- writeFileSync7(path4, line);
9494
+ writeFileSync7(path5, line);
8970
9495
  } catch {
8971
9496
  }
8972
9497
  }
@@ -9602,7 +10127,7 @@ function rollupOutcomeDay(entries) {
9602
10127
  return "exploratory";
9603
10128
  return "trivial";
9604
10129
  }
9605
- function truncate3(s, max) {
10130
+ function truncate4(s, max) {
9606
10131
  if (s.length <= max)
9607
10132
  return s;
9608
10133
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -9658,7 +10183,7 @@ function computeDaySignals(entries) {
9658
10183
  type,
9659
10184
  count: v.count,
9660
10185
  sample_description: v.sample_description,
9661
- sample_prompt_preview: truncate3(v.sample_prompt_preview, 200)
10186
+ sample_prompt_preview: truncate4(v.sample_prompt_preview, 200)
9662
10187
  }));
9663
10188
  const frameCounts = /* @__PURE__ */ new Map();
9664
10189
  for (const s of signalsList) {
@@ -9677,7 +10202,7 @@ function computeDaySignals(entries) {
9677
10202
  if ((e.first_user ?? "").length > 0)
9678
10203
  verbosity_distribution[s.verbosity] += 1;
9679
10204
  for (const ref of s.external_refs) {
9680
- external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate3(ref.preview, 200) });
10205
+ external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate4(ref.preview, 200) });
9681
10206
  }
9682
10207
  const ints = e.numbers.interrupts ?? 0;
9683
10208
  interrupts += ints;
@@ -10520,7 +11045,7 @@ function computeInteractionModes(entries) {
10520
11045
  date: entry.local_day,
10521
11046
  project_display: prettyProject3(entry.project),
10522
11047
  type: sa.type,
10523
- prompt_preview: truncate4(sa.prompt_preview, 200)
11048
+ prompt_preview: truncate5(sa.prompt_preview, 200)
10524
11049
  });
10525
11050
  }
10526
11051
  const skillExamples = [];
@@ -10537,7 +11062,7 @@ function computeInteractionModes(entries) {
10537
11062
  skillExamples.push({
10538
11063
  date: e.local_day,
10539
11064
  skill,
10540
- first_user_preview: truncate4(e.first_user, 200)
11065
+ first_user_preview: truncate5(e.first_user, 200)
10541
11066
  });
10542
11067
  }
10543
11068
  }
@@ -10554,7 +11079,7 @@ function computeInteractionModes(entries) {
10554
11079
  project_display: prettyProject3(longestTurnEntry.project),
10555
11080
  active_min: longestTurnEntry.numbers.active_min,
10556
11081
  top_tools: longestTurnEntry.top_tools.slice(0, 5),
10557
- first_user_preview: truncate4(longestTurnEntry.first_user, 200)
11082
+ first_user_preview: truncate5(longestTurnEntry.first_user, 200)
10558
11083
  } : null;
10559
11084
  const tools_per_turn = turn_count > 0 ? tools_total / turn_count : 0;
10560
11085
  const label = tools_per_turn < 5 ? "rapid" : tools_per_turn < 15 ? "mixed" : "batch";
@@ -10585,7 +11110,7 @@ function computeInteractionModes(entries) {
10585
11110
  }
10586
11111
  };
10587
11112
  }
10588
- function truncate4(s, max) {
11113
+ function truncate5(s, max) {
10589
11114
  if (s.length <= max)
10590
11115
  return s;
10591
11116
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -10642,7 +11167,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
10642
11167
  evidence_subagent = {
10643
11168
  type: sa.type,
10644
11169
  description: sa.description,
10645
- prompt_preview: truncate4(sa.prompt_preview, 200)
11170
+ prompt_preview: truncate5(sa.prompt_preview, 200)
10646
11171
  };
10647
11172
  }
10648
11173
  const project_display = repEntry ? prettyProject3(repEntry.project) : dd.projects[0]?.display_name ?? "";
@@ -10653,7 +11178,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
10653
11178
  outcome: dayOutcome.get(dd.key) ?? null,
10654
11179
  helpfulness: dayHelp.get(dd.key) ?? null,
10655
11180
  evidence_subagent,
10656
- evidence_first_user: repEntry?.first_user ? truncate4(repEntry.first_user, 200) : null,
11181
+ evidence_first_user: repEntry?.first_user ? truncate5(repEntry.first_user, 200) : null,
10657
11182
  day_signature: dd.day_signature ?? null
10658
11183
  };
10659
11184
  });
@@ -10728,7 +11253,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
10728
11253
  date: day,
10729
11254
  session_id: ref.session_id,
10730
11255
  ref_kind: ref.kind,
10731
- preview: truncate4(ref.preview, 200)
11256
+ preview: truncate5(ref.preview, 200)
10732
11257
  });
10733
11258
  }
10734
11259
  total_interrupts += signals.comm_style.steering.interrupts;
@@ -10800,7 +11325,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
10800
11325
  count: v.count,
10801
11326
  days: [...v.days].sort(),
10802
11327
  sample_description: v.sample_description,
10803
- sample_prompt_preview: truncate4(v.sample_prompt_preview, 200)
11328
+ sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
10804
11329
  })),
10805
11330
  threads,
10806
11331
  communication_style: {
@@ -11100,7 +11625,7 @@ var MonthDigestResponseSchema = external_exports.object({
11100
11625
  }).passthrough();
11101
11626
 
11102
11627
  // ../entries/dist/top-sessions.js
11103
- var IDLE_GAP_MS3 = 3 * 60 * 1e3;
11628
+ var IDLE_GAP_MS4 = 3 * 60 * 1e3;
11104
11629
  var LONG_AUTONOMOUS_MIN = 20;
11105
11630
  var N_USER = 150;
11106
11631
  var N_FIRST_AGENT = 150;
@@ -11131,7 +11656,7 @@ function activeMs(timestamps) {
11131
11656
  let active = 0;
11132
11657
  for (let i = 1; i < ts.length; i++) {
11133
11658
  const dt = ts[i] - ts[i - 1];
11134
- if (dt < IDLE_GAP_MS3)
11659
+ if (dt < IDLE_GAP_MS4)
11135
11660
  active += dt;
11136
11661
  }
11137
11662
  return active;
@@ -11305,7 +11830,7 @@ function buildSessionSlice(entry, events, daySignature) {
11305
11830
  let intEnd = sortedTs[0];
11306
11831
  for (let i = 1; i < sortedTs.length; i++) {
11307
11832
  const dt = sortedTs[i] - intEnd;
11308
- if (dt >= IDLE_GAP_MS3) {
11833
+ if (dt >= IDLE_GAP_MS4) {
11309
11834
  intervals.push({
11310
11835
  start_min: fmtMin(intStart - sliceStartMs),
11311
11836
  end_min: fmtMin(intEnd - sliceStartMs)