fleetlens 0.16.0 → 0.16.2

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 (133) 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.js.nft.json +1 -1
  12. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/app/apps/web/.next/server/app/agent/page.js.nft.json +1 -1
  14. package/app/apps/web/.next/server/app/agent/page_client-reference-manifest.js +1 -1
  15. package/app/apps/web/.next/server/app/api/agent/chats/[id]/events/route.js.nft.json +1 -1
  16. package/app/apps/web/.next/server/app/api/agent/chats/[id]/messages/route.js.nft.json +1 -1
  17. package/app/apps/web/.next/server/app/api/agent/chats/[id]/route.js.nft.json +1 -1
  18. package/app/apps/web/.next/server/app/api/agent/chats/[id]/stop/route.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/api/agent/chats/route.js.nft.json +1 -1
  20. package/app/apps/web/.next/server/app/api/agent/index/route.js.nft.json +1 -1
  21. package/app/apps/web/.next/server/app/api/agent/mcp/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/agent/suggestions/route.js.nft.json +1 -1
  23. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  24. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  25. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  26. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  27. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  29. package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -1
  31. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/api/projects/open-folder/route.js.nft.json +1 -1
  33. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  34. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  35. package/app/apps/web/.next/server/app/api/runs/route.js.nft.json +1 -1
  36. package/app/apps/web/.next/server/app/api/settings/credentials/route.js.nft.json +1 -1
  37. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  38. package/app/apps/web/.next/server/app/api/team/autostart/route.js.nft.json +1 -1
  39. package/app/apps/web/.next/server/app/api/team/onboarding/start/route.js.nft.json +1 -1
  40. package/app/apps/web/.next/server/app/api/team/sync-projects/route.js.nft.json +1 -1
  41. package/app/apps/web/.next/server/app/api/workflow-agent/route.js.nft.json +1 -1
  42. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  43. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  44. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  45. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  46. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  47. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  48. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  49. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  50. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  51. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  52. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  53. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  54. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  55. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  56. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  57. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  58. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  59. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  60. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -1
  61. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
  62. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  63. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  64. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  65. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  66. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  67. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  68. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  69. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  70. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  71. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  72. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  73. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  74. package/app/apps/web/.next/server/app/team/onboarding/page.js.nft.json +1 -1
  75. package/app/apps/web/.next/server/app/team/onboarding/page_client-reference-manifest.js +1 -1
  76. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  77. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  78. package/app/apps/web/.next/server/app/usage/page.js +2 -1
  79. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  80. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  81. package/app/apps/web/.next/server/chunks/[root-of-the-server]__02faosk._.js +3 -3
  82. package/app/apps/web/.next/server/chunks/[root-of-the-server]__09cgmam._.js +2 -2
  83. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0tk8p3d._.js +2 -2
  84. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0u6pamj._.js +2 -2
  85. package/app/apps/web/.next/server/chunks/[root-of-the-server]__12jomao._.js +2 -2
  86. package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0sr4wr_.js +1 -1
  87. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +1 -1
  88. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +1 -1
  89. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0f3q8gt._.js +3 -0
  90. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__11xp-1u._.js +3 -0
  91. package/app/apps/web/.next/server/chunks/ssr/_0k8yioi._.js +1 -1
  92. package/app/apps/web/.next/server/chunks/ssr/apps_web_0epqfet._.js +3 -0
  93. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_sessions_[id]_session-view_tsx_0-9t5~.._.js +1 -1
  94. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_sessions_sessions-grid_tsx_0bri5x.._.js +1 -1
  95. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0x014hn._.js +1 -1
  96. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_usage-charts-dashboard_tsx_0bgr_uv._.js +1 -1
  97. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
  98. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
  99. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0mx_509._.js +1 -1
  100. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  101. package/app/apps/web/.next/server/middleware-manifest.json +5 -5
  102. package/app/apps/web/.next/server/pages/500.html +1 -1
  103. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  104. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  105. package/app/apps/web/.next/static/chunks/0jes0m38a9ib_.js +14 -0
  106. package/app/apps/web/.next/static/chunks/{07bzlfv97o1ig.js → 0p5ee8wje3zi~.js} +1 -1
  107. package/app/apps/web/.next/static/chunks/{0_0~~ipv90vm3.js → 0rrcj195v1nd..js} +1 -1
  108. package/app/apps/web/.next/static/chunks/{0awkd5df28gvj.js → 0~uugvb4izjd2.js} +1 -1
  109. package/app/apps/web/app/sessions/[id]/session-view.tsx +6 -2
  110. package/app/apps/web/app/sessions/sessions-grid.tsx +5 -1
  111. package/app/apps/web/app/usage/page.tsx +166 -2
  112. package/app/apps/web/components/agent-badge.tsx +3 -0
  113. package/app/apps/web/components/agent-icon.tsx +42 -4
  114. package/app/apps/web/components/menubar-install-banner.tsx +2 -1
  115. package/app/apps/web/components/usage-charts-dashboard.tsx +9 -1
  116. package/app/apps/web/lib/agent/run.ts +24 -5
  117. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  118. package/app/apps/web/package.json +1 -1
  119. package/app/apps/web/public/agent-icons/grok.svg +8 -0
  120. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  121. package/dist/daemon-worker.js +1173 -123
  122. package/dist/index.js +1230 -167
  123. package/menubar/FleetlensMenubar.app/Contents/Info.plist +2 -2
  124. package/menubar/FleetlensMenubar.app/Contents/MacOS/FleetlensMenubar +0 -0
  125. package/menubar/FleetlensMenubar.app/Contents/Resources/grok.svg +8 -0
  126. package/menubar/FleetlensMenubar.app/Contents/_CodeSignature/CodeResources +11 -0
  127. package/package.json +1 -1
  128. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ns6ydi._.js +0 -3
  129. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +0 -3
  130. package/app/apps/web/.next/static/chunks/0mry~475v0fa3.js +0 -14
  131. /package/app/apps/web/.next/static/{bTww6lPxII4wde65VQDrF → q_fQaCe85j7F9VawBRe81}/_buildManifest.js +0 -0
  132. /package/app/apps/web/.next/static/{bTww6lPxII4wde65VQDrF → q_fQaCe85j7F9VawBRe81}/_clientMiddlewareManifest.js +0 -0
  133. /package/app/apps/web/.next/static/{bTww6lPxII4wde65VQDrF → q_fQaCe85j7F9VawBRe81}/_ssgManifest.js +0 -0
@@ -607,7 +607,7 @@ function getAgentMetadata(kind) {
607
607
  function isAgentKind(s) {
608
608
  return typeof s === "string" && KNOWN_AGENT_KINDS.has(s);
609
609
  }
610
- var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, ZAI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
610
+ var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, ZAI_METADATA, GROK_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
611
611
  var init_agent_metadata = __esm({
612
612
  "../parser/dist/agent-metadata.js"() {
613
613
  "use strict";
@@ -653,13 +653,22 @@ var init_agent_metadata = __esm({
653
653
  accentColor: "rgb(59, 130, 246)",
654
654
  iconChar: "Z"
655
655
  };
656
+ GROK_METADATA = {
657
+ kind: "grok",
658
+ displayName: "Grok Build",
659
+ shortLabel: "Grok",
660
+ // Slate-400 — visible on dark Fleetlens chrome and still fine on light.
661
+ accentColor: "rgb(100, 116, 139)",
662
+ iconChar: "\u25C8"
663
+ };
656
664
  agentMetadata = [
657
665
  CLAUDE_CODE_METADATA,
658
666
  CODEX_METADATA,
659
667
  GEMINI_METADATA,
660
668
  ANTIGRAVITY_METADATA,
661
669
  COWORK_METADATA,
662
- ZAI_METADATA
670
+ ZAI_METADATA,
671
+ GROK_METADATA
663
672
  ];
664
673
  KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
665
674
  }
@@ -1516,11 +1525,11 @@ function defaultBranch(commonDir) {
1516
1525
  }
1517
1526
  return void 0;
1518
1527
  }
1519
- function readGitFolder(path7) {
1520
- if (!existsSync(path7))
1528
+ function readGitFolder(path9) {
1529
+ if (!existsSync(path9))
1521
1530
  return { exists: false, isWorktree: false };
1522
1531
  try {
1523
- const git = nearestDotGit(realpathOrSelf(path7));
1532
+ const git = nearestDotGit(realpathOrSelf(path9));
1524
1533
  if (!git)
1525
1534
  return { exists: true, isWorktree: false };
1526
1535
  const projectRoot = projectRootFromCommonDir(git.commonDir);
@@ -2776,6 +2785,11 @@ function parseRollout(file, lines) {
2776
2785
  let lastUserPreview;
2777
2786
  let lastAgentPreview;
2778
2787
  const tsMs = [];
2788
+ let threadSource;
2789
+ let rootSessionId;
2790
+ let parentThreadId;
2791
+ let agentNickname;
2792
+ let agentPath;
2779
2793
  let idx = 0;
2780
2794
  for (const line of lines) {
2781
2795
  if (typeof line !== "object" || line === null)
@@ -2796,6 +2810,16 @@ function parseRollout(file, lines) {
2796
2810
  if (type === "session_meta") {
2797
2811
  if (typeof payload.cwd === "string")
2798
2812
  cwd = payload.cwd;
2813
+ if (threadSource === void 0 && typeof payload.thread_source === "string")
2814
+ threadSource = payload.thread_source;
2815
+ if (rootSessionId === void 0 && typeof payload.session_id === "string")
2816
+ rootSessionId = payload.session_id;
2817
+ if (parentThreadId === void 0 && typeof payload.parent_thread_id === "string")
2818
+ parentThreadId = payload.parent_thread_id;
2819
+ if (agentNickname === void 0 && typeof payload.agent_nickname === "string")
2820
+ agentNickname = payload.agent_nickname;
2821
+ if (agentPath === void 0 && typeof payload.agent_path === "string")
2822
+ agentPath = payload.agent_path;
2799
2823
  continue;
2800
2824
  }
2801
2825
  if (type === "turn_context") {
@@ -2999,7 +3023,7 @@ function parseRollout(file, lines) {
2999
3023
  airTimeMs,
3000
3024
  activeSegments
3001
3025
  };
3002
- return { meta, events };
3026
+ return { meta, events, threadSource, rootSessionId, parentThreadId, agentNickname, agentPath };
3003
3027
  }
3004
3028
  function numberOf(v) {
3005
3029
  return typeof v === "number" && Number.isFinite(v) ? v : void 0;
@@ -3037,28 +3061,112 @@ function clearCodexCaches() {
3037
3061
  metaCache2.clear();
3038
3062
  detailCache2.clear();
3039
3063
  }
3040
- async function listCodexSessions(opts = {}) {
3041
- const root = opts.root ?? DEFAULT_CODEX_ROOT;
3064
+ async function scanAllCodex(root) {
3042
3065
  const files = await listRolloutFiles(root);
3043
3066
  const out = [];
3044
3067
  for (const file of files) {
3045
3068
  const cached = metaCache2.get(file.filePath);
3046
3069
  if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
3047
- out.push(cached.meta);
3070
+ out.push({
3071
+ file,
3072
+ meta: cached.meta,
3073
+ threadSource: cached.threadSource,
3074
+ rootSessionId: cached.rootSessionId,
3075
+ parentThreadId: cached.parentThreadId,
3076
+ agentNickname: cached.agentNickname,
3077
+ agentPath: cached.agentPath
3078
+ });
3048
3079
  continue;
3049
3080
  }
3050
3081
  try {
3051
3082
  const lines = await readJsonl(file.filePath);
3052
- const { meta } = parseRollout(file, lines);
3083
+ const parsed = parseRollout(file, lines);
3053
3084
  metaCache2.set(file.filePath, {
3054
- meta,
3085
+ meta: parsed.meta,
3055
3086
  mtimeMs: file.mtimeMs,
3056
- sizeBytes: file.sizeBytes
3087
+ sizeBytes: file.sizeBytes,
3088
+ threadSource: parsed.threadSource,
3089
+ rootSessionId: parsed.rootSessionId,
3090
+ parentThreadId: parsed.parentThreadId,
3091
+ agentNickname: parsed.agentNickname,
3092
+ agentPath: parsed.agentPath
3093
+ });
3094
+ out.push({
3095
+ file,
3096
+ meta: parsed.meta,
3097
+ threadSource: parsed.threadSource,
3098
+ rootSessionId: parsed.rootSessionId,
3099
+ parentThreadId: parsed.parentThreadId,
3100
+ agentNickname: parsed.agentNickname,
3101
+ agentPath: parsed.agentPath
3057
3102
  });
3058
- out.push(meta);
3059
3103
  } catch {
3060
3104
  }
3061
3105
  }
3106
+ return out;
3107
+ }
3108
+ function buildSubagentRun(entry, parentStartMs) {
3109
+ const meta = entry.meta;
3110
+ const startMs = meta.firstTimestamp ? Date.parse(meta.firstTimestamp) : void 0;
3111
+ const endMs = meta.lastTimestamp ? Date.parse(meta.lastTimestamp) : void 0;
3112
+ const startOk = startMs !== void 0 && Number.isFinite(startMs) ? startMs : void 0;
3113
+ const endOk = endMs !== void 0 && Number.isFinite(endMs) ? endMs : void 0;
3114
+ return {
3115
+ agentId: meta.id,
3116
+ agentType: entry.agentNickname ?? entry.agentPath ?? "subagent",
3117
+ description: entry.agentPath ?? entry.agentNickname ?? meta.id,
3118
+ startMs: startOk,
3119
+ endMs: endOk,
3120
+ durationMs: meta.durationMs,
3121
+ startTOffsetMs: parentStartMs !== void 0 && startOk !== void 0 ? Math.max(0, startOk - parentStartMs) : void 0,
3122
+ endTOffsetMs: parentStartMs !== void 0 && endOk !== void 0 ? Math.max(0, endOk - parentStartMs) : void 0,
3123
+ eventCount: meta.eventCount,
3124
+ totalUsage: meta.totalUsage,
3125
+ model: meta.model,
3126
+ toolCallCount: meta.toolCallCount,
3127
+ finalPreview: meta.lastAgentPreview
3128
+ };
3129
+ }
3130
+ async function listCodexSessions(opts = {}) {
3131
+ const root = opts.root ?? DEFAULT_CODEX_ROOT;
3132
+ const all = await scanAllCodex(root);
3133
+ const subagentsByRoot = /* @__PURE__ */ new Map();
3134
+ for (const entry of all) {
3135
+ if (entry.threadSource !== "subagent" || !entry.rootSessionId)
3136
+ continue;
3137
+ const list = subagentsByRoot.get(entry.rootSessionId);
3138
+ if (list)
3139
+ list.push(entry);
3140
+ else
3141
+ subagentsByRoot.set(entry.rootSessionId, [entry]);
3142
+ }
3143
+ const out = [];
3144
+ for (const entry of all) {
3145
+ if (entry.threadSource === "subagent")
3146
+ continue;
3147
+ const children = subagentsByRoot.get(entry.meta.id);
3148
+ if (!children || children.length === 0) {
3149
+ out.push(entry.meta);
3150
+ continue;
3151
+ }
3152
+ const merged = {
3153
+ ...entry.meta,
3154
+ spawnedAgentCount: children.length,
3155
+ totalUsage: {
3156
+ input: entry.meta.totalUsage.input + children.reduce((s, c) => s + c.meta.totalUsage.input, 0),
3157
+ output: entry.meta.totalUsage.output + children.reduce((s, c) => s + c.meta.totalUsage.output, 0),
3158
+ cacheRead: entry.meta.totalUsage.cacheRead + children.reduce((s, c) => s + c.meta.totalUsage.cacheRead, 0),
3159
+ cacheWrite: entry.meta.totalUsage.cacheWrite + children.reduce((s, c) => s + c.meta.totalUsage.cacheWrite, 0)
3160
+ },
3161
+ toolCallCount: (entry.meta.toolCallCount ?? 0) + children.reduce((s, c) => s + (c.meta.toolCallCount ?? 0), 0)
3162
+ };
3163
+ for (const c of children) {
3164
+ if (c.meta.lastTimestamp && (!merged.lastTimestamp || c.meta.lastTimestamp > merged.lastTimestamp)) {
3165
+ merged.lastTimestamp = c.meta.lastTimestamp;
3166
+ }
3167
+ }
3168
+ out.push(merged);
3169
+ }
3062
3170
  out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
3063
3171
  if (opts.limit !== void 0)
3064
3172
  return out.slice(0, opts.limit);
@@ -3066,17 +3174,41 @@ async function listCodexSessions(opts = {}) {
3066
3174
  }
3067
3175
  async function getCodexSession(id, opts = {}) {
3068
3176
  const root = opts.root ?? DEFAULT_CODEX_ROOT;
3069
- const files = await listRolloutFiles(root);
3070
- const file = files.find((f) => f.sessionId === id);
3071
- if (!file)
3072
- return null;
3177
+ const all = await scanAllCodex(root);
3178
+ const rootEntry = all.find((a) => a.meta.id === id && a.threadSource !== "subagent");
3179
+ if (!rootEntry) {
3180
+ const direct = all.find((a) => a.meta.id === id);
3181
+ if (!direct)
3182
+ return null;
3183
+ const cached2 = detailCache2.get(direct.file.filePath);
3184
+ if (cached2 && cached2.mtimeMs === direct.file.mtimeMs && cached2.sizeBytes === direct.file.sizeBytes) {
3185
+ return cached2.detail;
3186
+ }
3187
+ const lines2 = await readJsonl(direct.file.filePath);
3188
+ const { meta: meta2, events: events2 } = parseRollout(direct.file, lines2);
3189
+ const detail2 = { ...meta2, events: events2 };
3190
+ detailCache2.set(direct.file.filePath, {
3191
+ detail: detail2,
3192
+ mtimeMs: direct.file.mtimeMs,
3193
+ sizeBytes: direct.file.sizeBytes
3194
+ });
3195
+ return detail2;
3196
+ }
3197
+ const file = rootEntry.file;
3073
3198
  const cached = detailCache2.get(file.filePath);
3074
3199
  if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
3075
3200
  return cached.detail;
3076
3201
  }
3077
3202
  const lines = await readJsonl(file.filePath);
3078
3203
  const { meta, events } = parseRollout(file, lines);
3079
- const detail = { ...meta, events };
3204
+ const children = all.filter((a) => a.threadSource === "subagent" && a.rootSessionId === id);
3205
+ const parentStartMs = meta.firstTimestamp ? Date.parse(meta.firstTimestamp) : void 0;
3206
+ const subagents = children.map((c) => buildSubagentRun(c, parentStartMs)).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
3207
+ const detail = {
3208
+ ...meta,
3209
+ events,
3210
+ ...subagents.length > 0 ? { subagents, spawnedAgentCount: subagents.length } : {}
3211
+ };
3080
3212
  detailCache2.set(file.filePath, {
3081
3213
  detail,
3082
3214
  mtimeMs: file.mtimeMs,
@@ -4401,6 +4533,672 @@ var init_cowork = __esm({
4401
4533
  }
4402
4534
  });
4403
4535
 
4536
+ // ../parser/dist/grok.js
4537
+ import { promises as fs6 } from "node:fs";
4538
+ import os6 from "node:os";
4539
+ import path6 from "node:path";
4540
+ function resolveDefaultGrokRoot() {
4541
+ const home = process.env.GROK_HOME || path6.join(os6.homedir(), ".grok");
4542
+ return path6.join(home, "sessions");
4543
+ }
4544
+ async function safeReaddir5(p) {
4545
+ return fs6.readdir(p).catch(() => []);
4546
+ }
4547
+ async function safeReadJson(p) {
4548
+ const raw = await fs6.readFile(p, "utf8").catch(() => null);
4549
+ if (raw == null)
4550
+ return null;
4551
+ try {
4552
+ return JSON.parse(raw);
4553
+ } catch {
4554
+ return null;
4555
+ }
4556
+ }
4557
+ async function resolveEncodedCwd(groupDir, encoded) {
4558
+ const cwdFile = path6.join(groupDir, ".cwd");
4559
+ const fromFile = await fs6.readFile(cwdFile, "utf8").catch(() => null);
4560
+ if (fromFile && fromFile.trim())
4561
+ return fromFile.trim();
4562
+ try {
4563
+ return decodeURIComponent(encoded);
4564
+ } catch {
4565
+ return encoded;
4566
+ }
4567
+ }
4568
+ async function listSessionDirs(root) {
4569
+ const out = [];
4570
+ const groups = await safeReaddir5(root);
4571
+ for (const group of groups) {
4572
+ if (group === "session_search.sqlite" || group.startsWith("."))
4573
+ continue;
4574
+ const groupDir = path6.join(root, group);
4575
+ const groupStat = await fs6.stat(groupDir).catch(() => null);
4576
+ if (!groupStat?.isDirectory())
4577
+ continue;
4578
+ const decodedCwd = await resolveEncodedCwd(groupDir, group);
4579
+ const entries = await safeReaddir5(groupDir);
4580
+ for (const entry of entries) {
4581
+ if (entry === "prompt_history.jsonl" || entry.startsWith("."))
4582
+ continue;
4583
+ const dirPath = path6.join(groupDir, entry);
4584
+ const summaryPath = path6.join(dirPath, "summary.json");
4585
+ const updatesPath = path6.join(dirPath, "updates.jsonl");
4586
+ const signalsCandidate = path6.join(dirPath, "signals.json");
4587
+ const [summaryStat, updatesStat, signalsStat] = await Promise.all([
4588
+ fs6.stat(summaryPath).catch(() => null),
4589
+ fs6.stat(updatesPath).catch(() => null),
4590
+ fs6.stat(signalsCandidate).catch(() => null)
4591
+ ]);
4592
+ if (!summaryStat?.isFile())
4593
+ continue;
4594
+ const mtimeMs = Math.max(summaryStat.mtimeMs, updatesStat?.mtimeMs ?? 0);
4595
+ const sizeBytes = (updatesStat?.size ?? 0) + summaryStat.size;
4596
+ out.push({
4597
+ dirPath,
4598
+ updatesPath,
4599
+ summaryPath,
4600
+ signalsPath: signalsStat?.isFile() ? signalsCandidate : null,
4601
+ sessionId: entry,
4602
+ groupName: group,
4603
+ decodedCwd,
4604
+ mtimeMs,
4605
+ sizeBytes
4606
+ });
4607
+ }
4608
+ }
4609
+ return out;
4610
+ }
4611
+ function emptyUsage4() {
4612
+ return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
4613
+ }
4614
+ function previewOf4(text) {
4615
+ return text.replace(/\s+/g, " ").trim().slice(0, 200);
4616
+ }
4617
+ function truncate5(s, n) {
4618
+ return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
4619
+ }
4620
+ function textFromContent2(content) {
4621
+ if (!content)
4622
+ return "";
4623
+ if (typeof content === "string")
4624
+ return content;
4625
+ if (typeof content.text === "string")
4626
+ return content.text;
4627
+ return "";
4628
+ }
4629
+ function toolResultText(update) {
4630
+ const items = update.content;
4631
+ if (Array.isArray(items)) {
4632
+ const parts = [];
4633
+ for (const item of items) {
4634
+ if (!item || typeof item !== "object")
4635
+ continue;
4636
+ if (typeof item.text === "string" && item.text) {
4637
+ parts.push(item.text);
4638
+ continue;
4639
+ }
4640
+ const inner = item.content;
4641
+ if (typeof inner === "string" && inner)
4642
+ parts.push(inner);
4643
+ else if (inner && typeof inner === "object" && typeof inner.text === "string") {
4644
+ parts.push(inner.text);
4645
+ }
4646
+ }
4647
+ if (parts.length)
4648
+ return parts.join("\n");
4649
+ }
4650
+ const raw = update.rawOutput;
4651
+ if (raw == null)
4652
+ return "";
4653
+ if (typeof raw === "string")
4654
+ return raw;
4655
+ if (typeof raw === "object") {
4656
+ const r = raw;
4657
+ if (typeof r.output_for_prompt === "string")
4658
+ return r.output_for_prompt;
4659
+ if (typeof r.summary_for_prompt === "string")
4660
+ return r.summary_for_prompt;
4661
+ if (r.Content && typeof r.Content === "object") {
4662
+ const c = r.Content;
4663
+ if (typeof c.content === "string")
4664
+ return c.content;
4665
+ }
4666
+ if (r.TodosUpdated && typeof r.TodosUpdated === "object") {
4667
+ const t = r.TodosUpdated;
4668
+ if (typeof t.summary_for_prompt === "string")
4669
+ return t.summary_for_prompt;
4670
+ }
4671
+ if (Array.isArray(r.stdout) || Array.isArray(r.output)) {
4672
+ try {
4673
+ return JSON.stringify({
4674
+ type: r.type,
4675
+ exit_code: r.exit_code,
4676
+ note: "binary/stdout omitted"
4677
+ });
4678
+ } catch {
4679
+ return "";
4680
+ }
4681
+ }
4682
+ try {
4683
+ return JSON.stringify(raw);
4684
+ } catch {
4685
+ return "";
4686
+ }
4687
+ }
4688
+ return String(raw);
4689
+ }
4690
+ function toolNameOf(update) {
4691
+ const meta = update._meta;
4692
+ if (meta && typeof meta === "object") {
4693
+ const xai = meta["x.ai/tool"];
4694
+ if (xai && typeof xai === "object") {
4695
+ const name = xai.name;
4696
+ if (typeof name === "string" && name)
4697
+ return name;
4698
+ }
4699
+ }
4700
+ if (typeof update.title === "string" && update.title) {
4701
+ if (!update.title.includes(" ") && !update.title.includes("`"))
4702
+ return update.title;
4703
+ return update.title;
4704
+ }
4705
+ return "tool";
4706
+ }
4707
+ function statusOf(update) {
4708
+ const s = update.status;
4709
+ if (typeof s === "string")
4710
+ return s;
4711
+ if (s && typeof s === "object" && typeof s.status === "string")
4712
+ return s.status;
4713
+ return void 0;
4714
+ }
4715
+ function lineTimestampIso(line) {
4716
+ const meta = line.params?._meta;
4717
+ const agentMs = meta && typeof meta.agentTimestampMs === "number" ? meta.agentTimestampMs : void 0;
4718
+ if (agentMs != null && Number.isFinite(agentMs)) {
4719
+ return new Date(agentMs).toISOString();
4720
+ }
4721
+ const ts = line.timestamp;
4722
+ if (typeof ts === "number" && Number.isFinite(ts)) {
4723
+ const ms = ts > 1e12 ? ts : ts * 1e3;
4724
+ return new Date(ms).toISOString();
4725
+ }
4726
+ return void 0;
4727
+ }
4728
+ function computeActiveSegments5(tsMs) {
4729
+ if (tsMs.length === 0)
4730
+ return [];
4731
+ const sorted = [...tsMs].sort((a, b) => a - b);
4732
+ const out = [];
4733
+ let segStart = sorted[0];
4734
+ let segEnd = sorted[0];
4735
+ for (let i = 1; i < sorted.length; i++) {
4736
+ const t = sorted[i];
4737
+ if (t - segEnd > IDLE_GAP_MS4) {
4738
+ out.push({ startMs: segStart, endMs: segEnd });
4739
+ segStart = t;
4740
+ }
4741
+ segEnd = t;
4742
+ }
4743
+ out.push({ startMs: segStart, endMs: segEnd });
4744
+ return out;
4745
+ }
4746
+ async function parseSession3(dir) {
4747
+ const [summary, signals, updatesRaw] = await Promise.all([
4748
+ safeReadJson(dir.summaryPath),
4749
+ dir.signalsPath ? safeReadJson(dir.signalsPath) : Promise.resolve(null),
4750
+ fs6.readFile(dir.updatesPath, "utf8").catch(() => "")
4751
+ ]);
4752
+ const sessionId = summary?.info?.id ?? dir.sessionId;
4753
+ const cwd = summary?.info?.cwd ?? dir.decodedCwd;
4754
+ let model = summary?.current_model_id ?? signals?.primaryModelId ?? signals?.modelsUsed?.[0];
4755
+ const events = [];
4756
+ const totalUsage = emptyUsage4();
4757
+ if (signals?.contextTokensUsed && signals.contextTokensUsed > 0) {
4758
+ totalUsage.input = signals.contextTokensUsed;
4759
+ }
4760
+ let firstTimestamp;
4761
+ let lastTimestamp;
4762
+ let toolCallCount = 0;
4763
+ let turnCount = 0;
4764
+ let firstUserPreview;
4765
+ let lastUserPreview;
4766
+ let lastAgentPreview;
4767
+ const tsMs = [];
4768
+ let idx = 0;
4769
+ const completedToolResults = /* @__PURE__ */ new Set();
4770
+ let maxTotalTokens = 0;
4771
+ function noteTs(ts, role) {
4772
+ if (!ts || role === "meta")
4773
+ return;
4774
+ if (!firstTimestamp)
4775
+ firstTimestamp = ts;
4776
+ lastTimestamp = ts;
4777
+ const ms = Date.parse(ts);
4778
+ if (Number.isFinite(ms))
4779
+ tsMs.push(ms);
4780
+ }
4781
+ function pushEvent(e) {
4782
+ events.push(e);
4783
+ noteTs(e.timestamp, e.role);
4784
+ }
4785
+ let buf = null;
4786
+ function flushBuf() {
4787
+ if (!buf)
4788
+ return;
4789
+ const text = buf.texts.join("");
4790
+ const preview = previewOf4(text);
4791
+ if (buf.kind === "user") {
4792
+ const isHidden = !text || isFrameworkInjectedUserInput(text);
4793
+ if (text && !isHidden) {
4794
+ if (!firstUserPreview)
4795
+ firstUserPreview = preview;
4796
+ lastUserPreview = preview;
4797
+ turnCount += 1;
4798
+ }
4799
+ if (text) {
4800
+ pushEvent({
4801
+ index: idx++,
4802
+ timestamp: buf.firstTs,
4803
+ role: "user",
4804
+ rawType: "grok/user_message",
4805
+ preview,
4806
+ blocks: [{ type: "text", text }],
4807
+ messageId: buf.promptId,
4808
+ raw: buf.raw.length === 1 ? buf.raw[0] : buf.raw
4809
+ });
4810
+ }
4811
+ } else if (buf.kind === "agent") {
4812
+ if (text)
4813
+ lastAgentPreview = preview;
4814
+ if (text) {
4815
+ pushEvent({
4816
+ index: idx++,
4817
+ timestamp: buf.firstTs,
4818
+ role: "agent",
4819
+ rawType: "grok/agent_message",
4820
+ preview,
4821
+ blocks: [{ type: "text", text }],
4822
+ messageId: buf.promptId,
4823
+ model: buf.model ?? model,
4824
+ raw: buf.raw.length === 1 ? buf.raw[0] : buf.raw
4825
+ });
4826
+ }
4827
+ } else if (buf.kind === "thought") {
4828
+ if (text) {
4829
+ pushEvent({
4830
+ index: idx++,
4831
+ timestamp: buf.firstTs,
4832
+ role: "agent-thinking",
4833
+ rawType: "grok/agent_thought",
4834
+ preview,
4835
+ blocks: [{ type: "thinking", thinking: text }],
4836
+ messageId: buf.promptId,
4837
+ model: buf.model ?? model,
4838
+ raw: buf.raw.length === 1 ? buf.raw[0] : buf.raw
4839
+ });
4840
+ }
4841
+ }
4842
+ buf = null;
4843
+ }
4844
+ function appendChunk(kind, text, ts, promptId, modelId, raw) {
4845
+ if (!text && kind === "user")
4846
+ return;
4847
+ if (buf && buf.kind !== kind)
4848
+ flushBuf();
4849
+ if (!buf) {
4850
+ buf = {
4851
+ kind,
4852
+ texts: [],
4853
+ firstTs: ts,
4854
+ lastTs: ts,
4855
+ model: modelId,
4856
+ promptId,
4857
+ raw: []
4858
+ };
4859
+ }
4860
+ if (text)
4861
+ buf.texts.push(text);
4862
+ buf.lastTs = ts ?? buf.lastTs;
4863
+ if (modelId)
4864
+ buf.model = modelId;
4865
+ if (promptId)
4866
+ buf.promptId = promptId;
4867
+ buf.raw.push(raw);
4868
+ }
4869
+ const lines = updatesRaw.split("\n");
4870
+ for (const line of lines) {
4871
+ const trimmed = line.trim();
4872
+ if (!trimmed)
4873
+ continue;
4874
+ let obj;
4875
+ try {
4876
+ obj = JSON.parse(trimmed);
4877
+ } catch {
4878
+ continue;
4879
+ }
4880
+ const update = obj.params?.update;
4881
+ if (!update || typeof update !== "object")
4882
+ continue;
4883
+ const st = update.sessionUpdate;
4884
+ if (!st)
4885
+ continue;
4886
+ const ts = lineTimestampIso(obj);
4887
+ const lineMeta = obj.params?._meta ?? {};
4888
+ const updateMeta = update._meta ?? {};
4889
+ const promptId = typeof lineMeta.promptId === "string" && lineMeta.promptId || typeof updateMeta.promptId === "string" && updateMeta.promptId || void 0;
4890
+ const modelId = typeof updateMeta.modelId === "string" && updateMeta.modelId || typeof lineMeta.modelId === "string" && lineMeta.modelId || void 0;
4891
+ if (modelId)
4892
+ model = modelId;
4893
+ const totalTok = lineMeta.totalTokens;
4894
+ if (typeof totalTok === "number" && totalTok > maxTotalTokens) {
4895
+ maxTotalTokens = totalTok;
4896
+ }
4897
+ if (st === "user_message_chunk") {
4898
+ const text = textFromContent2(update.content);
4899
+ appendChunk("user", text, ts, promptId, modelId, obj);
4900
+ continue;
4901
+ }
4902
+ if (st === "agent_message_chunk") {
4903
+ const text = textFromContent2(update.content);
4904
+ appendChunk("agent", text, ts, promptId, modelId, obj);
4905
+ continue;
4906
+ }
4907
+ if (st === "agent_thought_chunk") {
4908
+ const text = textFromContent2(update.content);
4909
+ appendChunk("thought", text, ts, promptId, modelId, obj);
4910
+ continue;
4911
+ }
4912
+ flushBuf();
4913
+ if (st === "tool_call") {
4914
+ const toolCallId = typeof update.toolCallId === "string" ? update.toolCallId : `grok-${idx}`;
4915
+ const name = toolNameOf(update);
4916
+ const input = update.rawInput ?? {};
4917
+ const argsStr = input ? JSON.stringify(input) : "";
4918
+ toolCallCount += 1;
4919
+ pushEvent({
4920
+ index: idx++,
4921
+ timestamp: ts,
4922
+ role: "tool-call",
4923
+ rawType: "grok/tool_call",
4924
+ preview: `${name}(${truncate5(argsStr, 80)})`,
4925
+ blocks: [{ type: "tool_use", id: toolCallId, name, input }],
4926
+ toolName: name,
4927
+ toolUseId: toolCallId,
4928
+ model,
4929
+ raw: obj
4930
+ });
4931
+ continue;
4932
+ }
4933
+ if (st === "tool_call_update") {
4934
+ const status = statusOf(update);
4935
+ if (status !== "completed" && status !== "failed" && status !== "error" && status !== "cancelled") {
4936
+ continue;
4937
+ }
4938
+ const toolCallId = typeof update.toolCallId === "string" ? update.toolCallId : "";
4939
+ if (toolCallId && completedToolResults.has(toolCallId))
4940
+ continue;
4941
+ if (toolCallId)
4942
+ completedToolResults.add(toolCallId);
4943
+ const resultText = toolResultText(update);
4944
+ const isError = status === "failed" || status === "error" || status === "cancelled";
4945
+ pushEvent({
4946
+ index: idx++,
4947
+ timestamp: ts,
4948
+ role: "tool-result",
4949
+ rawType: "grok/tool_result",
4950
+ preview: previewOf4(resultText),
4951
+ blocks: [
4952
+ {
4953
+ type: "tool_result",
4954
+ tool_use_id: toolCallId,
4955
+ content: resultText,
4956
+ is_error: isError || void 0
4957
+ }
4958
+ ],
4959
+ toolUseId: toolCallId || void 0,
4960
+ toolResult: resultText,
4961
+ raw: obj
4962
+ });
4963
+ continue;
4964
+ }
4965
+ if (st === "turn_completed") {
4966
+ continue;
4967
+ }
4968
+ }
4969
+ flushBuf();
4970
+ if (totalUsage.input === 0 && maxTotalTokens > 0) {
4971
+ totalUsage.input = maxTotalTokens;
4972
+ }
4973
+ if (!firstTimestamp && summary?.created_at)
4974
+ firstTimestamp = summary.created_at;
4975
+ if (!lastTimestamp) {
4976
+ lastTimestamp = summary?.last_active_at ?? summary?.updated_at ?? firstTimestamp;
4977
+ }
4978
+ if (signals?.toolCallCount != null && signals.toolCallCount > toolCallCount) {
4979
+ toolCallCount = signals.toolCallCount;
4980
+ }
4981
+ if (signals?.turnCount != null && signals.turnCount > turnCount) {
4982
+ turnCount = signals.turnCount;
4983
+ }
4984
+ const startMs = firstTimestamp ? Date.parse(firstTimestamp) : void 0;
4985
+ if (startMs !== void 0 && Number.isFinite(startMs)) {
4986
+ let prevMs;
4987
+ for (const ev of events) {
4988
+ if (!ev.timestamp)
4989
+ continue;
4990
+ const ms = Date.parse(ev.timestamp);
4991
+ if (!Number.isFinite(ms))
4992
+ continue;
4993
+ ev.tOffsetMs = Math.max(0, ms - startMs);
4994
+ if (prevMs !== void 0)
4995
+ ev.gapMs = Math.max(0, ms - prevMs);
4996
+ prevMs = ms;
4997
+ }
4998
+ }
4999
+ const activeSegments = computeActiveSegments5(tsMs);
5000
+ const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
5001
+ const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
5002
+ const project = cwd ? resolveProjectIdentity(cwd) : void 0;
5003
+ const projectName = project?.projectName ?? cwd ?? dir.decodedCwd;
5004
+ const projectDir = dir.groupName || (cwd ? encodeURIComponent(cwd) : "(unknown)");
5005
+ if (!firstUserPreview) {
5006
+ const title = summary?.generated_title || summary?.session_summary;
5007
+ if (title)
5008
+ firstUserPreview = previewOf4(title);
5009
+ }
5010
+ const spawnedAgentCount = await countSubagentChildren(dir.dirPath);
5011
+ const meta = {
5012
+ agent: "grok",
5013
+ id: sessionId,
5014
+ filePath: dir.updatesPath,
5015
+ projectName,
5016
+ worktreeName: project?.worktreeName,
5017
+ repoName: project?.repoName,
5018
+ projectDir,
5019
+ sessionId,
5020
+ firstTimestamp,
5021
+ lastTimestamp,
5022
+ lastActivityMs: lastTimestamp ? Date.parse(lastTimestamp) : void 0,
5023
+ durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
5024
+ eventCount: events.length,
5025
+ model,
5026
+ cwd,
5027
+ gitBranch: summary?.head_branch,
5028
+ agentName: summary?.agent_name,
5029
+ totalUsage,
5030
+ status: "idle",
5031
+ firstUserPreview,
5032
+ lastUserPreview,
5033
+ lastAgentPreview,
5034
+ toolCallCount,
5035
+ turnCount,
5036
+ linesAdded: signals?.agentLinesAdded,
5037
+ linesRemoved: signals?.agentLinesRemoved,
5038
+ airTimeMs,
5039
+ activeSegments,
5040
+ ...spawnedAgentCount > 0 ? { spawnedAgentCount } : {}
5041
+ };
5042
+ return { meta, events, sessionKind: summary?.session_kind };
5043
+ }
5044
+ async function countSubagentChildren(dirPath) {
5045
+ const subRoot = path6.join(dirPath, "subagents");
5046
+ const entries = await safeReaddir5(subRoot);
5047
+ let n = 0;
5048
+ for (const e of entries) {
5049
+ const st = await fs6.stat(path6.join(subRoot, e)).catch(() => null);
5050
+ if (st?.isDirectory())
5051
+ n += 1;
5052
+ }
5053
+ return n;
5054
+ }
5055
+ async function loadGrokSubagents(parentDir, parentStartMs) {
5056
+ const subRoot = path6.join(parentDir.dirPath, "subagents");
5057
+ const entries = await safeReaddir5(subRoot);
5058
+ const groupDir = path6.dirname(parentDir.dirPath);
5059
+ const runs = [];
5060
+ for (const entry of entries) {
5061
+ const metaPath = path6.join(subRoot, entry, "meta.json");
5062
+ const meta = await safeReadJson(metaPath);
5063
+ if (!meta)
5064
+ continue;
5065
+ const childId = meta.child_session_id ?? meta.subagent_id ?? entry;
5066
+ const childDir = path6.join(groupDir, childId);
5067
+ const [childSummary, childSignals] = await Promise.all([
5068
+ safeReadJson(path6.join(childDir, "summary.json")),
5069
+ safeReadJson(path6.join(childDir, "signals.json"))
5070
+ ]);
5071
+ const startMs = childSummary?.created_at ? Date.parse(childSummary.created_at) : void 0;
5072
+ const endIso = childSummary?.last_active_at ?? childSummary?.updated_at;
5073
+ const endMs = endIso ? Date.parse(endIso) : void 0;
5074
+ const startOk = startMs !== void 0 && Number.isFinite(startMs) ? startMs : void 0;
5075
+ const endOk = endMs !== void 0 && Number.isFinite(endMs) ? endMs : void 0;
5076
+ const usage = emptyUsage4();
5077
+ if (childSignals?.contextTokensUsed)
5078
+ usage.input = childSignals.contextTokensUsed;
5079
+ runs.push({
5080
+ agentId: childId,
5081
+ agentType: meta.subagent_type ?? childSummary?.agent_name ?? "subagent",
5082
+ description: meta.description && meta.description.trim() || childSummary?.generated_title || childSummary?.session_summary || childId,
5083
+ startMs: startOk,
5084
+ endMs: endOk,
5085
+ durationMs: startOk !== void 0 && endOk !== void 0 ? Math.max(0, endOk - startOk) : void 0,
5086
+ startTOffsetMs: parentStartMs !== void 0 && startOk !== void 0 ? Math.max(0, startOk - parentStartMs) : void 0,
5087
+ endTOffsetMs: parentStartMs !== void 0 && endOk !== void 0 ? Math.max(0, endOk - parentStartMs) : void 0,
5088
+ eventCount: childSummary?.num_messages ?? childSummary?.num_chat_messages ?? 0,
5089
+ totalUsage: usage,
5090
+ prompt: typeof meta.prompt === "string" ? meta.prompt : void 0,
5091
+ model: childSummary?.current_model_id ?? childSignals?.primaryModelId,
5092
+ toolCallCount: childSignals?.toolCallCount
5093
+ });
5094
+ }
5095
+ runs.sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
5096
+ return runs;
5097
+ }
5098
+ function clearGrokCaches() {
5099
+ metaCache6.clear();
5100
+ detailCache6.clear();
5101
+ }
5102
+ async function listGrokSessions(opts = {}) {
5103
+ const root = opts.root ?? resolveDefaultGrokRoot();
5104
+ const dirs = await listSessionDirs(root);
5105
+ const out = [];
5106
+ for (const dir of dirs) {
5107
+ const summaryPeek = await safeReadJson(dir.summaryPath);
5108
+ if (summaryPeek?.session_kind === "subagent")
5109
+ continue;
5110
+ const cached = metaCache6.get(dir.dirPath);
5111
+ if (cached && cached.mtimeMs === dir.mtimeMs && cached.sizeBytes === dir.sizeBytes) {
5112
+ out.push(cached.meta);
5113
+ continue;
5114
+ }
5115
+ try {
5116
+ const { meta, sessionKind } = await parseSession3(dir);
5117
+ if (sessionKind === "subagent")
5118
+ continue;
5119
+ metaCache6.set(dir.dirPath, {
5120
+ meta,
5121
+ mtimeMs: dir.mtimeMs,
5122
+ sizeBytes: dir.sizeBytes
5123
+ });
5124
+ out.push(meta);
5125
+ } catch {
5126
+ }
5127
+ }
5128
+ out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
5129
+ if (opts.limit !== void 0)
5130
+ return out.slice(0, opts.limit);
5131
+ return out;
5132
+ }
5133
+ async function getGrokSession(id, opts = {}) {
5134
+ const root = opts.root ?? resolveDefaultGrokRoot();
5135
+ const dirs = await listSessionDirs(root);
5136
+ const chosen = dirs.find((d) => d.sessionId === id);
5137
+ if (!chosen) {
5138
+ for (const dir of dirs) {
5139
+ try {
5140
+ const { meta: meta2, events: events2 } = await parseSession3(dir);
5141
+ if (meta2.id === id) {
5142
+ const detail2 = { ...meta2, events: events2 };
5143
+ detailCache6.set(dir.dirPath, {
5144
+ detail: detail2,
5145
+ mtimeMs: dir.mtimeMs,
5146
+ sizeBytes: dir.sizeBytes
5147
+ });
5148
+ return detail2;
5149
+ }
5150
+ } catch {
5151
+ }
5152
+ }
5153
+ return null;
5154
+ }
5155
+ const cached = detailCache6.get(chosen.dirPath);
5156
+ if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
5157
+ return cached.detail;
5158
+ }
5159
+ const { meta, events } = await parseSession3(chosen);
5160
+ const parentStartMs = meta.firstTimestamp ? Date.parse(meta.firstTimestamp) : void 0;
5161
+ const subagents = await loadGrokSubagents(chosen, parentStartMs !== void 0 && Number.isFinite(parentStartMs) ? parentStartMs : void 0);
5162
+ const detail = {
5163
+ ...meta,
5164
+ events,
5165
+ ...subagents.length > 0 ? { subagents, spawnedAgentCount: subagents.length } : {}
5166
+ };
5167
+ detailCache6.set(chosen.dirPath, {
5168
+ detail,
5169
+ mtimeMs: chosen.mtimeMs,
5170
+ sizeBytes: chosen.sizeBytes
5171
+ });
5172
+ metaCache6.set(chosen.dirPath, {
5173
+ meta: {
5174
+ ...meta,
5175
+ ...subagents.length > 0 ? { spawnedAgentCount: subagents.length } : {}
5176
+ },
5177
+ mtimeMs: chosen.mtimeMs,
5178
+ sizeBytes: chosen.sizeBytes
5179
+ });
5180
+ return detail;
5181
+ }
5182
+ function grokSessionLocalDay(meta) {
5183
+ if (!meta.firstTimestamp)
5184
+ return void 0;
5185
+ const ms = Date.parse(meta.firstTimestamp);
5186
+ return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
5187
+ }
5188
+ var DEFAULT_GROK_ROOT, IDLE_GAP_MS4, metaCache6, detailCache6;
5189
+ var init_grok = __esm({
5190
+ "../parser/dist/grok.js"() {
5191
+ "use strict";
5192
+ init_analytics();
5193
+ init_git_project();
5194
+ init_user_input();
5195
+ DEFAULT_GROK_ROOT = path6.join(os6.homedir(), ".grok", "sessions");
5196
+ IDLE_GAP_MS4 = 3 * 60 * 1e3;
5197
+ metaCache6 = /* @__PURE__ */ new Map();
5198
+ detailCache6 = /* @__PURE__ */ new Map();
5199
+ }
5200
+ });
5201
+
4404
5202
  // ../parser/dist/team-config.js
4405
5203
  import { readFileSync as readFileSync3, writeFileSync, unlinkSync, mkdirSync, renameSync } from "node:fs";
4406
5204
  import { join as join3 } from "node:path";
@@ -4460,6 +5258,7 @@ __export(fs_exports, {
4460
5258
  DEFAULT_CODEX_ROOT: () => DEFAULT_CODEX_ROOT,
4461
5259
  DEFAULT_COWORK_ROOT: () => DEFAULT_COWORK_ROOT,
4462
5260
  DEFAULT_GEMINI_ROOT: () => DEFAULT_GEMINI_ROOT,
5261
+ DEFAULT_GROK_ROOT: () => DEFAULT_GROK_ROOT,
4463
5262
  DEFAULT_ROOT: () => DEFAULT_ROOT,
4464
5263
  RICH_ROLLUP_SCHEMA_VERSION: () => RICH_ROLLUP_SCHEMA_VERSION,
4465
5264
  agentSources: () => agentSources,
@@ -4470,6 +5269,7 @@ __export(fs_exports, {
4470
5269
  cclensHome: () => cclensHome,
4471
5270
  cclensPath: () => cclensPath,
4472
5271
  clearCaches: () => clearCaches,
5272
+ clearGrokCaches: () => clearGrokCaches,
4473
5273
  clearTeamConfig: () => clearTeamConfig,
4474
5274
  codexSessionLocalDay: () => codexSessionLocalDay,
4475
5275
  decodeProjectName: () => decodeProjectName,
@@ -4481,8 +5281,10 @@ __export(fs_exports, {
4481
5281
  getCodexSession: () => getCodexSession,
4482
5282
  getCoworkSession: () => getCoworkSession,
4483
5283
  getGeminiSession: () => getGeminiSession,
5284
+ getGrokSession: () => getGrokSession,
4484
5285
  getLatestCodexUsage: () => getLatestCodexUsage,
4485
5286
  getSession: () => getSession,
5287
+ grokSessionLocalDay: () => grokSessionLocalDay,
4486
5288
  invalidateFile: () => invalidateFile,
4487
5289
  isFleetlensRuntimeDir: () => isFleetlensRuntimeDir,
4488
5290
  listAllSessions: () => listAllSessions,
@@ -4490,6 +5292,7 @@ __export(fs_exports, {
4490
5292
  listCodexSessions: () => listCodexSessions,
4491
5293
  listCoworkSessions: () => listCoworkSessions,
4492
5294
  listGeminiSessions: () => listGeminiSessions,
5295
+ listGrokSessions: () => listGrokSessions,
4493
5296
  listProjects: () => listProjects,
4494
5297
  listSessions: () => listSessions,
4495
5298
  loadCalibrationCurve: () => loadCalibrationCurve,
@@ -4502,20 +5305,21 @@ __export(fs_exports, {
4502
5305
  readGitFolder: () => readGitFolder,
4503
5306
  readJsonlFile: () => readJsonlFile,
4504
5307
  readTeamConfig: () => readTeamConfig,
5308
+ resolveDefaultGrokRoot: () => resolveDefaultGrokRoot,
4505
5309
  resolveProjectIdentity: () => resolveProjectIdentity,
4506
5310
  sessionIdFromFileName: () => sessionIdFromFileName,
4507
5311
  shouldSyncProject: () => shouldSyncProject,
4508
5312
  walkJsonlFiles: () => walkJsonlFiles,
4509
5313
  writeTeamConfig: () => writeTeamConfig
4510
5314
  });
4511
- import { promises as fs6, existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2, appendFileSync, mkdirSync as mkdirSync2 } from "node:fs";
4512
- import os6 from "node:os";
4513
- import path6 from "node:path";
5315
+ import { promises as fs7, existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2, appendFileSync, mkdirSync as mkdirSync2 } from "node:fs";
5316
+ import os7 from "node:os";
5317
+ import path7 from "node:path";
4514
5318
  function cclensHome() {
4515
- return process.env.CCLENS_HOME || path6.join(os6.homedir(), ".cclens");
5319
+ return process.env.CCLENS_HOME || path7.join(os7.homedir(), ".cclens");
4516
5320
  }
4517
5321
  function cclensPath(...parts) {
4518
- return path6.join(cclensHome(), ...parts);
5322
+ return path7.join(cclensHome(), ...parts);
4519
5323
  }
4520
5324
  function cacheStats() {
4521
5325
  return claudeCodeCacheStats();
@@ -4526,6 +5330,7 @@ function clearCaches() {
4526
5330
  clearGeminiCaches();
4527
5331
  clearAntigravityCaches();
4528
5332
  clearCoworkCaches();
5333
+ clearGrokCaches();
4529
5334
  }
4530
5335
  function invalidateFile(fullPath) {
4531
5336
  invalidateClaudeCodeFile(fullPath);
@@ -4556,7 +5361,7 @@ function usageLogPath() {
4556
5361
  }
4557
5362
  function appendUsageSnapshot(snapshot) {
4558
5363
  const p = usageLogPath();
4559
- mkdirSync2(path6.dirname(p), { recursive: true });
5364
+ mkdirSync2(path7.dirname(p), { recursive: true });
4560
5365
  appendFileSync(p, JSON.stringify(snapshot) + "\n", "utf8");
4561
5366
  }
4562
5367
  function pruneUsageAgent(agent) {
@@ -4572,13 +5377,13 @@ function pruneUsageAgent(agent) {
4572
5377
  return true;
4573
5378
  }
4574
5379
  });
4575
- mkdirSync2(path6.dirname(p), { recursive: true });
5380
+ mkdirSync2(path7.dirname(p), { recursive: true });
4576
5381
  writeFileSync2(p, kept.join("\n") + (kept.length ? "\n" : ""), "utf8");
4577
5382
  }
4578
5383
  async function loadUsageByDay(start, end) {
4579
5384
  let raw;
4580
5385
  try {
4581
- raw = await fs6.readFile(usageLogPath(), "utf8");
5386
+ raw = await fs7.readFile(usageLogPath(), "utf8");
4582
5387
  } catch {
4583
5388
  return { by_day: [] };
4584
5389
  }
@@ -4623,7 +5428,7 @@ async function loadUsageByDay(start, end) {
4623
5428
  async function loadCalibrationSnapshots() {
4624
5429
  let raw;
4625
5430
  try {
4626
- raw = await fs6.readFile(usageLogPath(), "utf8");
5431
+ raw = await fs7.readFile(usageLogPath(), "utf8");
4627
5432
  } catch {
4628
5433
  return [];
4629
5434
  }
@@ -4787,7 +5592,7 @@ async function loadCalibrationCurve(tier = "pro-max-20x", root = DEFAULT_ROOT, g
4787
5592
  ]);
4788
5593
  return buildCalibrationCurve(events, snapshots, tier, granularityMin);
4789
5594
  }
4790
- var codexSource, geminiSource, antigravitySource, coworkSource, agentSources;
5595
+ var codexSource, geminiSource, antigravitySource, coworkSource, grokSource, agentSources;
4791
5596
  var init_fs = __esm({
4792
5597
  "../parser/dist/fs.js"() {
4793
5598
  "use strict";
@@ -4799,12 +5604,14 @@ var init_fs = __esm({
4799
5604
  init_gemini();
4800
5605
  init_antigravity();
4801
5606
  init_cowork();
5607
+ init_grok();
4802
5608
  init_claude_code();
4803
5609
  init_git_project();
4804
5610
  init_codex();
4805
5611
  init_gemini();
4806
5612
  init_antigravity();
4807
5613
  init_cowork();
5614
+ init_grok();
4808
5615
  init_team_config();
4809
5616
  init_team_wire();
4810
5617
  codexSource = {
@@ -4858,26 +5665,38 @@ var init_fs = __esm({
4858
5665
  return getCoworkSession(id);
4859
5666
  }
4860
5667
  };
5668
+ grokSource = {
5669
+ ...GROK_METADATA,
5670
+ // Display default; list/get re-resolve GROK_HOME at call time internally.
5671
+ defaultRoot: DEFAULT_GROK_ROOT,
5672
+ async listSessions(opts) {
5673
+ return listGrokSessions(opts);
5674
+ },
5675
+ async getSession(id, opts) {
5676
+ return getGrokSession(id, opts);
5677
+ }
5678
+ };
4861
5679
  agentSources = [
4862
5680
  claudeCodeSource,
4863
5681
  codexSource,
4864
5682
  geminiSource,
4865
5683
  antigravitySource,
4866
- coworkSource
5684
+ coworkSource,
5685
+ grokSource
4867
5686
  ];
4868
5687
  }
4869
5688
  });
4870
5689
 
4871
5690
  // src/usage/storage.ts
4872
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync4 } from "node:fs";
5691
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3, existsSync as existsSync5 } from "node:fs";
4873
5692
  import { dirname as dirname2 } from "node:path";
4874
5693
  function appendSnapshot(filePath, snapshot) {
4875
5694
  mkdirSync3(dirname2(filePath), { recursive: true });
4876
5695
  appendFileSync2(filePath, JSON.stringify(snapshot) + "\n", "utf8");
4877
5696
  }
4878
5697
  function readSnapshots(filePath) {
4879
- if (!existsSync4(filePath)) return [];
4880
- const content = readFileSync6(filePath, "utf8");
5698
+ if (!existsSync5(filePath)) return [];
5699
+ const content = readFileSync7(filePath, "utf8");
4881
5700
  const snapshots = [];
4882
5701
  for (const line of content.split("\n")) {
4883
5702
  if (!line.trim()) continue;
@@ -4889,8 +5708,8 @@ function readSnapshots(filePath) {
4889
5708
  return snapshots;
4890
5709
  }
4891
5710
  function pruneAgent(filePath, agent) {
4892
- if (!existsSync4(filePath)) return;
4893
- const kept = readFileSync6(filePath, "utf8").split("\n").filter((line) => {
5711
+ if (!existsSync5(filePath)) return;
5712
+ const kept = readFileSync7(filePath, "utf8").split("\n").filter((line) => {
4894
5713
  if (!line.trim()) return false;
4895
5714
  try {
4896
5715
  return JSON.parse(line).agent !== agent;
@@ -5328,6 +6147,7 @@ __export(dist_exports, {
5328
6147
  CODEX_METADATA: () => CODEX_METADATA,
5329
6148
  COWORK_METADATA: () => COWORK_METADATA,
5330
6149
  GEMINI_METADATA: () => GEMINI_METADATA,
6150
+ GROK_METADATA: () => GROK_METADATA,
5331
6151
  PRICES: () => PRICES,
5332
6152
  RATE_PER_PCT: () => RATE_PER_PCT,
5333
6153
  RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
@@ -5401,7 +6221,7 @@ __export(file_probe_exports, {
5401
6221
  probeArtifactSignals: () => probeArtifactSignals
5402
6222
  });
5403
6223
  import { createHash } from "node:crypto";
5404
- import { existsSync as existsSync9, readdirSync as readdirSync3, statSync as statSync5 } from "node:fs";
6224
+ import { existsSync as existsSync10, readdirSync as readdirSync3, statSync as statSync5 } from "node:fs";
5405
6225
  import { homedir as homedir3 } from "node:os";
5406
6226
  import { join as join8, relative, resolve as resolve3, sep } from "node:path";
5407
6227
  import { execFileSync as execFileSync2 } from "node:child_process";
@@ -5411,15 +6231,15 @@ function pathHash(relPath) {
5411
6231
  function defaultScanRoots(extraRoots = []) {
5412
6232
  const roots = [];
5413
6233
  const home = join8(homedir3(), ".claude");
5414
- if (existsSync9(home)) roots.push({ root: home, label: "user" });
6234
+ if (existsSync10(home)) roots.push({ root: home, label: "user" });
5415
6235
  for (const e of extraRoots) {
5416
6236
  const r = resolve3(e, ".claude");
5417
- if (existsSync9(r) && r !== home) roots.push({ root: r, label: "project" });
6237
+ if (existsSync10(r) && r !== home) roots.push({ root: r, label: "project" });
5418
6238
  }
5419
6239
  return roots;
5420
6240
  }
5421
6241
  function listMarkdownFiles(dir) {
5422
- if (!existsSync9(dir)) return [];
6242
+ if (!existsSync10(dir)) return [];
5423
6243
  const out = [];
5424
6244
  let entries;
5425
6245
  try {
@@ -5489,7 +6309,7 @@ function scanAuthored(roots, subdir, day) {
5489
6309
  const out = [];
5490
6310
  for (const r of roots) {
5491
6311
  const dir = join8(r.root, subdir);
5492
- if (!existsSync9(dir)) continue;
6312
+ if (!existsSync10(dir)) continue;
5493
6313
  for (const f of listMarkdownFiles(dir)) {
5494
6314
  const firstSeen = firstSeenDateOf(f);
5495
6315
  if (firstSeen !== day) continue;
@@ -5503,7 +6323,7 @@ function scanEdited(roots, day) {
5503
6323
  const out = [];
5504
6324
  for (const r of roots) {
5505
6325
  const dir = join8(r.root, "skills");
5506
- if (!existsSync9(dir)) continue;
6326
+ if (!existsSync10(dir)) continue;
5507
6327
  for (const f of listMarkdownFiles(dir)) {
5508
6328
  const firstSeen = firstSeenDateOf(f);
5509
6329
  if (firstSeen === day) continue;
@@ -5526,10 +6346,10 @@ function claudemdLineDelta(extraRoots, authorEmail, day) {
5526
6346
  const candidates = [];
5527
6347
  for (const e of extraRoots) {
5528
6348
  const f = resolve3(e, "CLAUDE.md");
5529
- if (existsSync9(f)) candidates.push(f);
6349
+ if (existsSync10(f)) candidates.push(f);
5530
6350
  }
5531
6351
  const homeClaudeMd = join8(homedir3(), "CLAUDE.md");
5532
- if (existsSync9(homeClaudeMd)) candidates.push(homeClaudeMd);
6352
+ if (existsSync10(homeClaudeMd)) candidates.push(homeClaudeMd);
5533
6353
  for (const file of candidates) {
5534
6354
  try {
5535
6355
  const out = execFileSync2(
@@ -5586,7 +6406,7 @@ var init_file_probe = __esm({
5586
6406
 
5587
6407
  // src/daemon-worker.ts
5588
6408
  import { spawn as spawn2 } from "node:child_process";
5589
- import { closeSync, existsSync as existsSync16, mkdirSync as mkdirSync14, openSync, readFileSync as readFileSync19, writeFileSync as writeFileSync14 } from "node:fs";
6409
+ import { closeSync, existsSync as existsSync17, mkdirSync as mkdirSync14, openSync, readFileSync as readFileSync20, writeFileSync as writeFileSync14 } from "node:fs";
5590
6410
  import { dirname as dirname11, join as join12 } from "node:path";
5591
6411
  import { fileURLToPath } from "node:url";
5592
6412
 
@@ -5618,9 +6438,9 @@ function readFromCredentialsFile() {
5618
6438
  join(homedir(), ".claude", ".credentials.json"),
5619
6439
  join(homedir(), ".config", "claude", "credentials.json")
5620
6440
  ];
5621
- for (const path7 of candidates) {
6441
+ for (const path9 of candidates) {
5622
6442
  try {
5623
- const blob = readFileSync(path7, "utf8");
6443
+ const blob = readFileSync(path9, "utf8");
5624
6444
  const creds = extractCredentials(blob);
5625
6445
  if (creds) return creds;
5626
6446
  } catch {
@@ -5832,6 +6652,218 @@ async function fetchZaiUsage() {
5832
6652
  };
5833
6653
  }
5834
6654
 
6655
+ // src/usage/grok.ts
6656
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "node:fs";
6657
+ import os8 from "node:os";
6658
+ import path8 from "node:path";
6659
+ var CREDITS_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
6660
+ var SETTINGS_URL = "https://cli-chat-proxy.grok.com/v1/settings";
6661
+ var REFRESH_URL = "https://auth.x.ai/oauth2/token";
6662
+ var TOKEN_AUTH = "xai-grok-cli";
6663
+ var DEFAULT_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
6664
+ var WEEKLY_PERIOD = "USAGE_PERIOD_TYPE_WEEKLY";
6665
+ var REFRESH_BUFFER_MS = 5 * 60 * 1e3;
6666
+ var GrokApiError = class extends Error {
6667
+ constructor(message, code) {
6668
+ super(message);
6669
+ this.code = code;
6670
+ }
6671
+ };
6672
+ function grokHome() {
6673
+ return process.env.GROK_HOME || path8.join(os8.homedir(), ".grok");
6674
+ }
6675
+ function authPath() {
6676
+ return path8.join(grokHome(), "auth.json");
6677
+ }
6678
+ function loadAuthEntry() {
6679
+ const p = authPath();
6680
+ if (!existsSync4(p)) {
6681
+ throw new GrokApiError("Grok not logged in. Run `grok login`.", "no_auth");
6682
+ }
6683
+ let raw;
6684
+ try {
6685
+ raw = JSON.parse(readFileSync6(p, "utf8"));
6686
+ } catch {
6687
+ throw new GrokApiError("Grok auth.json is unreadable. Run `grok login`.", "no_auth");
6688
+ }
6689
+ for (const [entryKey2, entry] of Object.entries(raw)) {
6690
+ const token = typeof entry?.key === "string" ? entry.key.trim() : "";
6691
+ if (token) return { token, entry, entryKey: entryKey2 };
6692
+ }
6693
+ throw new GrokApiError("Grok auth has no access token. Run `grok login`.", "no_auth");
6694
+ }
6695
+ function needsRefresh(entry) {
6696
+ const exp = entry.expires_at;
6697
+ if (!exp) return false;
6698
+ const ms = Date.parse(exp);
6699
+ if (!Number.isFinite(ms)) return false;
6700
+ return Date.now() >= ms - REFRESH_BUFFER_MS;
6701
+ }
6702
+ async function refreshAccessToken(entry) {
6703
+ const refresh = entry.refresh_token?.trim();
6704
+ if (!refresh) return null;
6705
+ const clientId = entry.oidc_client_id?.trim() || DEFAULT_CLIENT_ID;
6706
+ const body = new URLSearchParams({
6707
+ grant_type: "refresh_token",
6708
+ client_id: clientId,
6709
+ refresh_token: refresh
6710
+ });
6711
+ let res;
6712
+ try {
6713
+ res = await fetch(REFRESH_URL, {
6714
+ method: "POST",
6715
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
6716
+ body: body.toString()
6717
+ });
6718
+ } catch {
6719
+ return null;
6720
+ }
6721
+ if (!res.ok) return null;
6722
+ try {
6723
+ const j = await res.json();
6724
+ if (typeof j.access_token !== "string" || !j.access_token) return null;
6725
+ try {
6726
+ const p = authPath();
6727
+ const raw = JSON.parse(readFileSync6(p, "utf8"));
6728
+ for (const key of Object.keys(raw)) {
6729
+ if (raw[key]?.key === entry.key || raw[key]?.refresh_token === refresh) {
6730
+ raw[key] = {
6731
+ ...raw[key],
6732
+ key: j.access_token,
6733
+ refresh_token: j.refresh_token ?? raw[key].refresh_token,
6734
+ expires_at: typeof j.expires_in === "number" ? new Date(Date.now() + j.expires_in * 1e3).toISOString() : raw[key].expires_at
6735
+ };
6736
+ break;
6737
+ }
6738
+ }
6739
+ const { writeFileSync: writeFileSync15 } = await import("node:fs");
6740
+ writeFileSync15(p, JSON.stringify(raw, null, 2), "utf8");
6741
+ } catch {
6742
+ }
6743
+ return j.access_token;
6744
+ } catch {
6745
+ return null;
6746
+ }
6747
+ }
6748
+ function authHeaders(token) {
6749
+ return {
6750
+ Authorization: `Bearer ${token.trim()}`,
6751
+ "X-XAI-Token-Auth": TOKEN_AUTH,
6752
+ Accept: "application/json",
6753
+ "User-Agent": "fleetlens"
6754
+ };
6755
+ }
6756
+ function parseGrokCreditsConfig(body) {
6757
+ if (!body || typeof body !== "object") {
6758
+ throw new GrokApiError("Grok billing response missing body", "parse");
6759
+ }
6760
+ const config = body.config;
6761
+ if (!config || typeof config !== "object") {
6762
+ throw new GrokApiError("Grok billing response missing config", "parse");
6763
+ }
6764
+ const period = config.currentPeriod;
6765
+ if (!period || typeof period !== "object") {
6766
+ throw new GrokApiError("Grok billing response missing currentPeriod", "parse");
6767
+ }
6768
+ const periodType = typeof period.type === "string" ? period.type.trim() : "";
6769
+ if (!periodType) {
6770
+ throw new GrokApiError("Grok billing period type missing", "parse");
6771
+ }
6772
+ let utilization = 0;
6773
+ if (config.creditUsagePercent !== void 0 && config.creditUsagePercent !== null) {
6774
+ const n = Number(config.creditUsagePercent);
6775
+ if (!Number.isFinite(n)) {
6776
+ throw new GrokApiError("Grok creditUsagePercent is not a number", "parse");
6777
+ }
6778
+ utilization = Math.min(100, Math.max(0, n));
6779
+ }
6780
+ const end = typeof period.end === "string" && period.end ? new Date(period.end).toISOString() : null;
6781
+ let onDemandCap = 0;
6782
+ const cap = config.onDemandCap;
6783
+ if (cap && typeof cap === "object" && "val" in cap) {
6784
+ const v = Number(cap.val);
6785
+ if (Number.isFinite(v)) onDemandCap = v;
6786
+ }
6787
+ return {
6788
+ utilization,
6789
+ resets_at: end && !Number.isNaN(Date.parse(end)) ? end : null,
6790
+ period_type: periodType,
6791
+ on_demand_cap: onDemandCap
6792
+ };
6793
+ }
6794
+ async function fetchJson(url, token) {
6795
+ let res;
6796
+ try {
6797
+ res = await fetch(url, { headers: authHeaders(token) });
6798
+ } catch (err) {
6799
+ throw new GrokApiError(
6800
+ `Network error reaching Grok billing: ${err.message}`,
6801
+ "network"
6802
+ );
6803
+ }
6804
+ let body = null;
6805
+ try {
6806
+ body = await res.json();
6807
+ } catch {
6808
+ }
6809
+ return { status: res.status, body };
6810
+ }
6811
+ async function fetchGrokUsage() {
6812
+ const loaded = loadAuthEntry();
6813
+ const entry = loaded.entry;
6814
+ let token = loaded.token;
6815
+ if (needsRefresh(entry)) {
6816
+ const refreshed = await refreshAccessToken(entry);
6817
+ if (refreshed) token = refreshed;
6818
+ }
6819
+ let { status, body } = await fetchJson(CREDITS_URL, token);
6820
+ if (status === 401 || status === 403) {
6821
+ const refreshed = await refreshAccessToken(entry);
6822
+ if (refreshed) {
6823
+ token = refreshed;
6824
+ ({ status, body } = await fetchJson(CREDITS_URL, token));
6825
+ }
6826
+ }
6827
+ if (status < 200 || status >= 300) {
6828
+ throw new GrokApiError(
6829
+ `Grok billing returned HTTP ${status}`,
6830
+ status === 401 || status === 403 ? "no_auth" : "http"
6831
+ );
6832
+ }
6833
+ const credits = parseGrokCreditsConfig(body);
6834
+ if (credits.period_type !== WEEKLY_PERIOD) {
6835
+ throw new GrokApiError(
6836
+ `Grok period is ${credits.period_type}, not weekly`,
6837
+ "not_weekly"
6838
+ );
6839
+ }
6840
+ let planType = null;
6841
+ try {
6842
+ const settings = await fetchJson(SETTINGS_URL, token);
6843
+ if (settings.status >= 200 && settings.status < 300 && settings.body && typeof settings.body === "object") {
6844
+ const tier = settings.body.subscription_tier_display;
6845
+ if (typeof tier === "string" && tier.trim()) planType = tier.trim();
6846
+ }
6847
+ } catch {
6848
+ }
6849
+ return {
6850
+ captured_at: (/* @__PURE__ */ new Date()).toISOString(),
6851
+ agent: "grok",
6852
+ // No 5-hour window — menubar / strip show "—" on the top line.
6853
+ five_hour: { utilization: null, resets_at: null },
6854
+ seven_day: {
6855
+ utilization: credits.utilization,
6856
+ resets_at: credits.resets_at
6857
+ },
6858
+ seven_day_opus: null,
6859
+ seven_day_sonnet: null,
6860
+ seven_day_oauth_apps: null,
6861
+ seven_day_cowork: null,
6862
+ extra_usage: null,
6863
+ plan_type: planType
6864
+ };
6865
+ }
6866
+
5835
6867
  // src/daemon-worker.ts
5836
6868
  init_storage();
5837
6869
  init_fs();
@@ -5873,7 +6905,7 @@ import { randomUUID } from "node:crypto";
5873
6905
 
5874
6906
  // ../entries/dist/fs.js
5875
6907
  init_fs();
5876
- import { readFileSync as readFileSync8, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, renameSync as renameSync3, existsSync as existsSync6 } from "node:fs";
6908
+ import { readFileSync as readFileSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, renameSync as renameSync3, existsSync as existsSync7 } from "node:fs";
5877
6909
  import { randomBytes } from "node:crypto";
5878
6910
  import { join as join5 } from "node:path";
5879
6911
 
@@ -5948,12 +6980,12 @@ var PROMPT_FRAME_ORIGIN = {
5948
6980
 
5949
6981
  // ../entries/dist/digest-fs.js
5950
6982
  init_fs();
5951
- import { readFileSync as readFileSync7, readdirSync, writeFileSync as writeFileSync4, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync4, existsSync as existsSync5 } from "node:fs";
6983
+ import { readFileSync as readFileSync8, readdirSync, writeFileSync as writeFileSync4, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "node:fs";
5952
6984
  import { dirname as dirname3, join as join4 } from "node:path";
5953
6985
  var digestsDirCached = null;
5954
- function parseDigestFile(path7, expectedVersion) {
6986
+ function parseDigestFile(path9, expectedVersion) {
5955
6987
  try {
5956
- const parsed = JSON.parse(readFileSync7(path7, "utf8"));
6988
+ const parsed = JSON.parse(readFileSync8(path9, "utf8"));
5957
6989
  if (!parsed || typeof parsed !== "object")
5958
6990
  return null;
5959
6991
  if (parsed.version !== expectedVersion)
@@ -5993,7 +7025,7 @@ function writeDayDigest(digest) {
5993
7025
  }
5994
7026
  function readDayDigest(date) {
5995
7027
  const p = dayDigestPath(date);
5996
- if (!existsSync5(p))
7028
+ if (!existsSync6(p))
5997
7029
  return null;
5998
7030
  return parseDigestFile(p, CURRENT_DAY_DIGEST_SCHEMA_VERSION);
5999
7031
  }
@@ -6026,7 +7058,7 @@ function writeWeekDigest(digest) {
6026
7058
  }
6027
7059
  function readWeekDigest(monday) {
6028
7060
  const p = weekDigestPath(monday);
6029
- if (!existsSync5(p))
7061
+ if (!existsSync6(p))
6030
7062
  return null;
6031
7063
  return parseDigestFile(p, CURRENT_WEEK_DIGEST_SCHEMA_VERSION);
6032
7064
  }
@@ -6104,17 +7136,17 @@ function writeEntryPreservingEnrichment(fresh) {
6104
7136
  }
6105
7137
  function readEntry(sessionId, localDay2) {
6106
7138
  const p = pathFor(sessionId, localDay2);
6107
- if (!existsSync6(p))
7139
+ if (!existsSync7(p))
6108
7140
  return null;
6109
- const raw = readFileSync8(p, "utf8");
7141
+ const raw = readFileSync9(p, "utf8");
6110
7142
  return JSON.parse(raw);
6111
7143
  }
6112
7144
  function entryExists(sessionId, localDay2) {
6113
- return existsSync6(pathFor(sessionId, localDay2));
7145
+ return existsSync7(pathFor(sessionId, localDay2));
6114
7146
  }
6115
7147
  function listEntryKeys() {
6116
7148
  const dir = entriesDir();
6117
- if (!existsSync6(dir))
7149
+ if (!existsSync7(dir))
6118
7150
  return [];
6119
7151
  return readdirSync2(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
6120
7152
  }
@@ -6133,7 +7165,7 @@ function listEntriesForDay(localDay2) {
6133
7165
 
6134
7166
  // src/perception/build-entries.ts
6135
7167
  init_dist();
6136
- import { statSync as statSync2, readFileSync as readFileSync9 } from "node:fs";
7168
+ import { statSync as statSync2, readFileSync as readFileSync10 } from "node:fs";
6137
7169
  import { basename as basename2, dirname as dirname4 } from "node:path";
6138
7170
 
6139
7171
  // ../entries/dist/signals.js
@@ -6367,7 +7399,7 @@ function viewEvent(ev) {
6367
7399
  cwd: rawCwd
6368
7400
  };
6369
7401
  }
6370
- var IDLE_GAP_MS4 = 3 * 60 * 1e3;
7402
+ var IDLE_GAP_MS5 = 3 * 60 * 1e3;
6371
7403
  var INTERRUPT_RE2 = /\[request interrupted|interrupted by user/i;
6372
7404
  var PR_TITLE_RE = /--title\s+["']([^"']+)["']/;
6373
7405
  var BASH_CHAIN_SPLIT_RE = /\|\||&&|;|\|/;
@@ -6479,7 +7511,7 @@ function closeTurn(t, closed, cwd) {
6479
7511
  let active = 0;
6480
7512
  for (let i = 1; i < ts.length; i++) {
6481
7513
  const dt = ts[i] - ts[i - 1];
6482
- if (dt < IDLE_GAP_MS4)
7514
+ if (dt < IDLE_GAP_MS5)
6483
7515
  active += dt;
6484
7516
  }
6485
7517
  closed.push({
@@ -6676,7 +7708,7 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
6676
7708
  let activeMs2 = 0;
6677
7709
  for (let i = 1; i < tsSorted.length; i++) {
6678
7710
  const dt = tsSorted[i] - tsSorted[i - 1];
6679
- if (dt < IDLE_GAP_MS4)
7711
+ if (dt < IDLE_GAP_MS5)
6680
7712
  activeMs2 += dt;
6681
7713
  }
6682
7714
  const tsSortedStrings = dayEvents.map((e) => e.timestamp).filter((t) => !!t).sort();
@@ -6873,7 +7905,7 @@ function decodeProjectDirName(projectDir) {
6873
7905
  }
6874
7906
  function buildEntriesForFile(filePath) {
6875
7907
  const stat = statSync2(filePath);
6876
- const raw = readFileSync9(filePath, "utf8");
7908
+ const raw = readFileSync10(filePath, "utf8");
6877
7909
  const rawLines = raw.split("\n").filter(Boolean).map((l) => {
6878
7910
  try {
6879
7911
  return JSON.parse(l);
@@ -7134,7 +8166,7 @@ function buildIngestPayload(inputs) {
7134
8166
  return {
7135
8167
  ingestId: randomUUID(),
7136
8168
  observedAt: (/* @__PURE__ */ new Date()).toISOString(),
7137
- cliVersion: "0.16.0",
8169
+ cliVersion: "0.16.2",
7138
8170
  ...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
7139
8171
  ...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
7140
8172
  ...richRollup ? { richRollup } : {},
@@ -7161,7 +8193,7 @@ async function pushToTeamServer(config, payload) {
7161
8193
  }
7162
8194
 
7163
8195
  // src/team/git-remote.ts
7164
- import { existsSync as existsSync7, readFileSync as readFileSync10, statSync as statSync3 } from "node:fs";
8196
+ import { existsSync as existsSync8, readFileSync as readFileSync11, statSync as statSync3 } from "node:fs";
7165
8197
  import { dirname as dirname5, isAbsolute as isAbsolute2, join as join6, resolve as resolve2 } from "node:path";
7166
8198
  var GITHUB_URL_RE = /github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?$/;
7167
8199
  function parseGithubRemote(url) {
@@ -7187,12 +8219,12 @@ function gitConfigPathFor(dir) {
7187
8219
  const st = statSync3(dotGit, { throwIfNoEntry: false });
7188
8220
  if (!st) return null;
7189
8221
  if (st.isDirectory()) return join6(dotGit, "config");
7190
- const m = readFileSync10(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
8222
+ const m = readFileSync11(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
7191
8223
  if (!m) return null;
7192
8224
  const gd = isAbsolute2(m[1]) ? m[1] : resolve2(dir, m[1]);
7193
8225
  const commondirFile = join6(gd, "commondir");
7194
- if (existsSync7(commondirFile)) {
7195
- const common = readFileSync10(commondirFile, "utf8").trim();
8226
+ if (existsSync8(commondirFile)) {
8227
+ const common = readFileSync11(commondirFile, "utf8").trim();
7196
8228
  return join6(isAbsolute2(common) ? common : resolve2(gd, common), "config");
7197
8229
  }
7198
8230
  return join6(gd, "config");
@@ -7207,8 +8239,8 @@ function createRepoResolver() {
7207
8239
  try {
7208
8240
  for (let d = dir; ; d = dirname5(d)) {
7209
8241
  const config = gitConfigPathFor(d);
7210
- if (config && existsSync7(config)) {
7211
- const url = originUrl2(readFileSync10(config, "utf8"));
8242
+ if (config && existsSync8(config)) {
8243
+ const url = originUrl2(readFileSync11(config, "utf8"));
7212
8244
  repo = url ? parseGithubRemote(url) : null;
7213
8245
  break;
7214
8246
  }
@@ -7224,7 +8256,7 @@ function createRepoResolver() {
7224
8256
 
7225
8257
  // src/team/queue.ts
7226
8258
  init_fs();
7227
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, appendFileSync as appendFileSync4, statSync as statSync4, mkdirSync as mkdirSync6 } from "node:fs";
8259
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, appendFileSync as appendFileSync4, statSync as statSync4, mkdirSync as mkdirSync6 } from "node:fs";
7228
8260
  import { dirname as dirname6 } from "node:path";
7229
8261
  var QUEUE_PATH = cclensPath("ingest-queue.jsonl");
7230
8262
  var MAX_SIZE_BYTES = 10 * 1024 * 1024;
@@ -7244,7 +8276,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
7244
8276
  function dequeuePayloads(queuePath = QUEUE_PATH) {
7245
8277
  let lines;
7246
8278
  try {
7247
- lines = readFileSync11(queuePath, "utf8").trim().split("\n").filter(Boolean);
8279
+ lines = readFileSync12(queuePath, "utf8").trim().split("\n").filter(Boolean);
7248
8280
  } catch {
7249
8281
  return [];
7250
8282
  }
@@ -7265,7 +8297,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
7265
8297
  function pruneOldest(queuePath) {
7266
8298
  let lines;
7267
8299
  try {
7268
- lines = readFileSync11(queuePath, "utf8").trim().split("\n").filter(Boolean);
8300
+ lines = readFileSync12(queuePath, "utf8").trim().split("\n").filter(Boolean);
7269
8301
  } catch {
7270
8302
  return;
7271
8303
  }
@@ -7278,7 +8310,7 @@ init_storage();
7278
8310
  import { randomUUID as randomUUID2 } from "node:crypto";
7279
8311
 
7280
8312
  // src/usage/profile.ts
7281
- import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
8313
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
7282
8314
  import { dirname as dirname7 } from "node:path";
7283
8315
  var PROFILE_ENDPOINT = "https://api.anthropic.com/api/oauth/profile";
7284
8316
  var BETA_HEADER2 = "oauth-2025-04-20";
@@ -7322,9 +8354,9 @@ async function fetchProfile(nowMs = Date.now()) {
7322
8354
  };
7323
8355
  }
7324
8356
  function readCachedProfile(cachePath) {
7325
- if (!existsSync8(cachePath)) return null;
8357
+ if (!existsSync9(cachePath)) return null;
7326
8358
  try {
7327
- const raw = JSON.parse(readFileSync12(cachePath, "utf8"));
8359
+ const raw = JSON.parse(readFileSync13(cachePath, "utf8"));
7328
8360
  if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
7329
8361
  return raw;
7330
8362
  } catch {
@@ -7493,13 +8525,13 @@ async function runTeamBackfill(log3 = noopLog, filePath = USAGE_LOG, configOverr
7493
8525
 
7494
8526
  // src/team/sync-log.ts
7495
8527
  init_fs();
7496
- import { readFileSync as readFileSync13 } from "node:fs";
8528
+ import { readFileSync as readFileSync14 } from "node:fs";
7497
8529
  var MAX_LINES = 300;
7498
8530
  var MAX_MSG_CHARS = 1900;
7499
8531
  function readPendingSyncLog(watermark) {
7500
8532
  let raw;
7501
8533
  try {
7502
- raw = readFileSync13(cclensPath("daemon.log"), "utf8");
8534
+ raw = readFileSync14(cclensPath("daemon.log"), "utf8");
7503
8535
  } catch {
7504
8536
  return { lines: [] };
7505
8537
  }
@@ -8125,7 +9157,7 @@ init_fs();
8125
9157
 
8126
9158
  // src/perception/state.ts
8127
9159
  init_fs();
8128
- import { existsSync as existsSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, renameSync as renameSync4 } from "node:fs";
9160
+ import { existsSync as existsSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, renameSync as renameSync4 } from "node:fs";
8129
9161
  import { dirname as dirname9 } from "node:path";
8130
9162
  var STALE_MS = 15 * 60 * 1e3;
8131
9163
  var pathCached = null;
@@ -8136,7 +9168,7 @@ function statePath() {
8136
9168
  }
8137
9169
  function readState() {
8138
9170
  const p = statePath();
8139
- if (!existsSync10(p)) {
9171
+ if (!existsSync11(p)) {
8140
9172
  return {
8141
9173
  sweep_in_progress: false,
8142
9174
  last_sweep_started_at: null,
@@ -8144,7 +9176,7 @@ function readState() {
8144
9176
  file_checkpoints: {}
8145
9177
  };
8146
9178
  }
8147
- const raw = readFileSync14(p, "utf8");
9179
+ const raw = readFileSync15(p, "utf8");
8148
9180
  return JSON.parse(raw);
8149
9181
  }
8150
9182
  function writeState(s) {
@@ -8752,8 +9784,8 @@ function getErrorMap() {
8752
9784
 
8753
9785
  // ../../node_modules/zod/v3/helpers/parseUtil.js
8754
9786
  var makeIssue = (params) => {
8755
- const { data, path: path7, errorMaps, issueData } = params;
8756
- const fullPath = [...path7, ...issueData.path || []];
9787
+ const { data, path: path9, errorMaps, issueData } = params;
9788
+ const fullPath = [...path9, ...issueData.path || []];
8757
9789
  const fullIssue = {
8758
9790
  ...issueData,
8759
9791
  path: fullPath
@@ -8869,11 +9901,11 @@ var errorUtil;
8869
9901
 
8870
9902
  // ../../node_modules/zod/v3/types.js
8871
9903
  var ParseInputLazyPath = class {
8872
- constructor(parent, value, path7, key) {
9904
+ constructor(parent, value, path9, key) {
8873
9905
  this._cachedPath = [];
8874
9906
  this.parent = parent;
8875
9907
  this.data = value;
8876
- this._path = path7;
9908
+ this._path = path9;
8877
9909
  this._key = key;
8878
9910
  }
8879
9911
  get path() {
@@ -12407,12 +13439,12 @@ var ENRICHMENT_SYSTEM_PROMPT = SYSTEM_PROMPT;
12407
13439
  // ../entries/dist/llm-runner.js
12408
13440
  init_fs();
12409
13441
  import { spawn } from "node:child_process";
12410
- import { mkdirSync as mkdirSync11, appendFileSync as appendFileSync5, writeFileSync as writeFileSync11, existsSync as existsSync12 } from "node:fs";
13442
+ import { mkdirSync as mkdirSync11, appendFileSync as appendFileSync5, writeFileSync as writeFileSync11, existsSync as existsSync13 } from "node:fs";
12411
13443
  import { join as join11 } from "node:path";
12412
13444
  import { randomUUID as randomUUID4 } from "node:crypto";
12413
13445
 
12414
13446
  // ../entries/dist/tmux-runner.js
12415
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10, existsSync as existsSync11, readdirSync as readdirSync5, realpathSync as realpathSync2, readFileSync as readFileSync15, unlinkSync as unlinkSync3, renameSync as renameSync5 } from "node:fs";
13447
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10, existsSync as existsSync12, readdirSync as readdirSync5, realpathSync as realpathSync2, readFileSync as readFileSync16, unlinkSync as unlinkSync3, renameSync as renameSync5 } from "node:fs";
12416
13448
  import { join as join10 } from "node:path";
12417
13449
  import { homedir as homedir5 } from "node:os";
12418
13450
  import { spawnSync } from "node:child_process";
@@ -12443,7 +13475,7 @@ function tmuxRunnerAvailable() {
12443
13475
  }
12444
13476
  function runtimeCwd() {
12445
13477
  const dir = join10(homedir5(), ".cclens", "runtime");
12446
- if (!existsSync11(dir))
13478
+ if (!existsSync12(dir))
12447
13479
  mkdirSync10(dir, { recursive: true });
12448
13480
  return realpathSync2(dir);
12449
13481
  }
@@ -12451,7 +13483,7 @@ function ensureRuntimeCwdTrusted(cwd) {
12451
13483
  const cfgPath = join10(homedir5(), ".claude.json");
12452
13484
  let cfg;
12453
13485
  try {
12454
- cfg = JSON.parse(readFileSync15(cfgPath, "utf8"));
13486
+ cfg = JSON.parse(readFileSync16(cfgPath, "utf8"));
12455
13487
  } catch {
12456
13488
  return;
12457
13489
  }
@@ -12600,10 +13632,10 @@ function snapshotAllTranscripts() {
12600
13632
  }
12601
13633
  return out;
12602
13634
  }
12603
- function readJsonlCwd(path7, maxLines = 8) {
13635
+ function readJsonlCwd(path9, maxLines = 8) {
12604
13636
  let raw;
12605
13637
  try {
12606
- raw = readFileSync15(path7, "utf8");
13638
+ raw = readFileSync16(path9, "utf8");
12607
13639
  } catch {
12608
13640
  return void 0;
12609
13641
  }
@@ -12657,10 +13689,10 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
12657
13689
  }
12658
13690
  throw new TmuxRunError(`timeout waiting for claude to create the session transcript (cwd: ${targetCwd})`);
12659
13691
  }
12660
- function parseTranscript2(path7, defaultModel) {
13692
+ function parseTranscript2(path9, defaultModel) {
12661
13693
  let raw;
12662
13694
  try {
12663
- raw = readFileSync15(path7, "utf8");
13695
+ raw = readFileSync16(path9, "utf8");
12664
13696
  } catch {
12665
13697
  return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
12666
13698
  }
@@ -12735,7 +13767,7 @@ function shellEscape(s) {
12735
13767
  // ../entries/dist/llm-runner.js
12736
13768
  var RUNS_DIR = cclensPath("llm-runs");
12737
13769
  function ensureRunsDir() {
12738
- if (!existsSync12(RUNS_DIR)) {
13770
+ if (!existsSync13(RUNS_DIR)) {
12739
13771
  try {
12740
13772
  mkdirSync11(RUNS_DIR, { recursive: true });
12741
13773
  } catch {
@@ -12766,15 +13798,15 @@ function newRunId(kind) {
12766
13798
  function tracePath(runId) {
12767
13799
  return join11(RUNS_DIR, `${runId}.jsonl`);
12768
13800
  }
12769
- function safeAppend(path7, line) {
13801
+ function safeAppend(path9, line) {
12770
13802
  try {
12771
- appendFileSync5(path7, line);
13803
+ appendFileSync5(path9, line);
12772
13804
  } catch {
12773
13805
  }
12774
13806
  }
12775
- function safeWrite(path7, line) {
13807
+ function safeWrite(path9, line) {
12776
13808
  try {
12777
- writeFileSync11(path7, line);
13809
+ writeFileSync11(path9, line);
12778
13810
  } catch {
12779
13811
  }
12780
13812
  }
@@ -13163,7 +14195,7 @@ function applyEnrichmentError(entry, errorMessage, model, costUsd, generatedAt,
13163
14195
 
13164
14196
  // ../entries/dist/budget.js
13165
14197
  init_fs();
13166
- import { appendFileSync as appendFileSync6, readFileSync as readFileSync16, existsSync as existsSync13, mkdirSync as mkdirSync12 } from "node:fs";
14198
+ import { appendFileSync as appendFileSync6, readFileSync as readFileSync17, existsSync as existsSync14, mkdirSync as mkdirSync12 } from "node:fs";
13167
14199
  import { dirname as dirname10 } from "node:path";
13168
14200
  var spendPathCached = null;
13169
14201
  function spendPath() {
@@ -13179,12 +14211,12 @@ function appendSpend(record) {
13179
14211
  }
13180
14212
  function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
13181
14213
  const p = spendPath();
13182
- if (!existsSync13(p))
14214
+ if (!existsSync14(p))
13183
14215
  return 0;
13184
14216
  const year = now.getUTCFullYear();
13185
14217
  const month = now.getUTCMonth();
13186
14218
  let total = 0;
13187
- const raw = readFileSync16(p, "utf8");
14219
+ const raw = readFileSync17(p, "utf8");
13188
14220
  for (const line of raw.split("\n")) {
13189
14221
  if (!line)
13190
14222
  continue;
@@ -13206,7 +14238,7 @@ function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
13206
14238
 
13207
14239
  // ../entries/dist/pipeline-lock.js
13208
14240
  init_fs();
13209
- import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync4, existsSync as existsSync14, readFileSync as readFileSync17, statSync as statSync7 } from "node:fs";
14241
+ import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync4, existsSync as existsSync15, readFileSync as readFileSync18, statSync as statSync7 } from "node:fs";
13210
14242
  var STALE_MS2 = 60 * 1e3;
13211
14243
  var HEARTBEAT_MS = 30 * 1e3;
13212
14244
  var lockPathCached = null;
@@ -13252,13 +14284,13 @@ function pidAlive(pid) {
13252
14284
  }
13253
14285
  function interactiveLockFresh(nowMs) {
13254
14286
  const p = lockPath();
13255
- if (!existsSync14(p))
14287
+ if (!existsSync15(p))
13256
14288
  return false;
13257
14289
  try {
13258
14290
  const mtime = statSync7(p).mtimeMs;
13259
14291
  if (nowMs - mtime > STALE_MS2)
13260
14292
  return false;
13261
- const pid = Number(readFileSync17(p, "utf8").trim());
14293
+ const pid = Number(readFileSync18(p, "utf8").trim());
13262
14294
  if (!Number.isFinite(pid) || pid <= 0)
13263
14295
  return false;
13264
14296
  if (!pidAlive(pid))
@@ -13273,7 +14305,7 @@ function interactiveLockFresh(nowMs) {
13273
14305
  var THIRTY_MIN_MS = 30 * 60 * 1e3;
13274
14306
 
13275
14307
  // ../entries/dist/settings.js
13276
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync13, renameSync as renameSync6, chmodSync as chmodSync2, mkdirSync as mkdirSync13, existsSync as existsSync15 } from "node:fs";
14308
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync13, renameSync as renameSync6, chmodSync as chmodSync2, mkdirSync as mkdirSync13, existsSync as existsSync16 } from "node:fs";
13277
14309
  init_fs();
13278
14310
  var DEFAULT_SETTINGS = {
13279
14311
  ai_features: {
@@ -13305,10 +14337,10 @@ function fromDisk(d) {
13305
14337
  }
13306
14338
  function readSettings() {
13307
14339
  const p = settingsPath();
13308
- if (!existsSync15(p))
14340
+ if (!existsSync16(p))
13309
14341
  return DEFAULT_SETTINGS;
13310
14342
  try {
13311
- const raw = readFileSync18(p, "utf8");
14343
+ const raw = readFileSync19(p, "utf8");
13312
14344
  return fromDisk(JSON.parse(raw));
13313
14345
  } catch {
13314
14346
  return DEFAULT_SETTINGS;
@@ -13481,7 +14513,7 @@ function rollupOutcomeDay(entries) {
13481
14513
  return "exploratory";
13482
14514
  return "trivial";
13483
14515
  }
13484
- function truncate5(s, max) {
14516
+ function truncate6(s, max) {
13485
14517
  if (s.length <= max)
13486
14518
  return s;
13487
14519
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -13537,7 +14569,7 @@ function computeDaySignals(entries) {
13537
14569
  type,
13538
14570
  count: v.count,
13539
14571
  sample_description: v.sample_description,
13540
- sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
14572
+ sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
13541
14573
  }));
13542
14574
  const frameCounts = /* @__PURE__ */ new Map();
13543
14575
  for (const s of signalsList) {
@@ -13556,7 +14588,7 @@ function computeDaySignals(entries) {
13556
14588
  if ((e.first_user ?? "").length > 0)
13557
14589
  verbosity_distribution[s.verbosity] += 1;
13558
14590
  for (const ref of s.external_refs) {
13559
- external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate5(ref.preview, 200) });
14591
+ external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate6(ref.preview, 200) });
13560
14592
  }
13561
14593
  const ints = e.numbers.interrupts ?? 0;
13562
14594
  interrupts += ints;
@@ -14399,7 +15431,7 @@ function computeInteractionModes(entries) {
14399
15431
  date: entry.local_day,
14400
15432
  project_display: prettyProject3(entry.project),
14401
15433
  type: sa.type,
14402
- prompt_preview: truncate6(sa.prompt_preview, 200)
15434
+ prompt_preview: truncate7(sa.prompt_preview, 200)
14403
15435
  });
14404
15436
  }
14405
15437
  const skillExamples = [];
@@ -14416,7 +15448,7 @@ function computeInteractionModes(entries) {
14416
15448
  skillExamples.push({
14417
15449
  date: e.local_day,
14418
15450
  skill,
14419
- first_user_preview: truncate6(e.first_user, 200)
15451
+ first_user_preview: truncate7(e.first_user, 200)
14420
15452
  });
14421
15453
  }
14422
15454
  }
@@ -14433,7 +15465,7 @@ function computeInteractionModes(entries) {
14433
15465
  project_display: prettyProject3(longestTurnEntry.project),
14434
15466
  active_min: longestTurnEntry.numbers.active_min,
14435
15467
  top_tools: longestTurnEntry.top_tools.slice(0, 5),
14436
- first_user_preview: truncate6(longestTurnEntry.first_user, 200)
15468
+ first_user_preview: truncate7(longestTurnEntry.first_user, 200)
14437
15469
  } : null;
14438
15470
  const tools_per_turn = turn_count > 0 ? tools_total / turn_count : 0;
14439
15471
  const label = tools_per_turn < 5 ? "rapid" : tools_per_turn < 15 ? "mixed" : "batch";
@@ -14464,7 +15496,7 @@ function computeInteractionModes(entries) {
14464
15496
  }
14465
15497
  };
14466
15498
  }
14467
- function truncate6(s, max) {
15499
+ function truncate7(s, max) {
14468
15500
  if (s.length <= max)
14469
15501
  return s;
14470
15502
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -14521,7 +15553,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
14521
15553
  evidence_subagent = {
14522
15554
  type: sa.type,
14523
15555
  description: sa.description,
14524
- prompt_preview: truncate6(sa.prompt_preview, 200)
15556
+ prompt_preview: truncate7(sa.prompt_preview, 200)
14525
15557
  };
14526
15558
  }
14527
15559
  const project_display = repEntry ? prettyProject3(repEntry.project) : dd.projects[0]?.display_name ?? "";
@@ -14532,7 +15564,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
14532
15564
  outcome: dayOutcome.get(dd.key) ?? null,
14533
15565
  helpfulness: dayHelp.get(dd.key) ?? null,
14534
15566
  evidence_subagent,
14535
- evidence_first_user: repEntry?.first_user ? truncate6(repEntry.first_user, 200) : null,
15567
+ evidence_first_user: repEntry?.first_user ? truncate7(repEntry.first_user, 200) : null,
14536
15568
  day_signature: dd.day_signature ?? null
14537
15569
  };
14538
15570
  });
@@ -14607,7 +15639,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
14607
15639
  date: day,
14608
15640
  session_id: ref.session_id,
14609
15641
  ref_kind: ref.kind,
14610
- preview: truncate6(ref.preview, 200)
15642
+ preview: truncate7(ref.preview, 200)
14611
15643
  });
14612
15644
  }
14613
15645
  total_interrupts += signals.comm_style.steering.interrupts;
@@ -14679,7 +15711,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
14679
15711
  count: v.count,
14680
15712
  days: [...v.days].sort(),
14681
15713
  sample_description: v.sample_description,
14682
- sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
15714
+ sample_prompt_preview: truncate7(v.sample_prompt_preview, 200)
14683
15715
  })),
14684
15716
  threads,
14685
15717
  communication_style: {
@@ -14979,7 +16011,7 @@ var MonthDigestResponseSchema = external_exports.object({
14979
16011
  }).passthrough();
14980
16012
 
14981
16013
  // ../entries/dist/top-sessions.js
14982
- var IDLE_GAP_MS5 = 3 * 60 * 1e3;
16014
+ var IDLE_GAP_MS6 = 3 * 60 * 1e3;
14983
16015
  var LONG_AUTONOMOUS_MIN = 20;
14984
16016
  var N_USER = 150;
14985
16017
  var N_FIRST_AGENT = 150;
@@ -15010,7 +16042,7 @@ function activeMs(timestamps) {
15010
16042
  let active = 0;
15011
16043
  for (let i = 1; i < ts.length; i++) {
15012
16044
  const dt = ts[i] - ts[i - 1];
15013
- if (dt < IDLE_GAP_MS5)
16045
+ if (dt < IDLE_GAP_MS6)
15014
16046
  active += dt;
15015
16047
  }
15016
16048
  return active;
@@ -15184,7 +16216,7 @@ function buildSessionSlice(entry, events, daySignature) {
15184
16216
  let intEnd = sortedTs[0];
15185
16217
  for (let i = 1; i < sortedTs.length; i++) {
15186
16218
  const dt = sortedTs[i] - intEnd;
15187
- if (dt >= IDLE_GAP_MS5) {
16219
+ if (dt >= IDLE_GAP_MS6) {
15188
16220
  intervals.push({
15189
16221
  start_min: fmtMin(intStart - sliceStartMs),
15190
16222
  end_min: fmtMin(intEnd - sliceStartMs)
@@ -16068,14 +17100,14 @@ async function getUpdateAvailability() {
16068
17100
  if (isDevMode()) return null;
16069
17101
  const latest = await fetchLatestVersion();
16070
17102
  if (latest === null) return {
16071
- current: "0.16.0",
17103
+ current: "0.16.2",
16072
17104
  latest: null,
16073
17105
  updateAvailable: false
16074
17106
  };
16075
17107
  return {
16076
- current: "0.16.0",
17108
+ current: "0.16.2",
16077
17109
  latest,
16078
- updateAvailable: shouldUpdate("0.16.0", latest)
17110
+ updateAvailable: shouldUpdate("0.16.2", latest)
16079
17111
  };
16080
17112
  }
16081
17113
 
@@ -16123,7 +17155,7 @@ var perceptionHandle = setInterval(async () => {
16123
17155
  }, PERCEPTION_INTERVAL_MS);
16124
17156
  function readUpdateState() {
16125
17157
  try {
16126
- return JSON.parse(readFileSync19(UPDATE_STATE, "utf8"));
17158
+ return JSON.parse(readFileSync20(UPDATE_STATE, "utf8"));
16127
17159
  } catch {
16128
17160
  return null;
16129
17161
  }
@@ -16175,7 +17207,7 @@ async function runDaemonUpdateCheck() {
16175
17207
  return;
16176
17208
  }
16177
17209
  const entry = cliEntryPath();
16178
- if (!existsSync16(entry)) {
17210
+ if (!existsSync17(entry)) {
16179
17211
  log2("warn", `update check found ${availability.latest}, but CLI entry is missing at ${entry}`);
16180
17212
  return;
16181
17213
  }
@@ -16252,6 +17284,24 @@ async function tick() {
16252
17284
  log2("warn", `zai poll failed: ${err.message}`);
16253
17285
  }
16254
17286
  }
17287
+ try {
17288
+ const grokSnapshot = await fetchGrokUsage();
17289
+ appendSnapshot(USAGE_LOG3, grokSnapshot);
17290
+ log2(
17291
+ "info",
17292
+ `grok snapshot 5h=\u2014 7d=${grokSnapshot.seven_day.utilization}%`
17293
+ );
17294
+ } catch (err) {
17295
+ if (err instanceof GrokApiError && (err.code === "no_auth" || err.code === "not_weekly")) {
17296
+ pruneAgent(USAGE_LOG3, "grok");
17297
+ if (err.code === "no_auth") {
17298
+ } else {
17299
+ log2("warn", `grok poll skipped: ${err.message}`);
17300
+ }
17301
+ } else {
17302
+ log2("warn", `grok poll failed: ${err.message}`);
17303
+ }
17304
+ }
16255
17305
  try {
16256
17306
  const snapshot = await fetchUsage();
16257
17307
  appendSnapshot(USAGE_LOG3, snapshot);