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
package/dist/index.js CHANGED
@@ -675,7 +675,7 @@ function getAgentMetadata(kind) {
675
675
  function isAgentKind(s) {
676
676
  return typeof s === "string" && KNOWN_AGENT_KINDS.has(s);
677
677
  }
678
- var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, ZAI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
678
+ var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, ZAI_METADATA, GROK_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
679
679
  var init_agent_metadata = __esm({
680
680
  "../parser/dist/agent-metadata.js"() {
681
681
  "use strict";
@@ -721,13 +721,22 @@ var init_agent_metadata = __esm({
721
721
  accentColor: "rgb(59, 130, 246)",
722
722
  iconChar: "Z"
723
723
  };
724
+ GROK_METADATA = {
725
+ kind: "grok",
726
+ displayName: "Grok Build",
727
+ shortLabel: "Grok",
728
+ // Slate-400 — visible on dark Fleetlens chrome and still fine on light.
729
+ accentColor: "rgb(100, 116, 139)",
730
+ iconChar: "\u25C8"
731
+ };
724
732
  agentMetadata = [
725
733
  CLAUDE_CODE_METADATA,
726
734
  CODEX_METADATA,
727
735
  GEMINI_METADATA,
728
736
  ANTIGRAVITY_METADATA,
729
737
  COWORK_METADATA,
730
- ZAI_METADATA
738
+ ZAI_METADATA,
739
+ GROK_METADATA
731
740
  ];
732
741
  KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
733
742
  }
@@ -1584,11 +1593,11 @@ function defaultBranch(commonDir) {
1584
1593
  }
1585
1594
  return void 0;
1586
1595
  }
1587
- function readGitFolder(path7) {
1588
- if (!existsSync(path7))
1596
+ function readGitFolder(path9) {
1597
+ if (!existsSync(path9))
1589
1598
  return { exists: false, isWorktree: false };
1590
1599
  try {
1591
- const git = nearestDotGit(realpathOrSelf(path7));
1600
+ const git = nearestDotGit(realpathOrSelf(path9));
1592
1601
  if (!git)
1593
1602
  return { exists: true, isWorktree: false };
1594
1603
  const projectRoot = projectRootFromCommonDir(git.commonDir);
@@ -2844,6 +2853,11 @@ function parseRollout(file, lines) {
2844
2853
  let lastUserPreview;
2845
2854
  let lastAgentPreview;
2846
2855
  const tsMs = [];
2856
+ let threadSource;
2857
+ let rootSessionId;
2858
+ let parentThreadId;
2859
+ let agentNickname;
2860
+ let agentPath;
2847
2861
  let idx = 0;
2848
2862
  for (const line of lines) {
2849
2863
  if (typeof line !== "object" || line === null)
@@ -2864,6 +2878,16 @@ function parseRollout(file, lines) {
2864
2878
  if (type === "session_meta") {
2865
2879
  if (typeof payload.cwd === "string")
2866
2880
  cwd = payload.cwd;
2881
+ if (threadSource === void 0 && typeof payload.thread_source === "string")
2882
+ threadSource = payload.thread_source;
2883
+ if (rootSessionId === void 0 && typeof payload.session_id === "string")
2884
+ rootSessionId = payload.session_id;
2885
+ if (parentThreadId === void 0 && typeof payload.parent_thread_id === "string")
2886
+ parentThreadId = payload.parent_thread_id;
2887
+ if (agentNickname === void 0 && typeof payload.agent_nickname === "string")
2888
+ agentNickname = payload.agent_nickname;
2889
+ if (agentPath === void 0 && typeof payload.agent_path === "string")
2890
+ agentPath = payload.agent_path;
2867
2891
  continue;
2868
2892
  }
2869
2893
  if (type === "turn_context") {
@@ -3067,7 +3091,7 @@ function parseRollout(file, lines) {
3067
3091
  airTimeMs,
3068
3092
  activeSegments
3069
3093
  };
3070
- return { meta, events };
3094
+ return { meta, events, threadSource, rootSessionId, parentThreadId, agentNickname, agentPath };
3071
3095
  }
3072
3096
  function numberOf(v) {
3073
3097
  return typeof v === "number" && Number.isFinite(v) ? v : void 0;
@@ -3105,28 +3129,112 @@ function clearCodexCaches() {
3105
3129
  metaCache2.clear();
3106
3130
  detailCache2.clear();
3107
3131
  }
3108
- async function listCodexSessions(opts = {}) {
3109
- const root = opts.root ?? DEFAULT_CODEX_ROOT;
3132
+ async function scanAllCodex(root) {
3110
3133
  const files = await listRolloutFiles(root);
3111
3134
  const out = [];
3112
3135
  for (const file of files) {
3113
3136
  const cached = metaCache2.get(file.filePath);
3114
3137
  if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
3115
- out.push(cached.meta);
3138
+ out.push({
3139
+ file,
3140
+ meta: cached.meta,
3141
+ threadSource: cached.threadSource,
3142
+ rootSessionId: cached.rootSessionId,
3143
+ parentThreadId: cached.parentThreadId,
3144
+ agentNickname: cached.agentNickname,
3145
+ agentPath: cached.agentPath
3146
+ });
3116
3147
  continue;
3117
3148
  }
3118
3149
  try {
3119
3150
  const lines = await readJsonl(file.filePath);
3120
- const { meta } = parseRollout(file, lines);
3151
+ const parsed = parseRollout(file, lines);
3121
3152
  metaCache2.set(file.filePath, {
3122
- meta,
3153
+ meta: parsed.meta,
3123
3154
  mtimeMs: file.mtimeMs,
3124
- sizeBytes: file.sizeBytes
3155
+ sizeBytes: file.sizeBytes,
3156
+ threadSource: parsed.threadSource,
3157
+ rootSessionId: parsed.rootSessionId,
3158
+ parentThreadId: parsed.parentThreadId,
3159
+ agentNickname: parsed.agentNickname,
3160
+ agentPath: parsed.agentPath
3161
+ });
3162
+ out.push({
3163
+ file,
3164
+ meta: parsed.meta,
3165
+ threadSource: parsed.threadSource,
3166
+ rootSessionId: parsed.rootSessionId,
3167
+ parentThreadId: parsed.parentThreadId,
3168
+ agentNickname: parsed.agentNickname,
3169
+ agentPath: parsed.agentPath
3125
3170
  });
3126
- out.push(meta);
3127
3171
  } catch {
3128
3172
  }
3129
3173
  }
3174
+ return out;
3175
+ }
3176
+ function buildSubagentRun(entry, parentStartMs) {
3177
+ const meta = entry.meta;
3178
+ const startMs = meta.firstTimestamp ? Date.parse(meta.firstTimestamp) : void 0;
3179
+ const endMs = meta.lastTimestamp ? Date.parse(meta.lastTimestamp) : void 0;
3180
+ const startOk = startMs !== void 0 && Number.isFinite(startMs) ? startMs : void 0;
3181
+ const endOk = endMs !== void 0 && Number.isFinite(endMs) ? endMs : void 0;
3182
+ return {
3183
+ agentId: meta.id,
3184
+ agentType: entry.agentNickname ?? entry.agentPath ?? "subagent",
3185
+ description: entry.agentPath ?? entry.agentNickname ?? meta.id,
3186
+ startMs: startOk,
3187
+ endMs: endOk,
3188
+ durationMs: meta.durationMs,
3189
+ startTOffsetMs: parentStartMs !== void 0 && startOk !== void 0 ? Math.max(0, startOk - parentStartMs) : void 0,
3190
+ endTOffsetMs: parentStartMs !== void 0 && endOk !== void 0 ? Math.max(0, endOk - parentStartMs) : void 0,
3191
+ eventCount: meta.eventCount,
3192
+ totalUsage: meta.totalUsage,
3193
+ model: meta.model,
3194
+ toolCallCount: meta.toolCallCount,
3195
+ finalPreview: meta.lastAgentPreview
3196
+ };
3197
+ }
3198
+ async function listCodexSessions(opts = {}) {
3199
+ const root = opts.root ?? DEFAULT_CODEX_ROOT;
3200
+ const all = await scanAllCodex(root);
3201
+ const subagentsByRoot = /* @__PURE__ */ new Map();
3202
+ for (const entry of all) {
3203
+ if (entry.threadSource !== "subagent" || !entry.rootSessionId)
3204
+ continue;
3205
+ const list = subagentsByRoot.get(entry.rootSessionId);
3206
+ if (list)
3207
+ list.push(entry);
3208
+ else
3209
+ subagentsByRoot.set(entry.rootSessionId, [entry]);
3210
+ }
3211
+ const out = [];
3212
+ for (const entry of all) {
3213
+ if (entry.threadSource === "subagent")
3214
+ continue;
3215
+ const children = subagentsByRoot.get(entry.meta.id);
3216
+ if (!children || children.length === 0) {
3217
+ out.push(entry.meta);
3218
+ continue;
3219
+ }
3220
+ const merged = {
3221
+ ...entry.meta,
3222
+ spawnedAgentCount: children.length,
3223
+ totalUsage: {
3224
+ input: entry.meta.totalUsage.input + children.reduce((s, c) => s + c.meta.totalUsage.input, 0),
3225
+ output: entry.meta.totalUsage.output + children.reduce((s, c) => s + c.meta.totalUsage.output, 0),
3226
+ cacheRead: entry.meta.totalUsage.cacheRead + children.reduce((s, c) => s + c.meta.totalUsage.cacheRead, 0),
3227
+ cacheWrite: entry.meta.totalUsage.cacheWrite + children.reduce((s, c) => s + c.meta.totalUsage.cacheWrite, 0)
3228
+ },
3229
+ toolCallCount: (entry.meta.toolCallCount ?? 0) + children.reduce((s, c) => s + (c.meta.toolCallCount ?? 0), 0)
3230
+ };
3231
+ for (const c of children) {
3232
+ if (c.meta.lastTimestamp && (!merged.lastTimestamp || c.meta.lastTimestamp > merged.lastTimestamp)) {
3233
+ merged.lastTimestamp = c.meta.lastTimestamp;
3234
+ }
3235
+ }
3236
+ out.push(merged);
3237
+ }
3130
3238
  out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
3131
3239
  if (opts.limit !== void 0)
3132
3240
  return out.slice(0, opts.limit);
@@ -3134,17 +3242,41 @@ async function listCodexSessions(opts = {}) {
3134
3242
  }
3135
3243
  async function getCodexSession(id, opts = {}) {
3136
3244
  const root = opts.root ?? DEFAULT_CODEX_ROOT;
3137
- const files = await listRolloutFiles(root);
3138
- const file = files.find((f) => f.sessionId === id);
3139
- if (!file)
3140
- return null;
3245
+ const all = await scanAllCodex(root);
3246
+ const rootEntry = all.find((a) => a.meta.id === id && a.threadSource !== "subagent");
3247
+ if (!rootEntry) {
3248
+ const direct = all.find((a) => a.meta.id === id);
3249
+ if (!direct)
3250
+ return null;
3251
+ const cached2 = detailCache2.get(direct.file.filePath);
3252
+ if (cached2 && cached2.mtimeMs === direct.file.mtimeMs && cached2.sizeBytes === direct.file.sizeBytes) {
3253
+ return cached2.detail;
3254
+ }
3255
+ const lines2 = await readJsonl(direct.file.filePath);
3256
+ const { meta: meta2, events: events2 } = parseRollout(direct.file, lines2);
3257
+ const detail2 = { ...meta2, events: events2 };
3258
+ detailCache2.set(direct.file.filePath, {
3259
+ detail: detail2,
3260
+ mtimeMs: direct.file.mtimeMs,
3261
+ sizeBytes: direct.file.sizeBytes
3262
+ });
3263
+ return detail2;
3264
+ }
3265
+ const file = rootEntry.file;
3141
3266
  const cached = detailCache2.get(file.filePath);
3142
3267
  if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
3143
3268
  return cached.detail;
3144
3269
  }
3145
3270
  const lines = await readJsonl(file.filePath);
3146
3271
  const { meta, events } = parseRollout(file, lines);
3147
- const detail = { ...meta, events };
3272
+ const children = all.filter((a) => a.threadSource === "subagent" && a.rootSessionId === id);
3273
+ const parentStartMs = meta.firstTimestamp ? Date.parse(meta.firstTimestamp) : void 0;
3274
+ const subagents = children.map((c) => buildSubagentRun(c, parentStartMs)).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
3275
+ const detail = {
3276
+ ...meta,
3277
+ events,
3278
+ ...subagents.length > 0 ? { subagents, spawnedAgentCount: subagents.length } : {}
3279
+ };
3148
3280
  detailCache2.set(file.filePath, {
3149
3281
  detail,
3150
3282
  mtimeMs: file.mtimeMs,
@@ -4469,6 +4601,672 @@ var init_cowork = __esm({
4469
4601
  }
4470
4602
  });
4471
4603
 
4604
+ // ../parser/dist/grok.js
4605
+ import { promises as fs6 } from "node:fs";
4606
+ import os6 from "node:os";
4607
+ import path6 from "node:path";
4608
+ function resolveDefaultGrokRoot() {
4609
+ const home = process.env.GROK_HOME || path6.join(os6.homedir(), ".grok");
4610
+ return path6.join(home, "sessions");
4611
+ }
4612
+ async function safeReaddir5(p) {
4613
+ return fs6.readdir(p).catch(() => []);
4614
+ }
4615
+ async function safeReadJson(p) {
4616
+ const raw = await fs6.readFile(p, "utf8").catch(() => null);
4617
+ if (raw == null)
4618
+ return null;
4619
+ try {
4620
+ return JSON.parse(raw);
4621
+ } catch {
4622
+ return null;
4623
+ }
4624
+ }
4625
+ async function resolveEncodedCwd(groupDir, encoded) {
4626
+ const cwdFile = path6.join(groupDir, ".cwd");
4627
+ const fromFile = await fs6.readFile(cwdFile, "utf8").catch(() => null);
4628
+ if (fromFile && fromFile.trim())
4629
+ return fromFile.trim();
4630
+ try {
4631
+ return decodeURIComponent(encoded);
4632
+ } catch {
4633
+ return encoded;
4634
+ }
4635
+ }
4636
+ async function listSessionDirs(root) {
4637
+ const out = [];
4638
+ const groups = await safeReaddir5(root);
4639
+ for (const group of groups) {
4640
+ if (group === "session_search.sqlite" || group.startsWith("."))
4641
+ continue;
4642
+ const groupDir = path6.join(root, group);
4643
+ const groupStat = await fs6.stat(groupDir).catch(() => null);
4644
+ if (!groupStat?.isDirectory())
4645
+ continue;
4646
+ const decodedCwd = await resolveEncodedCwd(groupDir, group);
4647
+ const entries2 = await safeReaddir5(groupDir);
4648
+ for (const entry of entries2) {
4649
+ if (entry === "prompt_history.jsonl" || entry.startsWith("."))
4650
+ continue;
4651
+ const dirPath = path6.join(groupDir, entry);
4652
+ const summaryPath = path6.join(dirPath, "summary.json");
4653
+ const updatesPath = path6.join(dirPath, "updates.jsonl");
4654
+ const signalsCandidate = path6.join(dirPath, "signals.json");
4655
+ const [summaryStat, updatesStat, signalsStat] = await Promise.all([
4656
+ fs6.stat(summaryPath).catch(() => null),
4657
+ fs6.stat(updatesPath).catch(() => null),
4658
+ fs6.stat(signalsCandidate).catch(() => null)
4659
+ ]);
4660
+ if (!summaryStat?.isFile())
4661
+ continue;
4662
+ const mtimeMs = Math.max(summaryStat.mtimeMs, updatesStat?.mtimeMs ?? 0);
4663
+ const sizeBytes = (updatesStat?.size ?? 0) + summaryStat.size;
4664
+ out.push({
4665
+ dirPath,
4666
+ updatesPath,
4667
+ summaryPath,
4668
+ signalsPath: signalsStat?.isFile() ? signalsCandidate : null,
4669
+ sessionId: entry,
4670
+ groupName: group,
4671
+ decodedCwd,
4672
+ mtimeMs,
4673
+ sizeBytes
4674
+ });
4675
+ }
4676
+ }
4677
+ return out;
4678
+ }
4679
+ function emptyUsage4() {
4680
+ return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
4681
+ }
4682
+ function previewOf4(text) {
4683
+ return text.replace(/\s+/g, " ").trim().slice(0, 200);
4684
+ }
4685
+ function truncate5(s, n) {
4686
+ return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
4687
+ }
4688
+ function textFromContent2(content) {
4689
+ if (!content)
4690
+ return "";
4691
+ if (typeof content === "string")
4692
+ return content;
4693
+ if (typeof content.text === "string")
4694
+ return content.text;
4695
+ return "";
4696
+ }
4697
+ function toolResultText(update2) {
4698
+ const items = update2.content;
4699
+ if (Array.isArray(items)) {
4700
+ const parts = [];
4701
+ for (const item of items) {
4702
+ if (!item || typeof item !== "object")
4703
+ continue;
4704
+ if (typeof item.text === "string" && item.text) {
4705
+ parts.push(item.text);
4706
+ continue;
4707
+ }
4708
+ const inner = item.content;
4709
+ if (typeof inner === "string" && inner)
4710
+ parts.push(inner);
4711
+ else if (inner && typeof inner === "object" && typeof inner.text === "string") {
4712
+ parts.push(inner.text);
4713
+ }
4714
+ }
4715
+ if (parts.length)
4716
+ return parts.join("\n");
4717
+ }
4718
+ const raw = update2.rawOutput;
4719
+ if (raw == null)
4720
+ return "";
4721
+ if (typeof raw === "string")
4722
+ return raw;
4723
+ if (typeof raw === "object") {
4724
+ const r = raw;
4725
+ if (typeof r.output_for_prompt === "string")
4726
+ return r.output_for_prompt;
4727
+ if (typeof r.summary_for_prompt === "string")
4728
+ return r.summary_for_prompt;
4729
+ if (r.Content && typeof r.Content === "object") {
4730
+ const c = r.Content;
4731
+ if (typeof c.content === "string")
4732
+ return c.content;
4733
+ }
4734
+ if (r.TodosUpdated && typeof r.TodosUpdated === "object") {
4735
+ const t = r.TodosUpdated;
4736
+ if (typeof t.summary_for_prompt === "string")
4737
+ return t.summary_for_prompt;
4738
+ }
4739
+ if (Array.isArray(r.stdout) || Array.isArray(r.output)) {
4740
+ try {
4741
+ return JSON.stringify({
4742
+ type: r.type,
4743
+ exit_code: r.exit_code,
4744
+ note: "binary/stdout omitted"
4745
+ });
4746
+ } catch {
4747
+ return "";
4748
+ }
4749
+ }
4750
+ try {
4751
+ return JSON.stringify(raw);
4752
+ } catch {
4753
+ return "";
4754
+ }
4755
+ }
4756
+ return String(raw);
4757
+ }
4758
+ function toolNameOf(update2) {
4759
+ const meta = update2._meta;
4760
+ if (meta && typeof meta === "object") {
4761
+ const xai = meta["x.ai/tool"];
4762
+ if (xai && typeof xai === "object") {
4763
+ const name = xai.name;
4764
+ if (typeof name === "string" && name)
4765
+ return name;
4766
+ }
4767
+ }
4768
+ if (typeof update2.title === "string" && update2.title) {
4769
+ if (!update2.title.includes(" ") && !update2.title.includes("`"))
4770
+ return update2.title;
4771
+ return update2.title;
4772
+ }
4773
+ return "tool";
4774
+ }
4775
+ function statusOf(update2) {
4776
+ const s = update2.status;
4777
+ if (typeof s === "string")
4778
+ return s;
4779
+ if (s && typeof s === "object" && typeof s.status === "string")
4780
+ return s.status;
4781
+ return void 0;
4782
+ }
4783
+ function lineTimestampIso(line) {
4784
+ const meta = line.params?._meta;
4785
+ const agentMs = meta && typeof meta.agentTimestampMs === "number" ? meta.agentTimestampMs : void 0;
4786
+ if (agentMs != null && Number.isFinite(agentMs)) {
4787
+ return new Date(agentMs).toISOString();
4788
+ }
4789
+ const ts = line.timestamp;
4790
+ if (typeof ts === "number" && Number.isFinite(ts)) {
4791
+ const ms = ts > 1e12 ? ts : ts * 1e3;
4792
+ return new Date(ms).toISOString();
4793
+ }
4794
+ return void 0;
4795
+ }
4796
+ function computeActiveSegments5(tsMs) {
4797
+ if (tsMs.length === 0)
4798
+ return [];
4799
+ const sorted = [...tsMs].sort((a, b) => a - b);
4800
+ const out = [];
4801
+ let segStart = sorted[0];
4802
+ let segEnd = sorted[0];
4803
+ for (let i = 1; i < sorted.length; i++) {
4804
+ const t = sorted[i];
4805
+ if (t - segEnd > IDLE_GAP_MS4) {
4806
+ out.push({ startMs: segStart, endMs: segEnd });
4807
+ segStart = t;
4808
+ }
4809
+ segEnd = t;
4810
+ }
4811
+ out.push({ startMs: segStart, endMs: segEnd });
4812
+ return out;
4813
+ }
4814
+ async function parseSession3(dir) {
4815
+ const [summary, signals, updatesRaw] = await Promise.all([
4816
+ safeReadJson(dir.summaryPath),
4817
+ dir.signalsPath ? safeReadJson(dir.signalsPath) : Promise.resolve(null),
4818
+ fs6.readFile(dir.updatesPath, "utf8").catch(() => "")
4819
+ ]);
4820
+ const sessionId = summary?.info?.id ?? dir.sessionId;
4821
+ const cwd = summary?.info?.cwd ?? dir.decodedCwd;
4822
+ let model = summary?.current_model_id ?? signals?.primaryModelId ?? signals?.modelsUsed?.[0];
4823
+ const events = [];
4824
+ const totalUsage = emptyUsage4();
4825
+ if (signals?.contextTokensUsed && signals.contextTokensUsed > 0) {
4826
+ totalUsage.input = signals.contextTokensUsed;
4827
+ }
4828
+ let firstTimestamp;
4829
+ let lastTimestamp;
4830
+ let toolCallCount = 0;
4831
+ let turnCount = 0;
4832
+ let firstUserPreview;
4833
+ let lastUserPreview;
4834
+ let lastAgentPreview;
4835
+ const tsMs = [];
4836
+ let idx = 0;
4837
+ const completedToolResults = /* @__PURE__ */ new Set();
4838
+ let maxTotalTokens = 0;
4839
+ function noteTs(ts, role) {
4840
+ if (!ts || role === "meta")
4841
+ return;
4842
+ if (!firstTimestamp)
4843
+ firstTimestamp = ts;
4844
+ lastTimestamp = ts;
4845
+ const ms = Date.parse(ts);
4846
+ if (Number.isFinite(ms))
4847
+ tsMs.push(ms);
4848
+ }
4849
+ function pushEvent(e) {
4850
+ events.push(e);
4851
+ noteTs(e.timestamp, e.role);
4852
+ }
4853
+ let buf = null;
4854
+ function flushBuf() {
4855
+ if (!buf)
4856
+ return;
4857
+ const text = buf.texts.join("");
4858
+ const preview = previewOf4(text);
4859
+ if (buf.kind === "user") {
4860
+ const isHidden = !text || isFrameworkInjectedUserInput(text);
4861
+ if (text && !isHidden) {
4862
+ if (!firstUserPreview)
4863
+ firstUserPreview = preview;
4864
+ lastUserPreview = preview;
4865
+ turnCount += 1;
4866
+ }
4867
+ if (text) {
4868
+ pushEvent({
4869
+ index: idx++,
4870
+ timestamp: buf.firstTs,
4871
+ role: "user",
4872
+ rawType: "grok/user_message",
4873
+ preview,
4874
+ blocks: [{ type: "text", text }],
4875
+ messageId: buf.promptId,
4876
+ raw: buf.raw.length === 1 ? buf.raw[0] : buf.raw
4877
+ });
4878
+ }
4879
+ } else if (buf.kind === "agent") {
4880
+ if (text)
4881
+ lastAgentPreview = preview;
4882
+ if (text) {
4883
+ pushEvent({
4884
+ index: idx++,
4885
+ timestamp: buf.firstTs,
4886
+ role: "agent",
4887
+ rawType: "grok/agent_message",
4888
+ preview,
4889
+ blocks: [{ type: "text", text }],
4890
+ messageId: buf.promptId,
4891
+ model: buf.model ?? model,
4892
+ raw: buf.raw.length === 1 ? buf.raw[0] : buf.raw
4893
+ });
4894
+ }
4895
+ } else if (buf.kind === "thought") {
4896
+ if (text) {
4897
+ pushEvent({
4898
+ index: idx++,
4899
+ timestamp: buf.firstTs,
4900
+ role: "agent-thinking",
4901
+ rawType: "grok/agent_thought",
4902
+ preview,
4903
+ blocks: [{ type: "thinking", thinking: text }],
4904
+ messageId: buf.promptId,
4905
+ model: buf.model ?? model,
4906
+ raw: buf.raw.length === 1 ? buf.raw[0] : buf.raw
4907
+ });
4908
+ }
4909
+ }
4910
+ buf = null;
4911
+ }
4912
+ function appendChunk(kind, text, ts, promptId, modelId, raw) {
4913
+ if (!text && kind === "user")
4914
+ return;
4915
+ if (buf && buf.kind !== kind)
4916
+ flushBuf();
4917
+ if (!buf) {
4918
+ buf = {
4919
+ kind,
4920
+ texts: [],
4921
+ firstTs: ts,
4922
+ lastTs: ts,
4923
+ model: modelId,
4924
+ promptId,
4925
+ raw: []
4926
+ };
4927
+ }
4928
+ if (text)
4929
+ buf.texts.push(text);
4930
+ buf.lastTs = ts ?? buf.lastTs;
4931
+ if (modelId)
4932
+ buf.model = modelId;
4933
+ if (promptId)
4934
+ buf.promptId = promptId;
4935
+ buf.raw.push(raw);
4936
+ }
4937
+ const lines = updatesRaw.split("\n");
4938
+ for (const line of lines) {
4939
+ const trimmed = line.trim();
4940
+ if (!trimmed)
4941
+ continue;
4942
+ let obj;
4943
+ try {
4944
+ obj = JSON.parse(trimmed);
4945
+ } catch {
4946
+ continue;
4947
+ }
4948
+ const update2 = obj.params?.update;
4949
+ if (!update2 || typeof update2 !== "object")
4950
+ continue;
4951
+ const st = update2.sessionUpdate;
4952
+ if (!st)
4953
+ continue;
4954
+ const ts = lineTimestampIso(obj);
4955
+ const lineMeta = obj.params?._meta ?? {};
4956
+ const updateMeta = update2._meta ?? {};
4957
+ const promptId = typeof lineMeta.promptId === "string" && lineMeta.promptId || typeof updateMeta.promptId === "string" && updateMeta.promptId || void 0;
4958
+ const modelId = typeof updateMeta.modelId === "string" && updateMeta.modelId || typeof lineMeta.modelId === "string" && lineMeta.modelId || void 0;
4959
+ if (modelId)
4960
+ model = modelId;
4961
+ const totalTok = lineMeta.totalTokens;
4962
+ if (typeof totalTok === "number" && totalTok > maxTotalTokens) {
4963
+ maxTotalTokens = totalTok;
4964
+ }
4965
+ if (st === "user_message_chunk") {
4966
+ const text = textFromContent2(update2.content);
4967
+ appendChunk("user", text, ts, promptId, modelId, obj);
4968
+ continue;
4969
+ }
4970
+ if (st === "agent_message_chunk") {
4971
+ const text = textFromContent2(update2.content);
4972
+ appendChunk("agent", text, ts, promptId, modelId, obj);
4973
+ continue;
4974
+ }
4975
+ if (st === "agent_thought_chunk") {
4976
+ const text = textFromContent2(update2.content);
4977
+ appendChunk("thought", text, ts, promptId, modelId, obj);
4978
+ continue;
4979
+ }
4980
+ flushBuf();
4981
+ if (st === "tool_call") {
4982
+ const toolCallId = typeof update2.toolCallId === "string" ? update2.toolCallId : `grok-${idx}`;
4983
+ const name = toolNameOf(update2);
4984
+ const input = update2.rawInput ?? {};
4985
+ const argsStr = input ? JSON.stringify(input) : "";
4986
+ toolCallCount += 1;
4987
+ pushEvent({
4988
+ index: idx++,
4989
+ timestamp: ts,
4990
+ role: "tool-call",
4991
+ rawType: "grok/tool_call",
4992
+ preview: `${name}(${truncate5(argsStr, 80)})`,
4993
+ blocks: [{ type: "tool_use", id: toolCallId, name, input }],
4994
+ toolName: name,
4995
+ toolUseId: toolCallId,
4996
+ model,
4997
+ raw: obj
4998
+ });
4999
+ continue;
5000
+ }
5001
+ if (st === "tool_call_update") {
5002
+ const status2 = statusOf(update2);
5003
+ if (status2 !== "completed" && status2 !== "failed" && status2 !== "error" && status2 !== "cancelled") {
5004
+ continue;
5005
+ }
5006
+ const toolCallId = typeof update2.toolCallId === "string" ? update2.toolCallId : "";
5007
+ if (toolCallId && completedToolResults.has(toolCallId))
5008
+ continue;
5009
+ if (toolCallId)
5010
+ completedToolResults.add(toolCallId);
5011
+ const resultText = toolResultText(update2);
5012
+ const isError = status2 === "failed" || status2 === "error" || status2 === "cancelled";
5013
+ pushEvent({
5014
+ index: idx++,
5015
+ timestamp: ts,
5016
+ role: "tool-result",
5017
+ rawType: "grok/tool_result",
5018
+ preview: previewOf4(resultText),
5019
+ blocks: [
5020
+ {
5021
+ type: "tool_result",
5022
+ tool_use_id: toolCallId,
5023
+ content: resultText,
5024
+ is_error: isError || void 0
5025
+ }
5026
+ ],
5027
+ toolUseId: toolCallId || void 0,
5028
+ toolResult: resultText,
5029
+ raw: obj
5030
+ });
5031
+ continue;
5032
+ }
5033
+ if (st === "turn_completed") {
5034
+ continue;
5035
+ }
5036
+ }
5037
+ flushBuf();
5038
+ if (totalUsage.input === 0 && maxTotalTokens > 0) {
5039
+ totalUsage.input = maxTotalTokens;
5040
+ }
5041
+ if (!firstTimestamp && summary?.created_at)
5042
+ firstTimestamp = summary.created_at;
5043
+ if (!lastTimestamp) {
5044
+ lastTimestamp = summary?.last_active_at ?? summary?.updated_at ?? firstTimestamp;
5045
+ }
5046
+ if (signals?.toolCallCount != null && signals.toolCallCount > toolCallCount) {
5047
+ toolCallCount = signals.toolCallCount;
5048
+ }
5049
+ if (signals?.turnCount != null && signals.turnCount > turnCount) {
5050
+ turnCount = signals.turnCount;
5051
+ }
5052
+ const startMs = firstTimestamp ? Date.parse(firstTimestamp) : void 0;
5053
+ if (startMs !== void 0 && Number.isFinite(startMs)) {
5054
+ let prevMs;
5055
+ for (const ev of events) {
5056
+ if (!ev.timestamp)
5057
+ continue;
5058
+ const ms = Date.parse(ev.timestamp);
5059
+ if (!Number.isFinite(ms))
5060
+ continue;
5061
+ ev.tOffsetMs = Math.max(0, ms - startMs);
5062
+ if (prevMs !== void 0)
5063
+ ev.gapMs = Math.max(0, ms - prevMs);
5064
+ prevMs = ms;
5065
+ }
5066
+ }
5067
+ const activeSegments = computeActiveSegments5(tsMs);
5068
+ const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
5069
+ const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
5070
+ const project = cwd ? resolveProjectIdentity(cwd) : void 0;
5071
+ const projectName = project?.projectName ?? cwd ?? dir.decodedCwd;
5072
+ const projectDir = dir.groupName || (cwd ? encodeURIComponent(cwd) : "(unknown)");
5073
+ if (!firstUserPreview) {
5074
+ const title = summary?.generated_title || summary?.session_summary;
5075
+ if (title)
5076
+ firstUserPreview = previewOf4(title);
5077
+ }
5078
+ const spawnedAgentCount = await countSubagentChildren(dir.dirPath);
5079
+ const meta = {
5080
+ agent: "grok",
5081
+ id: sessionId,
5082
+ filePath: dir.updatesPath,
5083
+ projectName,
5084
+ worktreeName: project?.worktreeName,
5085
+ repoName: project?.repoName,
5086
+ projectDir,
5087
+ sessionId,
5088
+ firstTimestamp,
5089
+ lastTimestamp,
5090
+ lastActivityMs: lastTimestamp ? Date.parse(lastTimestamp) : void 0,
5091
+ durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
5092
+ eventCount: events.length,
5093
+ model,
5094
+ cwd,
5095
+ gitBranch: summary?.head_branch,
5096
+ agentName: summary?.agent_name,
5097
+ totalUsage,
5098
+ status: "idle",
5099
+ firstUserPreview,
5100
+ lastUserPreview,
5101
+ lastAgentPreview,
5102
+ toolCallCount,
5103
+ turnCount,
5104
+ linesAdded: signals?.agentLinesAdded,
5105
+ linesRemoved: signals?.agentLinesRemoved,
5106
+ airTimeMs,
5107
+ activeSegments,
5108
+ ...spawnedAgentCount > 0 ? { spawnedAgentCount } : {}
5109
+ };
5110
+ return { meta, events, sessionKind: summary?.session_kind };
5111
+ }
5112
+ async function countSubagentChildren(dirPath) {
5113
+ const subRoot = path6.join(dirPath, "subagents");
5114
+ const entries2 = await safeReaddir5(subRoot);
5115
+ let n = 0;
5116
+ for (const e of entries2) {
5117
+ const st = await fs6.stat(path6.join(subRoot, e)).catch(() => null);
5118
+ if (st?.isDirectory())
5119
+ n += 1;
5120
+ }
5121
+ return n;
5122
+ }
5123
+ async function loadGrokSubagents(parentDir, parentStartMs) {
5124
+ const subRoot = path6.join(parentDir.dirPath, "subagents");
5125
+ const entries2 = await safeReaddir5(subRoot);
5126
+ const groupDir = path6.dirname(parentDir.dirPath);
5127
+ const runs2 = [];
5128
+ for (const entry of entries2) {
5129
+ const metaPath = path6.join(subRoot, entry, "meta.json");
5130
+ const meta = await safeReadJson(metaPath);
5131
+ if (!meta)
5132
+ continue;
5133
+ const childId = meta.child_session_id ?? meta.subagent_id ?? entry;
5134
+ const childDir = path6.join(groupDir, childId);
5135
+ const [childSummary, childSignals] = await Promise.all([
5136
+ safeReadJson(path6.join(childDir, "summary.json")),
5137
+ safeReadJson(path6.join(childDir, "signals.json"))
5138
+ ]);
5139
+ const startMs = childSummary?.created_at ? Date.parse(childSummary.created_at) : void 0;
5140
+ const endIso = childSummary?.last_active_at ?? childSummary?.updated_at;
5141
+ const endMs = endIso ? Date.parse(endIso) : void 0;
5142
+ const startOk = startMs !== void 0 && Number.isFinite(startMs) ? startMs : void 0;
5143
+ const endOk = endMs !== void 0 && Number.isFinite(endMs) ? endMs : void 0;
5144
+ const usage2 = emptyUsage4();
5145
+ if (childSignals?.contextTokensUsed)
5146
+ usage2.input = childSignals.contextTokensUsed;
5147
+ runs2.push({
5148
+ agentId: childId,
5149
+ agentType: meta.subagent_type ?? childSummary?.agent_name ?? "subagent",
5150
+ description: meta.description && meta.description.trim() || childSummary?.generated_title || childSummary?.session_summary || childId,
5151
+ startMs: startOk,
5152
+ endMs: endOk,
5153
+ durationMs: startOk !== void 0 && endOk !== void 0 ? Math.max(0, endOk - startOk) : void 0,
5154
+ startTOffsetMs: parentStartMs !== void 0 && startOk !== void 0 ? Math.max(0, startOk - parentStartMs) : void 0,
5155
+ endTOffsetMs: parentStartMs !== void 0 && endOk !== void 0 ? Math.max(0, endOk - parentStartMs) : void 0,
5156
+ eventCount: childSummary?.num_messages ?? childSummary?.num_chat_messages ?? 0,
5157
+ totalUsage: usage2,
5158
+ prompt: typeof meta.prompt === "string" ? meta.prompt : void 0,
5159
+ model: childSummary?.current_model_id ?? childSignals?.primaryModelId,
5160
+ toolCallCount: childSignals?.toolCallCount
5161
+ });
5162
+ }
5163
+ runs2.sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
5164
+ return runs2;
5165
+ }
5166
+ function clearGrokCaches() {
5167
+ metaCache6.clear();
5168
+ detailCache6.clear();
5169
+ }
5170
+ async function listGrokSessions(opts = {}) {
5171
+ const root = opts.root ?? resolveDefaultGrokRoot();
5172
+ const dirs = await listSessionDirs(root);
5173
+ const out = [];
5174
+ for (const dir of dirs) {
5175
+ const summaryPeek = await safeReadJson(dir.summaryPath);
5176
+ if (summaryPeek?.session_kind === "subagent")
5177
+ continue;
5178
+ const cached = metaCache6.get(dir.dirPath);
5179
+ if (cached && cached.mtimeMs === dir.mtimeMs && cached.sizeBytes === dir.sizeBytes) {
5180
+ out.push(cached.meta);
5181
+ continue;
5182
+ }
5183
+ try {
5184
+ const { meta, sessionKind } = await parseSession3(dir);
5185
+ if (sessionKind === "subagent")
5186
+ continue;
5187
+ metaCache6.set(dir.dirPath, {
5188
+ meta,
5189
+ mtimeMs: dir.mtimeMs,
5190
+ sizeBytes: dir.sizeBytes
5191
+ });
5192
+ out.push(meta);
5193
+ } catch {
5194
+ }
5195
+ }
5196
+ out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
5197
+ if (opts.limit !== void 0)
5198
+ return out.slice(0, opts.limit);
5199
+ return out;
5200
+ }
5201
+ async function getGrokSession(id, opts = {}) {
5202
+ const root = opts.root ?? resolveDefaultGrokRoot();
5203
+ const dirs = await listSessionDirs(root);
5204
+ const chosen = dirs.find((d) => d.sessionId === id);
5205
+ if (!chosen) {
5206
+ for (const dir of dirs) {
5207
+ try {
5208
+ const { meta: meta2, events: events2 } = await parseSession3(dir);
5209
+ if (meta2.id === id) {
5210
+ const detail2 = { ...meta2, events: events2 };
5211
+ detailCache6.set(dir.dirPath, {
5212
+ detail: detail2,
5213
+ mtimeMs: dir.mtimeMs,
5214
+ sizeBytes: dir.sizeBytes
5215
+ });
5216
+ return detail2;
5217
+ }
5218
+ } catch {
5219
+ }
5220
+ }
5221
+ return null;
5222
+ }
5223
+ const cached = detailCache6.get(chosen.dirPath);
5224
+ if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
5225
+ return cached.detail;
5226
+ }
5227
+ const { meta, events } = await parseSession3(chosen);
5228
+ const parentStartMs = meta.firstTimestamp ? Date.parse(meta.firstTimestamp) : void 0;
5229
+ const subagents = await loadGrokSubagents(chosen, parentStartMs !== void 0 && Number.isFinite(parentStartMs) ? parentStartMs : void 0);
5230
+ const detail = {
5231
+ ...meta,
5232
+ events,
5233
+ ...subagents.length > 0 ? { subagents, spawnedAgentCount: subagents.length } : {}
5234
+ };
5235
+ detailCache6.set(chosen.dirPath, {
5236
+ detail,
5237
+ mtimeMs: chosen.mtimeMs,
5238
+ sizeBytes: chosen.sizeBytes
5239
+ });
5240
+ metaCache6.set(chosen.dirPath, {
5241
+ meta: {
5242
+ ...meta,
5243
+ ...subagents.length > 0 ? { spawnedAgentCount: subagents.length } : {}
5244
+ },
5245
+ mtimeMs: chosen.mtimeMs,
5246
+ sizeBytes: chosen.sizeBytes
5247
+ });
5248
+ return detail;
5249
+ }
5250
+ function grokSessionLocalDay(meta) {
5251
+ if (!meta.firstTimestamp)
5252
+ return void 0;
5253
+ const ms = Date.parse(meta.firstTimestamp);
5254
+ return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
5255
+ }
5256
+ var DEFAULT_GROK_ROOT, IDLE_GAP_MS4, metaCache6, detailCache6;
5257
+ var init_grok = __esm({
5258
+ "../parser/dist/grok.js"() {
5259
+ "use strict";
5260
+ init_analytics();
5261
+ init_git_project();
5262
+ init_user_input();
5263
+ DEFAULT_GROK_ROOT = path6.join(os6.homedir(), ".grok", "sessions");
5264
+ IDLE_GAP_MS4 = 3 * 60 * 1e3;
5265
+ metaCache6 = /* @__PURE__ */ new Map();
5266
+ detailCache6 = /* @__PURE__ */ new Map();
5267
+ }
5268
+ });
5269
+
4472
5270
  // ../parser/dist/team-config.js
4473
5271
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2, renameSync } from "node:fs";
4474
5272
  import { join as join2 } from "node:path";
@@ -4528,6 +5326,7 @@ __export(fs_exports, {
4528
5326
  DEFAULT_CODEX_ROOT: () => DEFAULT_CODEX_ROOT,
4529
5327
  DEFAULT_COWORK_ROOT: () => DEFAULT_COWORK_ROOT,
4530
5328
  DEFAULT_GEMINI_ROOT: () => DEFAULT_GEMINI_ROOT,
5329
+ DEFAULT_GROK_ROOT: () => DEFAULT_GROK_ROOT,
4531
5330
  DEFAULT_ROOT: () => DEFAULT_ROOT,
4532
5331
  RICH_ROLLUP_SCHEMA_VERSION: () => RICH_ROLLUP_SCHEMA_VERSION,
4533
5332
  agentSources: () => agentSources,
@@ -4538,6 +5337,7 @@ __export(fs_exports, {
4538
5337
  cclensHome: () => cclensHome,
4539
5338
  cclensPath: () => cclensPath,
4540
5339
  clearCaches: () => clearCaches,
5340
+ clearGrokCaches: () => clearGrokCaches,
4541
5341
  clearTeamConfig: () => clearTeamConfig,
4542
5342
  codexSessionLocalDay: () => codexSessionLocalDay,
4543
5343
  decodeProjectName: () => decodeProjectName,
@@ -4549,8 +5349,10 @@ __export(fs_exports, {
4549
5349
  getCodexSession: () => getCodexSession,
4550
5350
  getCoworkSession: () => getCoworkSession,
4551
5351
  getGeminiSession: () => getGeminiSession,
5352
+ getGrokSession: () => getGrokSession,
4552
5353
  getLatestCodexUsage: () => getLatestCodexUsage,
4553
5354
  getSession: () => getSession,
5355
+ grokSessionLocalDay: () => grokSessionLocalDay,
4554
5356
  invalidateFile: () => invalidateFile,
4555
5357
  isFleetlensRuntimeDir: () => isFleetlensRuntimeDir,
4556
5358
  listAllSessions: () => listAllSessions,
@@ -4558,6 +5360,7 @@ __export(fs_exports, {
4558
5360
  listCodexSessions: () => listCodexSessions,
4559
5361
  listCoworkSessions: () => listCoworkSessions,
4560
5362
  listGeminiSessions: () => listGeminiSessions,
5363
+ listGrokSessions: () => listGrokSessions,
4561
5364
  listProjects: () => listProjects,
4562
5365
  listSessions: () => listSessions,
4563
5366
  loadCalibrationCurve: () => loadCalibrationCurve,
@@ -4570,20 +5373,21 @@ __export(fs_exports, {
4570
5373
  readGitFolder: () => readGitFolder,
4571
5374
  readJsonlFile: () => readJsonlFile,
4572
5375
  readTeamConfig: () => readTeamConfig,
5376
+ resolveDefaultGrokRoot: () => resolveDefaultGrokRoot,
4573
5377
  resolveProjectIdentity: () => resolveProjectIdentity,
4574
5378
  sessionIdFromFileName: () => sessionIdFromFileName,
4575
5379
  shouldSyncProject: () => shouldSyncProject,
4576
5380
  walkJsonlFiles: () => walkJsonlFiles,
4577
5381
  writeTeamConfig: () => writeTeamConfig
4578
5382
  });
4579
- import { promises as fs6, existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
4580
- import os6 from "node:os";
4581
- import path6 from "node:path";
5383
+ import { promises as fs7, existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
5384
+ import os7 from "node:os";
5385
+ import path7 from "node:path";
4582
5386
  function cclensHome() {
4583
- return process.env.CCLENS_HOME || path6.join(os6.homedir(), ".cclens");
5387
+ return process.env.CCLENS_HOME || path7.join(os7.homedir(), ".cclens");
4584
5388
  }
4585
5389
  function cclensPath(...parts) {
4586
- return path6.join(cclensHome(), ...parts);
5390
+ return path7.join(cclensHome(), ...parts);
4587
5391
  }
4588
5392
  function cacheStats() {
4589
5393
  return claudeCodeCacheStats();
@@ -4594,6 +5398,7 @@ function clearCaches() {
4594
5398
  clearGeminiCaches();
4595
5399
  clearAntigravityCaches();
4596
5400
  clearCoworkCaches();
5401
+ clearGrokCaches();
4597
5402
  }
4598
5403
  function invalidateFile(fullPath) {
4599
5404
  invalidateClaudeCodeFile(fullPath);
@@ -4624,7 +5429,7 @@ function usageLogPath() {
4624
5429
  }
4625
5430
  function appendUsageSnapshot(snapshot) {
4626
5431
  const p = usageLogPath();
4627
- mkdirSync3(path6.dirname(p), { recursive: true });
5432
+ mkdirSync3(path7.dirname(p), { recursive: true });
4628
5433
  appendFileSync(p, JSON.stringify(snapshot) + "\n", "utf8");
4629
5434
  }
4630
5435
  function pruneUsageAgent(agent) {
@@ -4640,13 +5445,13 @@ function pruneUsageAgent(agent) {
4640
5445
  return true;
4641
5446
  }
4642
5447
  });
4643
- mkdirSync3(path6.dirname(p), { recursive: true });
5448
+ mkdirSync3(path7.dirname(p), { recursive: true });
4644
5449
  writeFileSync3(p, kept.join("\n") + (kept.length ? "\n" : ""), "utf8");
4645
5450
  }
4646
5451
  async function loadUsageByDay(start2, end) {
4647
5452
  let raw;
4648
5453
  try {
4649
- raw = await fs6.readFile(usageLogPath(), "utf8");
5454
+ raw = await fs7.readFile(usageLogPath(), "utf8");
4650
5455
  } catch {
4651
5456
  return { by_day: [] };
4652
5457
  }
@@ -4691,7 +5496,7 @@ async function loadUsageByDay(start2, end) {
4691
5496
  async function loadCalibrationSnapshots() {
4692
5497
  let raw;
4693
5498
  try {
4694
- raw = await fs6.readFile(usageLogPath(), "utf8");
5499
+ raw = await fs7.readFile(usageLogPath(), "utf8");
4695
5500
  } catch {
4696
5501
  return [];
4697
5502
  }
@@ -4855,7 +5660,7 @@ async function loadCalibrationCurve(tier = "pro-max-20x", root = DEFAULT_ROOT, g
4855
5660
  ]);
4856
5661
  return buildCalibrationCurve(events, snapshots, tier, granularityMin);
4857
5662
  }
4858
- var codexSource, geminiSource, antigravitySource, coworkSource, agentSources;
5663
+ var codexSource, geminiSource, antigravitySource, coworkSource, grokSource, agentSources;
4859
5664
  var init_fs = __esm({
4860
5665
  "../parser/dist/fs.js"() {
4861
5666
  "use strict";
@@ -4867,12 +5672,14 @@ var init_fs = __esm({
4867
5672
  init_gemini();
4868
5673
  init_antigravity();
4869
5674
  init_cowork();
5675
+ init_grok();
4870
5676
  init_claude_code();
4871
5677
  init_git_project();
4872
5678
  init_codex();
4873
5679
  init_gemini();
4874
5680
  init_antigravity();
4875
5681
  init_cowork();
5682
+ init_grok();
4876
5683
  init_team_config();
4877
5684
  init_team_wire();
4878
5685
  codexSource = {
@@ -4926,12 +5733,24 @@ var init_fs = __esm({
4926
5733
  return getCoworkSession(id);
4927
5734
  }
4928
5735
  };
5736
+ grokSource = {
5737
+ ...GROK_METADATA,
5738
+ // Display default; list/get re-resolve GROK_HOME at call time internally.
5739
+ defaultRoot: DEFAULT_GROK_ROOT,
5740
+ async listSessions(opts) {
5741
+ return listGrokSessions(opts);
5742
+ },
5743
+ async getSession(id, opts) {
5744
+ return getGrokSession(id, opts);
5745
+ }
5746
+ };
4929
5747
  agentSources = [
4930
5748
  claudeCodeSource,
4931
5749
  codexSource,
4932
5750
  geminiSource,
4933
5751
  antigravitySource,
4934
- coworkSource
5752
+ coworkSource,
5753
+ grokSource
4935
5754
  ];
4936
5755
  }
4937
5756
  });
@@ -4967,9 +5786,9 @@ function onDiskVersion() {
4967
5786
  try {
4968
5787
  const here = dirname3(fileURLToPath(import.meta.url));
4969
5788
  const pkg = JSON.parse(readFileSync5(join3(here, "..", "package.json"), "utf8"));
4970
- return pkg.version ?? "0.16.0";
5789
+ return pkg.version ?? "0.16.2";
4971
5790
  } catch {
4972
- return "0.16.0";
5791
+ return "0.16.2";
4973
5792
  }
4974
5793
  }
4975
5794
  function getServerStatus() {
@@ -4981,7 +5800,7 @@ function getServerStatus() {
4981
5800
  return { running: false };
4982
5801
  }
4983
5802
  function isServerStale(status2) {
4984
- return status2.running === true && status2.version !== "0.16.0";
5803
+ return status2.running === true && status2.version !== "0.16.2";
4985
5804
  }
4986
5805
  async function ensureCurrentServer(opts = {}) {
4987
5806
  const status2 = getServerStatus();
@@ -5420,9 +6239,9 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
5420
6239
  console.warn(
5421
6240
  ` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
5422
6241
  );
5423
- } else if (verify.installedVersion !== "0.16.0") {
6242
+ } else if (verify.installedVersion !== "0.16.2") {
5424
6243
  console.log(
5425
- ` \u2192 This process is still running ${"0.16.0"}. Next invocation will use ${verify.installedVersion}.`
6244
+ ` \u2192 This process is still running ${"0.16.2"}. Next invocation will use ${verify.installedVersion}.`
5426
6245
  );
5427
6246
  }
5428
6247
  }
@@ -5457,14 +6276,14 @@ async function getUpdateAvailability() {
5457
6276
  if (isDevMode()) return null;
5458
6277
  const latest = await fetchLatestVersion();
5459
6278
  if (latest === null) return {
5460
- current: "0.16.0",
6279
+ current: "0.16.2",
5461
6280
  latest: null,
5462
6281
  updateAvailable: false
5463
6282
  };
5464
6283
  return {
5465
- current: "0.16.0",
6284
+ current: "0.16.2",
5466
6285
  latest,
5467
- updateAvailable: shouldUpdate("0.16.0", latest)
6286
+ updateAvailable: shouldUpdate("0.16.2", latest)
5468
6287
  };
5469
6288
  }
5470
6289
  async function checkForUpdate() {
@@ -5554,7 +6373,7 @@ async function restartServices(state) {
5554
6373
  }
5555
6374
  async function forceUpdate() {
5556
6375
  const latest = await fetchLatestVersion();
5557
- const current = "0.16.0";
6376
+ const current = "0.16.2";
5558
6377
  if (latest === null) {
5559
6378
  console.error("Could not reach npm registry. Check your network.");
5560
6379
  process.exit(1);
@@ -5967,7 +6786,7 @@ async function status() {
5967
6786
  console.log(`Server: running on ${url} (PID ${server.pid}, v${ver})`);
5968
6787
  if (isServerStale(server)) {
5969
6788
  console.log(
5970
- ` \u26A0 serving stale ${ver} (CLI is ${"0.16.0"}) \u2014 run 'fleetlens start' to restart on the current version`
6789
+ ` \u26A0 serving stale ${ver} (CLI is ${"0.16.2"}) \u2014 run 'fleetlens start' to restart on the current version`
5971
6790
  );
5972
6791
  }
5973
6792
  } else {
@@ -6006,7 +6825,7 @@ async function web(args2) {
6006
6825
  const open = args2.includes("--open");
6007
6826
  const positional = args2.filter((a) => !a.startsWith("--"));
6008
6827
  const rawPath = positional[0] ?? "";
6009
- const path7 = rawPath.startsWith("/") ? rawPath : rawPath ? `/${rawPath}` : "";
6828
+ const path9 = rawPath.startsWith("/") ? rawPath : rawPath ? `/${rawPath}` : "";
6010
6829
  let result;
6011
6830
  try {
6012
6831
  result = await ensureCurrentServer({});
@@ -6014,7 +6833,7 @@ async function web(args2) {
6014
6833
  console.error(`Failed to start: ${err.message}`);
6015
6834
  process.exit(1);
6016
6835
  }
6017
- const url = `http://localhost:${result.port}${path7}`;
6836
+ const url = `http://localhost:${result.port}${path9}`;
6018
6837
  if (result.restarted) {
6019
6838
  console.log(`fleetlens restarted on http://localhost:${result.port} (PID ${result.pid}) \u2014 replaced stale ${result.previousVersion ?? "unknown"} server`);
6020
6839
  }
@@ -6075,9 +6894,9 @@ function readFromCredentialsFile() {
6075
6894
  join7(homedir4(), ".claude", ".credentials.json"),
6076
6895
  join7(homedir4(), ".config", "claude", "credentials.json")
6077
6896
  ];
6078
- for (const path7 of candidates) {
6897
+ for (const path9 of candidates) {
6079
6898
  try {
6080
- const blob = readFileSync10(path7, "utf8");
6899
+ const blob = readFileSync10(path9, "utf8");
6081
6900
  const creds = extractCredentials(blob);
6082
6901
  if (creds) return creds;
6083
6902
  } catch {
@@ -6199,6 +7018,224 @@ var init_api = __esm({
6199
7018
  }
6200
7019
  });
6201
7020
 
7021
+ // src/usage/grok.ts
7022
+ import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
7023
+ import os8 from "node:os";
7024
+ import path8 from "node:path";
7025
+ function grokHome() {
7026
+ return process.env.GROK_HOME || path8.join(os8.homedir(), ".grok");
7027
+ }
7028
+ function authPath() {
7029
+ return path8.join(grokHome(), "auth.json");
7030
+ }
7031
+ function loadAuthEntry() {
7032
+ const p = authPath();
7033
+ if (!existsSync8(p)) {
7034
+ throw new GrokApiError("Grok not logged in. Run `grok login`.", "no_auth");
7035
+ }
7036
+ let raw;
7037
+ try {
7038
+ raw = JSON.parse(readFileSync11(p, "utf8"));
7039
+ } catch {
7040
+ throw new GrokApiError("Grok auth.json is unreadable. Run `grok login`.", "no_auth");
7041
+ }
7042
+ for (const [entryKey2, entry] of Object.entries(raw)) {
7043
+ const token = typeof entry?.key === "string" ? entry.key.trim() : "";
7044
+ if (token) return { token, entry, entryKey: entryKey2 };
7045
+ }
7046
+ throw new GrokApiError("Grok auth has no access token. Run `grok login`.", "no_auth");
7047
+ }
7048
+ function needsRefresh(entry) {
7049
+ const exp = entry.expires_at;
7050
+ if (!exp) return false;
7051
+ const ms = Date.parse(exp);
7052
+ if (!Number.isFinite(ms)) return false;
7053
+ return Date.now() >= ms - REFRESH_BUFFER_MS;
7054
+ }
7055
+ async function refreshAccessToken(entry) {
7056
+ const refresh = entry.refresh_token?.trim();
7057
+ if (!refresh) return null;
7058
+ const clientId = entry.oidc_client_id?.trim() || DEFAULT_CLIENT_ID;
7059
+ const body = new URLSearchParams({
7060
+ grant_type: "refresh_token",
7061
+ client_id: clientId,
7062
+ refresh_token: refresh
7063
+ });
7064
+ let res;
7065
+ try {
7066
+ res = await fetch(REFRESH_URL, {
7067
+ method: "POST",
7068
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
7069
+ body: body.toString()
7070
+ });
7071
+ } catch {
7072
+ return null;
7073
+ }
7074
+ if (!res.ok) return null;
7075
+ try {
7076
+ const j = await res.json();
7077
+ if (typeof j.access_token !== "string" || !j.access_token) return null;
7078
+ try {
7079
+ const p = authPath();
7080
+ const raw = JSON.parse(readFileSync11(p, "utf8"));
7081
+ for (const key of Object.keys(raw)) {
7082
+ if (raw[key]?.key === entry.key || raw[key]?.refresh_token === refresh) {
7083
+ raw[key] = {
7084
+ ...raw[key],
7085
+ key: j.access_token,
7086
+ refresh_token: j.refresh_token ?? raw[key].refresh_token,
7087
+ expires_at: typeof j.expires_in === "number" ? new Date(Date.now() + j.expires_in * 1e3).toISOString() : raw[key].expires_at
7088
+ };
7089
+ break;
7090
+ }
7091
+ }
7092
+ const { writeFileSync: writeFileSync17 } = await import("node:fs");
7093
+ writeFileSync17(p, JSON.stringify(raw, null, 2), "utf8");
7094
+ } catch {
7095
+ }
7096
+ return j.access_token;
7097
+ } catch {
7098
+ return null;
7099
+ }
7100
+ }
7101
+ function authHeaders(token) {
7102
+ return {
7103
+ Authorization: `Bearer ${token.trim()}`,
7104
+ "X-XAI-Token-Auth": TOKEN_AUTH,
7105
+ Accept: "application/json",
7106
+ "User-Agent": "fleetlens"
7107
+ };
7108
+ }
7109
+ function parseGrokCreditsConfig(body) {
7110
+ if (!body || typeof body !== "object") {
7111
+ throw new GrokApiError("Grok billing response missing body", "parse");
7112
+ }
7113
+ const config = body.config;
7114
+ if (!config || typeof config !== "object") {
7115
+ throw new GrokApiError("Grok billing response missing config", "parse");
7116
+ }
7117
+ const period = config.currentPeriod;
7118
+ if (!period || typeof period !== "object") {
7119
+ throw new GrokApiError("Grok billing response missing currentPeriod", "parse");
7120
+ }
7121
+ const periodType = typeof period.type === "string" ? period.type.trim() : "";
7122
+ if (!periodType) {
7123
+ throw new GrokApiError("Grok billing period type missing", "parse");
7124
+ }
7125
+ let utilization = 0;
7126
+ if (config.creditUsagePercent !== void 0 && config.creditUsagePercent !== null) {
7127
+ const n = Number(config.creditUsagePercent);
7128
+ if (!Number.isFinite(n)) {
7129
+ throw new GrokApiError("Grok creditUsagePercent is not a number", "parse");
7130
+ }
7131
+ utilization = Math.min(100, Math.max(0, n));
7132
+ }
7133
+ const end = typeof period.end === "string" && period.end ? new Date(period.end).toISOString() : null;
7134
+ let onDemandCap = 0;
7135
+ const cap = config.onDemandCap;
7136
+ if (cap && typeof cap === "object" && "val" in cap) {
7137
+ const v = Number(cap.val);
7138
+ if (Number.isFinite(v)) onDemandCap = v;
7139
+ }
7140
+ return {
7141
+ utilization,
7142
+ resets_at: end && !Number.isNaN(Date.parse(end)) ? end : null,
7143
+ period_type: periodType,
7144
+ on_demand_cap: onDemandCap
7145
+ };
7146
+ }
7147
+ async function fetchJson(url, token) {
7148
+ let res;
7149
+ try {
7150
+ res = await fetch(url, { headers: authHeaders(token) });
7151
+ } catch (err) {
7152
+ throw new GrokApiError(
7153
+ `Network error reaching Grok billing: ${err.message}`,
7154
+ "network"
7155
+ );
7156
+ }
7157
+ let body = null;
7158
+ try {
7159
+ body = await res.json();
7160
+ } catch {
7161
+ }
7162
+ return { status: res.status, body };
7163
+ }
7164
+ async function fetchGrokUsage() {
7165
+ const loaded = loadAuthEntry();
7166
+ const entry = loaded.entry;
7167
+ let token = loaded.token;
7168
+ if (needsRefresh(entry)) {
7169
+ const refreshed = await refreshAccessToken(entry);
7170
+ if (refreshed) token = refreshed;
7171
+ }
7172
+ let { status: status2, body } = await fetchJson(CREDITS_URL, token);
7173
+ if (status2 === 401 || status2 === 403) {
7174
+ const refreshed = await refreshAccessToken(entry);
7175
+ if (refreshed) {
7176
+ token = refreshed;
7177
+ ({ status: status2, body } = await fetchJson(CREDITS_URL, token));
7178
+ }
7179
+ }
7180
+ if (status2 < 200 || status2 >= 300) {
7181
+ throw new GrokApiError(
7182
+ `Grok billing returned HTTP ${status2}`,
7183
+ status2 === 401 || status2 === 403 ? "no_auth" : "http"
7184
+ );
7185
+ }
7186
+ const credits = parseGrokCreditsConfig(body);
7187
+ if (credits.period_type !== WEEKLY_PERIOD) {
7188
+ throw new GrokApiError(
7189
+ `Grok period is ${credits.period_type}, not weekly`,
7190
+ "not_weekly"
7191
+ );
7192
+ }
7193
+ let planType = null;
7194
+ try {
7195
+ const settings = await fetchJson(SETTINGS_URL, token);
7196
+ if (settings.status >= 200 && settings.status < 300 && settings.body && typeof settings.body === "object") {
7197
+ const tier = settings.body.subscription_tier_display;
7198
+ if (typeof tier === "string" && tier.trim()) planType = tier.trim();
7199
+ }
7200
+ } catch {
7201
+ }
7202
+ return {
7203
+ captured_at: (/* @__PURE__ */ new Date()).toISOString(),
7204
+ agent: "grok",
7205
+ // No 5-hour window — menubar / strip show "—" on the top line.
7206
+ five_hour: { utilization: null, resets_at: null },
7207
+ seven_day: {
7208
+ utilization: credits.utilization,
7209
+ resets_at: credits.resets_at
7210
+ },
7211
+ seven_day_opus: null,
7212
+ seven_day_sonnet: null,
7213
+ seven_day_oauth_apps: null,
7214
+ seven_day_cowork: null,
7215
+ extra_usage: null,
7216
+ plan_type: planType
7217
+ };
7218
+ }
7219
+ var CREDITS_URL, SETTINGS_URL, REFRESH_URL, TOKEN_AUTH, DEFAULT_CLIENT_ID, WEEKLY_PERIOD, REFRESH_BUFFER_MS, GrokApiError;
7220
+ var init_grok2 = __esm({
7221
+ "src/usage/grok.ts"() {
7222
+ "use strict";
7223
+ CREDITS_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
7224
+ SETTINGS_URL = "https://cli-chat-proxy.grok.com/v1/settings";
7225
+ REFRESH_URL = "https://auth.x.ai/oauth2/token";
7226
+ TOKEN_AUTH = "xai-grok-cli";
7227
+ DEFAULT_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
7228
+ WEEKLY_PERIOD = "USAGE_PERIOD_TYPE_WEEKLY";
7229
+ REFRESH_BUFFER_MS = 5 * 60 * 1e3;
7230
+ GrokApiError = class extends Error {
7231
+ constructor(message, code) {
7232
+ super(message);
7233
+ this.code = code;
7234
+ }
7235
+ };
7236
+ }
7237
+ });
7238
+
6202
7239
  // src/usage/format.ts
6203
7240
  function formatUsage(snapshot) {
6204
7241
  const rows = [
@@ -6558,6 +7595,30 @@ Usage:
6558
7595
  const snapshot = await fetchUsage();
6559
7596
  if (save) appendSnapshot(USAGE_LOG2, snapshot);
6560
7597
  process.stdout.write(formatUsage(snapshot));
7598
+ if (save) {
7599
+ for (const source of agentSources) {
7600
+ if (source.kind === "claude-code" || !source.usagePoller) continue;
7601
+ try {
7602
+ const partial = await source.usagePoller();
7603
+ if (!partial) continue;
7604
+ appendSnapshot(USAGE_LOG2, {
7605
+ ...partial,
7606
+ seven_day_opus: null,
7607
+ seven_day_sonnet: null,
7608
+ seven_day_oauth_apps: null,
7609
+ seven_day_cowork: null,
7610
+ extra_usage: null
7611
+ });
7612
+ } catch {
7613
+ }
7614
+ }
7615
+ try {
7616
+ appendSnapshot(USAGE_LOG2, await fetchGrokUsage());
7617
+ } catch (err) {
7618
+ if (!(err instanceof GrokApiError && err.code === "no_auth")) {
7619
+ }
7620
+ }
7621
+ }
6561
7622
  process.stdout.write("\n (tip: run with --history for the daily token/cost table)\n");
6562
7623
  } catch (err) {
6563
7624
  if (err instanceof UsageApiError) {
@@ -6572,6 +7633,7 @@ var init_usage = __esm({
6572
7633
  "src/commands/usage.ts"() {
6573
7634
  "use strict";
6574
7635
  init_api();
7636
+ init_grok2();
6575
7637
  init_format();
6576
7638
  init_storage();
6577
7639
  init_fs();
@@ -7068,6 +8130,7 @@ __export(dist_exports, {
7068
8130
  CODEX_METADATA: () => CODEX_METADATA,
7069
8131
  COWORK_METADATA: () => COWORK_METADATA,
7070
8132
  GEMINI_METADATA: () => GEMINI_METADATA,
8133
+ GROK_METADATA: () => GROK_METADATA,
7071
8134
  PRICES: () => PRICES,
7072
8135
  RATE_PER_PCT: () => RATE_PER_PCT,
7073
8136
  RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
@@ -7481,7 +8544,7 @@ function closeTurn(t, closed, cwd) {
7481
8544
  let active = 0;
7482
8545
  for (let i = 1; i < ts.length; i++) {
7483
8546
  const dt = ts[i] - ts[i - 1];
7484
- if (dt < IDLE_GAP_MS4)
8547
+ if (dt < IDLE_GAP_MS5)
7485
8548
  active += dt;
7486
8549
  }
7487
8550
  closed.push({
@@ -7678,7 +8741,7 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
7678
8741
  let activeMs2 = 0;
7679
8742
  for (let i = 1; i < tsSorted.length; i++) {
7680
8743
  const dt = tsSorted[i] - tsSorted[i - 1];
7681
- if (dt < IDLE_GAP_MS4)
8744
+ if (dt < IDLE_GAP_MS5)
7682
8745
  activeMs2 += dt;
7683
8746
  }
7684
8747
  const tsSortedStrings = dayEvents.map((e) => e.timestamp).filter((t) => !!t).sort();
@@ -7865,7 +8928,7 @@ function buildEntries(sessionDetail) {
7865
8928
  entries2.sort((a, b) => a.local_day.localeCompare(b.local_day));
7866
8929
  return entries2;
7867
8930
  }
7868
- var IDLE_GAP_MS4, INTERRUPT_RE2, PR_TITLE_RE, BASH_CHAIN_SPLIT_RE, SHELL_NOISE, IMAGE_BLOCK_RE;
8931
+ var IDLE_GAP_MS5, INTERRUPT_RE2, PR_TITLE_RE, BASH_CHAIN_SPLIT_RE, SHELL_NOISE, IMAGE_BLOCK_RE;
7869
8932
  var init_build = __esm({
7870
8933
  "../entries/dist/build.js"() {
7871
8934
  "use strict";
@@ -7873,7 +8936,7 @@ var init_build = __esm({
7873
8936
  init_types();
7874
8937
  init_signals();
7875
8938
  init_trivial();
7876
- IDLE_GAP_MS4 = 3 * 60 * 1e3;
8939
+ IDLE_GAP_MS5 = 3 * 60 * 1e3;
7877
8940
  INTERRUPT_RE2 = /\[request interrupted|interrupted by user/i;
7878
8941
  PR_TITLE_RE = /--title\s+["']([^"']+)["']/;
7879
8942
  BASH_CHAIN_SPLIT_RE = /\|\||&&|;|\|/;
@@ -7902,11 +8965,11 @@ var init_dist2 = __esm({
7902
8965
  });
7903
8966
 
7904
8967
  // ../entries/dist/digest-fs.js
7905
- import { readFileSync as readFileSync11, readdirSync, writeFileSync as writeFileSync6, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync6, existsSync as existsSync8 } from "node:fs";
8968
+ import { readFileSync as readFileSync12, readdirSync, writeFileSync as writeFileSync6, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync6, existsSync as existsSync9 } from "node:fs";
7906
8969
  import { dirname as dirname8, join as join8 } from "node:path";
7907
- function parseDigestFile(path7, expectedVersion) {
8970
+ function parseDigestFile(path9, expectedVersion) {
7908
8971
  try {
7909
- const parsed = JSON.parse(readFileSync11(path7, "utf8"));
8972
+ const parsed = JSON.parse(readFileSync12(path9, "utf8"));
7910
8973
  if (!parsed || typeof parsed !== "object")
7911
8974
  return null;
7912
8975
  if (parsed.version !== expectedVersion)
@@ -7925,11 +8988,11 @@ function digestsDir() {
7925
8988
  digestsDirCached = envOverride ?? cclensPath("digests");
7926
8989
  return digestsDirCached;
7927
8990
  }
7928
- function __setDigestsDirForTest(path7) {
7929
- digestsDirCached = path7;
7930
- mkdirSync6(join8(path7, "day"), { recursive: true });
7931
- mkdirSync6(join8(path7, "week"), { recursive: true });
7932
- mkdirSync6(join8(path7, "month"), { recursive: true });
8991
+ function __setDigestsDirForTest(path9) {
8992
+ digestsDirCached = path9;
8993
+ mkdirSync6(join8(path9, "day"), { recursive: true });
8994
+ mkdirSync6(join8(path9, "week"), { recursive: true });
8995
+ mkdirSync6(join8(path9, "month"), { recursive: true });
7933
8996
  }
7934
8997
  function dayDigestPath(date) {
7935
8998
  return join8(digestsDir(), "day", `${date}.json`);
@@ -7955,7 +9018,7 @@ function writeDayDigest(digest2) {
7955
9018
  }
7956
9019
  function readDayDigest(date) {
7957
9020
  const p = dayDigestPath(date);
7958
- if (!existsSync8(p))
9021
+ if (!existsSync9(p))
7959
9022
  return null;
7960
9023
  return parseDigestFile(p, CURRENT_DAY_DIGEST_SCHEMA_VERSION);
7961
9024
  }
@@ -7991,13 +9054,13 @@ function writeWeekDigest(digest2) {
7991
9054
  }
7992
9055
  function readWeekDigest(monday) {
7993
9056
  const p = weekDigestPath(monday);
7994
- if (!existsSync8(p))
9057
+ if (!existsSync9(p))
7995
9058
  return null;
7996
9059
  return parseDigestFile(p, CURRENT_WEEK_DIGEST_SCHEMA_VERSION);
7997
9060
  }
7998
9061
  function listWeekDigestKeys() {
7999
9062
  const dir = join8(digestsDir(), "week");
8000
- if (!existsSync8(dir))
9063
+ if (!existsSync9(dir))
8001
9064
  return [];
8002
9065
  return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}-\d{2}$/.test(k));
8003
9066
  }
@@ -8028,13 +9091,13 @@ function writeMonthDigest(digest2) {
8028
9091
  }
8029
9092
  function readMonthDigest(yearMonth) {
8030
9093
  const p = monthDigestPath(yearMonth);
8031
- if (!existsSync8(p))
9094
+ if (!existsSync9(p))
8032
9095
  return null;
8033
9096
  return parseDigestFile(p, CURRENT_MONTH_DIGEST_SCHEMA_VERSION);
8034
9097
  }
8035
9098
  function listMonthDigestKeys() {
8036
9099
  const dir = join8(digestsDir(), "month");
8037
- if (!existsSync8(dir))
9100
+ if (!existsSync9(dir))
8038
9101
  return [];
8039
9102
  return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}$/.test(k));
8040
9103
  }
@@ -8096,7 +9159,7 @@ __export(fs_exports2, {
8096
9159
  writeMonthDigest: () => writeMonthDigest,
8097
9160
  writeWeekDigest: () => writeWeekDigest
8098
9161
  });
8099
- import { readFileSync as readFileSync12, readdirSync as readdirSync2, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, renameSync as renameSync3, existsSync as existsSync9 } from "node:fs";
9162
+ import { readFileSync as readFileSync13, readdirSync as readdirSync2, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, renameSync as renameSync3, existsSync as existsSync10 } from "node:fs";
8100
9163
  import { randomBytes } from "node:crypto";
8101
9164
  import { join as join9 } from "node:path";
8102
9165
  function entriesDir() {
@@ -8106,9 +9169,9 @@ function entriesDir() {
8106
9169
  entriesDirCached = envOverride ?? cclensPath("entries");
8107
9170
  return entriesDirCached;
8108
9171
  }
8109
- function __setEntriesDirForTest(path7) {
8110
- entriesDirCached = path7;
8111
- mkdirSync7(path7, { recursive: true });
9172
+ function __setEntriesDirForTest(path9) {
9173
+ entriesDirCached = path9;
9174
+ mkdirSync7(path9, { recursive: true });
8112
9175
  }
8113
9176
  function pathFor(sessionId, localDay2) {
8114
9177
  return join9(entriesDir(), `${entryKey(sessionId, localDay2)}.json`);
@@ -8155,17 +9218,17 @@ function writeEntryPreservingEnrichment(fresh) {
8155
9218
  }
8156
9219
  function readEntry(sessionId, localDay2) {
8157
9220
  const p = pathFor(sessionId, localDay2);
8158
- if (!existsSync9(p))
9221
+ if (!existsSync10(p))
8159
9222
  return null;
8160
- const raw = readFileSync12(p, "utf8");
9223
+ const raw = readFileSync13(p, "utf8");
8161
9224
  return JSON.parse(raw);
8162
9225
  }
8163
9226
  function entryExists(sessionId, localDay2) {
8164
- return existsSync9(pathFor(sessionId, localDay2));
9227
+ return existsSync10(pathFor(sessionId, localDay2));
8165
9228
  }
8166
9229
  function listEntryKeys() {
8167
9230
  const dir = entriesDir();
8168
- if (!existsSync9(dir))
9231
+ if (!existsSync10(dir))
8169
9232
  return [];
8170
9233
  return readdirSync2(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
8171
9234
  }
@@ -8647,8 +9710,8 @@ var init_parseUtil = __esm({
8647
9710
  init_errors();
8648
9711
  init_en();
8649
9712
  makeIssue = (params) => {
8650
- const { data, path: path7, errorMaps, issueData } = params;
8651
- const fullPath = [...path7, ...issueData.path || []];
9713
+ const { data, path: path9, errorMaps, issueData } = params;
9714
+ const fullPath = [...path9, ...issueData.path || []];
8652
9715
  const fullIssue = {
8653
9716
  ...issueData,
8654
9717
  path: fullPath
@@ -8956,11 +10019,11 @@ var init_types3 = __esm({
8956
10019
  init_parseUtil();
8957
10020
  init_util();
8958
10021
  ParseInputLazyPath = class {
8959
- constructor(parent, value, path7, key) {
10022
+ constructor(parent, value, path9, key) {
8960
10023
  this._cachedPath = [];
8961
10024
  this.parent = parent;
8962
10025
  this.data = value;
8963
- this._path = path7;
10026
+ this._path = path9;
8964
10027
  this._key = key;
8965
10028
  }
8966
10029
  get path() {
@@ -12444,7 +13507,7 @@ RESPOND WITH ONLY VALID JSON (no prose, no code fence):
12444
13507
  });
12445
13508
 
12446
13509
  // ../entries/dist/tmux-runner.js
12447
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, existsSync as existsSync10, readdirSync as readdirSync3, realpathSync as realpathSync5, readFileSync as readFileSync13, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
13510
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, existsSync as existsSync11, readdirSync as readdirSync3, realpathSync as realpathSync5, readFileSync as readFileSync14, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
12448
13511
  import { join as join10 } from "node:path";
12449
13512
  import { homedir as homedir5 } from "node:os";
12450
13513
  import { spawnSync as spawnSync2 } from "node:child_process";
@@ -12463,7 +13526,7 @@ function tmuxRunnerAvailable() {
12463
13526
  }
12464
13527
  function runtimeCwd() {
12465
13528
  const dir = join10(homedir5(), ".cclens", "runtime");
12466
- if (!existsSync10(dir))
13529
+ if (!existsSync11(dir))
12467
13530
  mkdirSync8(dir, { recursive: true });
12468
13531
  return realpathSync5(dir);
12469
13532
  }
@@ -12471,7 +13534,7 @@ function ensureRuntimeCwdTrusted(cwd) {
12471
13534
  const cfgPath = join10(homedir5(), ".claude.json");
12472
13535
  let cfg;
12473
13536
  try {
12474
- cfg = JSON.parse(readFileSync13(cfgPath, "utf8"));
13537
+ cfg = JSON.parse(readFileSync14(cfgPath, "utf8"));
12475
13538
  } catch {
12476
13539
  return;
12477
13540
  }
@@ -12618,10 +13681,10 @@ function snapshotAllTranscripts() {
12618
13681
  }
12619
13682
  return out;
12620
13683
  }
12621
- function readJsonlCwd(path7, maxLines = 8) {
13684
+ function readJsonlCwd(path9, maxLines = 8) {
12622
13685
  let raw;
12623
13686
  try {
12624
- raw = readFileSync13(path7, "utf8");
13687
+ raw = readFileSync14(path9, "utf8");
12625
13688
  } catch {
12626
13689
  return void 0;
12627
13690
  }
@@ -12675,10 +13738,10 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
12675
13738
  }
12676
13739
  throw new TmuxRunError(`timeout waiting for claude to create the session transcript (cwd: ${targetCwd})`);
12677
13740
  }
12678
- function parseTranscript2(path7, defaultModel) {
13741
+ function parseTranscript2(path9, defaultModel) {
12679
13742
  let raw;
12680
13743
  try {
12681
- raw = readFileSync13(path7, "utf8");
13744
+ raw = readFileSync14(path9, "utf8");
12682
13745
  } catch {
12683
13746
  return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
12684
13747
  }
@@ -12772,11 +13835,11 @@ var init_tmux_runner = __esm({
12772
13835
 
12773
13836
  // ../entries/dist/llm-runner.js
12774
13837
  import { spawn as spawn3 } from "node:child_process";
12775
- import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as existsSync11 } from "node:fs";
13838
+ import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as existsSync12 } from "node:fs";
12776
13839
  import { join as join11 } from "node:path";
12777
13840
  import { randomUUID } from "node:crypto";
12778
13841
  function ensureRunsDir() {
12779
- if (!existsSync11(RUNS_DIR)) {
13842
+ if (!existsSync12(RUNS_DIR)) {
12780
13843
  try {
12781
13844
  mkdirSync9(RUNS_DIR, { recursive: true });
12782
13845
  } catch {
@@ -12807,15 +13870,15 @@ function newRunId(kind) {
12807
13870
  function tracePath(runId) {
12808
13871
  return join11(RUNS_DIR, `${runId}.jsonl`);
12809
13872
  }
12810
- function safeAppend(path7, line) {
13873
+ function safeAppend(path9, line) {
12811
13874
  try {
12812
- appendFileSync3(path7, line);
13875
+ appendFileSync3(path9, line);
12813
13876
  } catch {
12814
13877
  }
12815
13878
  }
12816
- function safeWrite(path7, line) {
13879
+ function safeWrite(path9, line) {
12817
13880
  try {
12818
- writeFileSync9(path7, line);
13881
+ writeFileSync9(path9, line);
12819
13882
  } catch {
12820
13883
  }
12821
13884
  }
@@ -13221,7 +14284,7 @@ var init_enrich2 = __esm({
13221
14284
  });
13222
14285
 
13223
14286
  // ../entries/dist/budget.js
13224
- import { appendFileSync as appendFileSync4, readFileSync as readFileSync14, existsSync as existsSync12, mkdirSync as mkdirSync10 } from "node:fs";
14287
+ import { appendFileSync as appendFileSync4, readFileSync as readFileSync15, existsSync as existsSync13, mkdirSync as mkdirSync10 } from "node:fs";
13225
14288
  import { dirname as dirname9 } from "node:path";
13226
14289
  function spendPath() {
13227
14290
  if (spendPathCached)
@@ -13229,8 +14292,8 @@ function spendPath() {
13229
14292
  spendPathCached = cclensPath("llm-spend.jsonl");
13230
14293
  return spendPathCached;
13231
14294
  }
13232
- function __setSpendPathForTest(path7) {
13233
- spendPathCached = path7;
14295
+ function __setSpendPathForTest(path9) {
14296
+ spendPathCached = path9;
13234
14297
  }
13235
14298
  function appendSpend(record) {
13236
14299
  const p = spendPath();
@@ -13239,12 +14302,12 @@ function appendSpend(record) {
13239
14302
  }
13240
14303
  function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
13241
14304
  const p = spendPath();
13242
- if (!existsSync12(p))
14305
+ if (!existsSync13(p))
13243
14306
  return 0;
13244
14307
  const year = now.getUTCFullYear();
13245
14308
  const month2 = now.getUTCMonth();
13246
14309
  let total = 0;
13247
- const raw = readFileSync14(p, "utf8");
14310
+ const raw = readFileSync15(p, "utf8");
13248
14311
  for (const line of raw.split("\n")) {
13249
14312
  if (!line)
13250
14313
  continue;
@@ -13273,15 +14336,15 @@ var init_budget = __esm({
13273
14336
  });
13274
14337
 
13275
14338
  // ../entries/dist/pipeline-lock.js
13276
- import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync13, readFileSync as readFileSync15, statSync as statSync3 } from "node:fs";
14339
+ import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync14, readFileSync as readFileSync16, statSync as statSync3 } from "node:fs";
13277
14340
  function lockPath() {
13278
14341
  if (lockPathCached)
13279
14342
  return lockPathCached;
13280
14343
  lockPathCached = cclensPath("llm-interactive.lock");
13281
14344
  return lockPathCached;
13282
14345
  }
13283
- function __setInteractiveLockPathForTest(path7) {
13284
- lockPathCached = path7;
14346
+ function __setInteractiveLockPathForTest(path9) {
14347
+ lockPathCached = path9;
13285
14348
  }
13286
14349
  function touchLock() {
13287
14350
  writeFileSync10(lockPath(), String(process.pid), "utf8");
@@ -13318,13 +14381,13 @@ function pidAlive(pid) {
13318
14381
  }
13319
14382
  function interactiveLockFresh(nowMs) {
13320
14383
  const p = lockPath();
13321
- if (!existsSync13(p))
14384
+ if (!existsSync14(p))
13322
14385
  return false;
13323
14386
  try {
13324
14387
  const mtime = statSync3(p).mtimeMs;
13325
14388
  if (nowMs - mtime > STALE_MS)
13326
14389
  return false;
13327
- const pid = Number(readFileSync15(p, "utf8").trim());
14390
+ const pid = Number(readFileSync16(p, "utf8").trim());
13328
14391
  if (!Number.isFinite(pid) || pid <= 0)
13329
14392
  return false;
13330
14393
  if (!pidAlive(pid))
@@ -13430,7 +14493,7 @@ var init_queue = __esm({
13430
14493
  });
13431
14494
 
13432
14495
  // ../entries/dist/settings.js
13433
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync11, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync11, existsSync as existsSync14 } from "node:fs";
14496
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync11, existsSync as existsSync15 } from "node:fs";
13434
14497
  import { dirname as dirname10 } from "node:path";
13435
14498
  function settingsPath() {
13436
14499
  if (settingsPathCached)
@@ -13438,8 +14501,8 @@ function settingsPath() {
13438
14501
  settingsPathCached = cclensPath("settings.json");
13439
14502
  return settingsPathCached;
13440
14503
  }
13441
- function __setSettingsPathForTest(path7) {
13442
- settingsPathCached = path7;
14504
+ function __setSettingsPathForTest(path9) {
14505
+ settingsPathCached = path9;
13443
14506
  }
13444
14507
  function toDisk(s) {
13445
14508
  return {
@@ -13466,10 +14529,10 @@ function fromDisk(d) {
13466
14529
  }
13467
14530
  function readSettings() {
13468
14531
  const p = settingsPath();
13469
- if (!existsSync14(p))
14532
+ if (!existsSync15(p))
13470
14533
  return DEFAULT_SETTINGS;
13471
14534
  try {
13472
- const raw = readFileSync16(p, "utf8");
14535
+ const raw = readFileSync17(p, "utf8");
13473
14536
  return fromDisk(JSON.parse(raw));
13474
14537
  } catch {
13475
14538
  return DEFAULT_SETTINGS;
@@ -13676,7 +14739,7 @@ function rollupOutcomeDay(entries2) {
13676
14739
  return "exploratory";
13677
14740
  return "trivial";
13678
14741
  }
13679
- function truncate5(s, max) {
14742
+ function truncate6(s, max) {
13680
14743
  if (s.length <= max)
13681
14744
  return s;
13682
14745
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -13732,7 +14795,7 @@ function computeDaySignals(entries2) {
13732
14795
  type,
13733
14796
  count: v.count,
13734
14797
  sample_description: v.sample_description,
13735
- sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
14798
+ sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
13736
14799
  }));
13737
14800
  const frameCounts = /* @__PURE__ */ new Map();
13738
14801
  for (const s of signalsList) {
@@ -13751,7 +14814,7 @@ function computeDaySignals(entries2) {
13751
14814
  if ((e.first_user ?? "").length > 0)
13752
14815
  verbosity_distribution[s.verbosity] += 1;
13753
14816
  for (const ref of s.external_refs) {
13754
- external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate5(ref.preview, 200) });
14817
+ external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate6(ref.preview, 200) });
13755
14818
  }
13756
14819
  const ints = e.numbers.interrupts ?? 0;
13757
14820
  interrupts += ints;
@@ -14624,7 +15687,7 @@ function computeInteractionModes(entries2) {
14624
15687
  date: entry.local_day,
14625
15688
  project_display: prettyProject3(entry.project),
14626
15689
  type: sa.type,
14627
- prompt_preview: truncate6(sa.prompt_preview, 200)
15690
+ prompt_preview: truncate7(sa.prompt_preview, 200)
14628
15691
  });
14629
15692
  }
14630
15693
  const skillExamples = [];
@@ -14641,7 +15704,7 @@ function computeInteractionModes(entries2) {
14641
15704
  skillExamples.push({
14642
15705
  date: e.local_day,
14643
15706
  skill,
14644
- first_user_preview: truncate6(e.first_user, 200)
15707
+ first_user_preview: truncate7(e.first_user, 200)
14645
15708
  });
14646
15709
  }
14647
15710
  }
@@ -14658,7 +15721,7 @@ function computeInteractionModes(entries2) {
14658
15721
  project_display: prettyProject3(longestTurnEntry.project),
14659
15722
  active_min: longestTurnEntry.numbers.active_min,
14660
15723
  top_tools: longestTurnEntry.top_tools.slice(0, 5),
14661
- first_user_preview: truncate6(longestTurnEntry.first_user, 200)
15724
+ first_user_preview: truncate7(longestTurnEntry.first_user, 200)
14662
15725
  } : null;
14663
15726
  const tools_per_turn = turn_count > 0 ? tools_total / turn_count : 0;
14664
15727
  const label = tools_per_turn < 5 ? "rapid" : tools_per_turn < 15 ? "mixed" : "batch";
@@ -14689,7 +15752,7 @@ function computeInteractionModes(entries2) {
14689
15752
  }
14690
15753
  };
14691
15754
  }
14692
- function truncate6(s, max) {
15755
+ function truncate7(s, max) {
14693
15756
  if (s.length <= max)
14694
15757
  return s;
14695
15758
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -14736,7 +15799,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
14736
15799
  evidence_subagent = {
14737
15800
  type: sa.type,
14738
15801
  description: sa.description,
14739
- prompt_preview: truncate6(sa.prompt_preview, 200)
15802
+ prompt_preview: truncate7(sa.prompt_preview, 200)
14740
15803
  };
14741
15804
  }
14742
15805
  const project_display = repEntry ? prettyProject3(repEntry.project) : dd.projects[0]?.display_name ?? "";
@@ -14747,7 +15810,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
14747
15810
  outcome: dayOutcome.get(dd.key) ?? null,
14748
15811
  helpfulness: dayHelp.get(dd.key) ?? null,
14749
15812
  evidence_subagent,
14750
- evidence_first_user: repEntry?.first_user ? truncate6(repEntry.first_user, 200) : null,
15813
+ evidence_first_user: repEntry?.first_user ? truncate7(repEntry.first_user, 200) : null,
14751
15814
  day_signature: dd.day_signature ?? null
14752
15815
  };
14753
15816
  });
@@ -14822,7 +15885,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
14822
15885
  date: day2,
14823
15886
  session_id: ref.session_id,
14824
15887
  ref_kind: ref.kind,
14825
- preview: truncate6(ref.preview, 200)
15888
+ preview: truncate7(ref.preview, 200)
14826
15889
  });
14827
15890
  }
14828
15891
  total_interrupts += signals.comm_style.steering.interrupts;
@@ -14894,7 +15957,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
14894
15957
  count: v.count,
14895
15958
  days: [...v.days].sort(),
14896
15959
  sample_description: v.sample_description,
14897
- sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
15960
+ sample_prompt_preview: truncate7(v.sample_prompt_preview, 200)
14898
15961
  })),
14899
15962
  threads,
14900
15963
  communication_style: {
@@ -15542,7 +16605,7 @@ function activeMs(timestamps) {
15542
16605
  let active = 0;
15543
16606
  for (let i = 1; i < ts.length; i++) {
15544
16607
  const dt = ts[i] - ts[i - 1];
15545
- if (dt < IDLE_GAP_MS5)
16608
+ if (dt < IDLE_GAP_MS6)
15546
16609
  active += dt;
15547
16610
  }
15548
16611
  return active;
@@ -15713,7 +16776,7 @@ function buildSessionSlice(entry, events, daySignature) {
15713
16776
  let intEnd = sortedTs[0];
15714
16777
  for (let i = 1; i < sortedTs.length; i++) {
15715
16778
  const dt = sortedTs[i] - intEnd;
15716
- if (dt >= IDLE_GAP_MS5) {
16779
+ if (dt >= IDLE_GAP_MS6) {
15717
16780
  intervals.push({
15718
16781
  start_min: fmtMin(intStart - sliceStartMs),
15719
16782
  end_min: fmtMin(intEnd - sliceStartMs)
@@ -16110,14 +17173,14 @@ async function generateTopSession(slice, opts = {}) {
16110
17173
  void lastModel;
16111
17174
  }
16112
17175
  }
16113
- var IDLE_GAP_MS5, LONG_AUTONOMOUS_MIN, N_USER, N_FIRST_AGENT, N_LAST_AGENT, N_USER_TURN1, N_SUBAGENT, SHELL_NOISE2, INTERRUPT_RE3, PR_TITLE_RE2, PinResponseSchema, TopSessionResponseSchema, SYSTEM_PROMPT5, TOP_SESSION_SYSTEM_PROMPT, DEFAULT_MODEL5, defaultCallLLMTopSession, validateTopSession;
17176
+ var IDLE_GAP_MS6, LONG_AUTONOMOUS_MIN, N_USER, N_FIRST_AGENT, N_LAST_AGENT, N_USER_TURN1, N_SUBAGENT, SHELL_NOISE2, INTERRUPT_RE3, PR_TITLE_RE2, PinResponseSchema, TopSessionResponseSchema, SYSTEM_PROMPT5, TOP_SESSION_SYSTEM_PROMPT, DEFAULT_MODEL5, defaultCallLLMTopSession, validateTopSession;
16114
17177
  var init_top_sessions = __esm({
16115
17178
  "../entries/dist/top-sessions.js"() {
16116
17179
  "use strict";
16117
17180
  init_zod();
16118
17181
  init_signals();
16119
17182
  init_llm_runner();
16120
- IDLE_GAP_MS5 = 3 * 60 * 1e3;
17183
+ IDLE_GAP_MS6 = 3 * 60 * 1e3;
16121
17184
  LONG_AUTONOMOUS_MIN = 20;
16122
17185
  N_USER = 150;
16123
17186
  N_FIRST_AGENT = 150;
@@ -16659,7 +17722,7 @@ var init_digest_month_pipeline = __esm({
16659
17722
  });
16660
17723
 
16661
17724
  // ../entries/dist/credentials.js
16662
- import { writeFileSync as writeFileSync12, readFileSync as readFileSync17, renameSync as renameSync6, chmodSync as chmodSync3, mkdirSync as mkdirSync12, existsSync as existsSync15, unlinkSync as unlinkSync5 } from "node:fs";
17725
+ import { writeFileSync as writeFileSync12, readFileSync as readFileSync18, renameSync as renameSync6, chmodSync as chmodSync3, mkdirSync as mkdirSync12, existsSync as existsSync16, unlinkSync as unlinkSync5 } from "node:fs";
16663
17726
  import { dirname as dirname11 } from "node:path";
16664
17727
  async function fetchZaiUsage(candidate) {
16665
17728
  const key = candidate.trim();
@@ -16730,10 +17793,10 @@ function credentialsPath() {
16730
17793
  }
16731
17794
  function readCredentials() {
16732
17795
  const p = credentialsPath();
16733
- if (!existsSync15(p))
17796
+ if (!existsSync16(p))
16734
17797
  return {};
16735
17798
  try {
16736
- const raw = readFileSync17(p, "utf8");
17799
+ const raw = readFileSync18(p, "utf8");
16737
17800
  return JSON.parse(raw);
16738
17801
  } catch {
16739
17802
  return {};
@@ -17363,7 +18426,7 @@ var menubar_exports = {};
17363
18426
  __export(menubar_exports, {
17364
18427
  menubar: () => menubar
17365
18428
  });
17366
- import { existsSync as existsSync16, mkdirSync as mkdirSync13, cpSync, rmSync as rmSync2, readdirSync as readdirSync4, writeFileSync as writeFileSync13, realpathSync as realpathSync6 } from "node:fs";
18429
+ import { existsSync as existsSync17, mkdirSync as mkdirSync13, cpSync, rmSync as rmSync2, readdirSync as readdirSync4, writeFileSync as writeFileSync13, realpathSync as realpathSync6 } from "node:fs";
17367
18430
  import { homedir as homedir6 } from "node:os";
17368
18431
  import { join as join12, dirname as dirname12 } from "node:path";
17369
18432
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -17405,8 +18468,8 @@ async function isRunning() {
17405
18468
  return false;
17406
18469
  }
17407
18470
  }
17408
- async function launchApp(path7) {
17409
- await execFileAsync2("open", ["-a", path7]);
18471
+ async function launchApp(path9) {
18472
+ await execFileAsync2("open", ["-a", path9]);
17410
18473
  }
17411
18474
  async function quitApp() {
17412
18475
  await execFileAsync2("osascript", ["-e", `tell application "${BUNDLE_EXEC}" to quit`]).catch(
@@ -17427,7 +18490,7 @@ async function installMenubar(opts) {
17427
18490
  return;
17428
18491
  }
17429
18492
  const src = bundledAppPath();
17430
- if (!existsSync16(src)) {
18493
+ if (!existsSync17(src)) {
17431
18494
  console.error(
17432
18495
  `Bundled widget not found at ${src}.
17433
18496
  This install was probably built without the menubar artifact. Run \`node apps/menubar/build-app.sh && cp -R apps/menubar/dist/FleetlensMenubar.app packages/cli/menubar/\` and rebuild.`
@@ -17469,7 +18532,7 @@ async function uninstallMenubar() {
17469
18532
  await new Promise((r) => setTimeout(r, 300));
17470
18533
  }
17471
18534
  const dest = installedAppPath();
17472
- if (existsSync16(dest)) {
18535
+ if (existsSync17(dest)) {
17473
18536
  rmSync2(dest, { recursive: true, force: true });
17474
18537
  console.log(`Removed ${dest}`);
17475
18538
  } else {
@@ -17483,7 +18546,7 @@ async function openMenubar() {
17483
18546
  return;
17484
18547
  }
17485
18548
  const dest = installedAppPath();
17486
- if (!existsSync16(dest)) {
18549
+ if (!existsSync17(dest)) {
17487
18550
  console.log("Widget not installed yet. Run `fleetlens menubar install` first.");
17488
18551
  return;
17489
18552
  }
@@ -17500,9 +18563,9 @@ async function statusMenubar() {
17500
18563
  return;
17501
18564
  }
17502
18565
  const dest = installedAppPath();
17503
- const installed = existsSync16(dest);
18566
+ const installed = existsSync17(dest);
17504
18567
  const running = await isRunning();
17505
- const bundled = existsSync16(bundledAppPath());
18568
+ const bundled = existsSync17(bundledAppPath());
17506
18569
  console.log(`Menu bar widget: ${installed ? "installed" : "not installed"}${installed ? ` (${dest})` : ""}`);
17507
18570
  console.log(`Running: ${running ? "yes" : "no"}`);
17508
18571
  console.log(`Bundled in CLI: ${bundled ? "yes" : "no \u2014 this build ships without the widget"}`);
@@ -17591,7 +18654,7 @@ var init_config = __esm({
17591
18654
  });
17592
18655
 
17593
18656
  // src/perception/build-entries.ts
17594
- import { statSync as statSync4, readFileSync as readFileSync18 } from "node:fs";
18657
+ import { statSync as statSync4, readFileSync as readFileSync19 } from "node:fs";
17595
18658
  import { basename as basename2, dirname as dirname13 } from "node:path";
17596
18659
  function decodeProjectDirName(projectDir) {
17597
18660
  if (projectDir.startsWith("-")) {
@@ -17601,7 +18664,7 @@ function decodeProjectDirName(projectDir) {
17601
18664
  }
17602
18665
  function buildEntriesForFile(filePath) {
17603
18666
  const stat = statSync4(filePath);
17604
- const raw = readFileSync18(filePath, "utf8");
18667
+ const raw = readFileSync19(filePath, "utf8");
17605
18668
  const rawLines = raw.split("\n").filter(Boolean).map((l) => {
17606
18669
  try {
17607
18670
  return JSON.parse(l);
@@ -17866,7 +18929,7 @@ function buildIngestPayload(inputs) {
17866
18929
  return {
17867
18930
  ingestId: randomUUID2(),
17868
18931
  observedAt: (/* @__PURE__ */ new Date()).toISOString(),
17869
- cliVersion: "0.16.0",
18932
+ cliVersion: "0.16.2",
17870
18933
  ...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
17871
18934
  ...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
17872
18935
  ...richRollup ? { richRollup } : {},
@@ -17907,7 +18970,7 @@ var init_push = __esm({
17907
18970
  });
17908
18971
 
17909
18972
  // src/team/git-remote.ts
17910
- import { existsSync as existsSync17, readFileSync as readFileSync19, statSync as statSync5 } from "node:fs";
18973
+ import { existsSync as existsSync18, readFileSync as readFileSync20, statSync as statSync5 } from "node:fs";
17911
18974
  import { dirname as dirname14, isAbsolute as isAbsolute2, join as join13, resolve as resolve2 } from "node:path";
17912
18975
  function parseGithubRemote(url) {
17913
18976
  const m = url.trim().match(GITHUB_URL_RE);
@@ -17932,12 +18995,12 @@ function gitConfigPathFor(dir) {
17932
18995
  const st = statSync5(dotGit, { throwIfNoEntry: false });
17933
18996
  if (!st) return null;
17934
18997
  if (st.isDirectory()) return join13(dotGit, "config");
17935
- const m = readFileSync19(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
18998
+ const m = readFileSync20(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
17936
18999
  if (!m) return null;
17937
19000
  const gd = isAbsolute2(m[1]) ? m[1] : resolve2(dir, m[1]);
17938
19001
  const commondirFile = join13(gd, "commondir");
17939
- if (existsSync17(commondirFile)) {
17940
- const common = readFileSync19(commondirFile, "utf8").trim();
19002
+ if (existsSync18(commondirFile)) {
19003
+ const common = readFileSync20(commondirFile, "utf8").trim();
17941
19004
  return join13(isAbsolute2(common) ? common : resolve2(gd, common), "config");
17942
19005
  }
17943
19006
  return join13(gd, "config");
@@ -17952,8 +19015,8 @@ function createRepoResolver() {
17952
19015
  try {
17953
19016
  for (let d = dir; ; d = dirname14(d)) {
17954
19017
  const config = gitConfigPathFor(d);
17955
- if (config && existsSync17(config)) {
17956
- const url = originUrl2(readFileSync19(config, "utf8"));
19018
+ if (config && existsSync18(config)) {
19019
+ const url = originUrl2(readFileSync20(config, "utf8"));
17957
19020
  repo = url ? parseGithubRemote(url) : null;
17958
19021
  break;
17959
19022
  }
@@ -17975,7 +19038,7 @@ var init_git_remote = __esm({
17975
19038
  });
17976
19039
 
17977
19040
  // src/team/queue.ts
17978
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, appendFileSync as appendFileSync5, statSync as statSync6, mkdirSync as mkdirSync14 } from "node:fs";
19041
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync14, appendFileSync as appendFileSync5, statSync as statSync6, mkdirSync as mkdirSync14 } from "node:fs";
17979
19042
  import { dirname as dirname15 } from "node:path";
17980
19043
  function enqueuePayload(payload, queuePath = QUEUE_PATH) {
17981
19044
  mkdirSync14(dirname15(queuePath), { recursive: true });
@@ -17992,7 +19055,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
17992
19055
  function dequeuePayloads(queuePath = QUEUE_PATH) {
17993
19056
  let lines;
17994
19057
  try {
17995
- lines = readFileSync20(queuePath, "utf8").trim().split("\n").filter(Boolean);
19058
+ lines = readFileSync21(queuePath, "utf8").trim().split("\n").filter(Boolean);
17996
19059
  } catch {
17997
19060
  return [];
17998
19061
  }
@@ -18013,7 +19076,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
18013
19076
  function pruneOldest(queuePath) {
18014
19077
  let lines;
18015
19078
  try {
18016
- lines = readFileSync20(queuePath, "utf8").trim().split("\n").filter(Boolean);
19079
+ lines = readFileSync21(queuePath, "utf8").trim().split("\n").filter(Boolean);
18017
19080
  } catch {
18018
19081
  return;
18019
19082
  }
@@ -18032,7 +19095,7 @@ var init_queue2 = __esm({
18032
19095
  });
18033
19096
 
18034
19097
  // src/usage/profile.ts
18035
- import { existsSync as existsSync18, mkdirSync as mkdirSync15, readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "node:fs";
19098
+ import { existsSync as existsSync19, mkdirSync as mkdirSync15, readFileSync as readFileSync22, writeFileSync as writeFileSync15 } from "node:fs";
18036
19099
  import { dirname as dirname16 } from "node:path";
18037
19100
  function mapRateLimitTier(rateLimitTier) {
18038
19101
  switch (rateLimitTier) {
@@ -18073,9 +19136,9 @@ async function fetchProfile(nowMs = Date.now()) {
18073
19136
  };
18074
19137
  }
18075
19138
  function readCachedProfile(cachePath) {
18076
- if (!existsSync18(cachePath)) return null;
19139
+ if (!existsSync19(cachePath)) return null;
18077
19140
  try {
18078
- const raw = JSON.parse(readFileSync21(cachePath, "utf8"));
19141
+ const raw = JSON.parse(readFileSync22(cachePath, "utf8"));
18079
19142
  if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
18080
19143
  return raw;
18081
19144
  } catch {
@@ -18264,11 +19327,11 @@ var init_backfill = __esm({
18264
19327
  });
18265
19328
 
18266
19329
  // src/team/sync-log.ts
18267
- import { readFileSync as readFileSync22 } from "node:fs";
19330
+ import { readFileSync as readFileSync23 } from "node:fs";
18268
19331
  function readPendingSyncLog(watermark) {
18269
19332
  let raw;
18270
19333
  try {
18271
- raw = readFileSync22(cclensPath("daemon.log"), "utf8");
19334
+ raw = readFileSync23(cclensPath("daemon.log"), "utf8");
18272
19335
  } catch {
18273
19336
  return { lines: [] };
18274
19337
  }
@@ -18332,7 +19395,7 @@ __export(file_probe_exports, {
18332
19395
  probeArtifactSignals: () => probeArtifactSignals
18333
19396
  });
18334
19397
  import { createHash } from "node:crypto";
18335
- import { existsSync as existsSync19, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
19398
+ import { existsSync as existsSync20, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
18336
19399
  import { homedir as homedir7 } from "node:os";
18337
19400
  import { join as join15, relative, resolve as resolve3, sep } from "node:path";
18338
19401
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -18342,15 +19405,15 @@ function pathHash(relPath) {
18342
19405
  function defaultScanRoots(extraRoots = []) {
18343
19406
  const roots = [];
18344
19407
  const home = join15(homedir7(), ".claude");
18345
- if (existsSync19(home)) roots.push({ root: home, label: "user" });
19408
+ if (existsSync20(home)) roots.push({ root: home, label: "user" });
18346
19409
  for (const e of extraRoots) {
18347
19410
  const r = resolve3(e, ".claude");
18348
- if (existsSync19(r) && r !== home) roots.push({ root: r, label: "project" });
19411
+ if (existsSync20(r) && r !== home) roots.push({ root: r, label: "project" });
18349
19412
  }
18350
19413
  return roots;
18351
19414
  }
18352
19415
  function listMarkdownFiles(dir) {
18353
- if (!existsSync19(dir)) return [];
19416
+ if (!existsSync20(dir)) return [];
18354
19417
  const out = [];
18355
19418
  let entries2;
18356
19419
  try {
@@ -18420,7 +19483,7 @@ function scanAuthored(roots, subdir, day2) {
18420
19483
  const out = [];
18421
19484
  for (const r of roots) {
18422
19485
  const dir = join15(r.root, subdir);
18423
- if (!existsSync19(dir)) continue;
19486
+ if (!existsSync20(dir)) continue;
18424
19487
  for (const f of listMarkdownFiles(dir)) {
18425
19488
  const firstSeen = firstSeenDateOf(f);
18426
19489
  if (firstSeen !== day2) continue;
@@ -18434,7 +19497,7 @@ function scanEdited(roots, day2) {
18434
19497
  const out = [];
18435
19498
  for (const r of roots) {
18436
19499
  const dir = join15(r.root, "skills");
18437
- if (!existsSync19(dir)) continue;
19500
+ if (!existsSync20(dir)) continue;
18438
19501
  for (const f of listMarkdownFiles(dir)) {
18439
19502
  const firstSeen = firstSeenDateOf(f);
18440
19503
  if (firstSeen === day2) continue;
@@ -18457,10 +19520,10 @@ function claudemdLineDelta(extraRoots, authorEmail, day2) {
18457
19520
  const candidates = [];
18458
19521
  for (const e of extraRoots) {
18459
19522
  const f = resolve3(e, "CLAUDE.md");
18460
- if (existsSync19(f)) candidates.push(f);
19523
+ if (existsSync20(f)) candidates.push(f);
18461
19524
  }
18462
19525
  const homeClaudeMd = join15(homedir7(), "CLAUDE.md");
18463
- if (existsSync19(homeClaudeMd)) candidates.push(homeClaudeMd);
19526
+ if (existsSync20(homeClaudeMd)) candidates.push(homeClaudeMd);
18464
19527
  for (const file of candidates) {
18465
19528
  try {
18466
19529
  const out = execFileSync3(
@@ -19350,11 +20413,11 @@ var logs_exports = {};
19350
20413
  __export(logs_exports, {
19351
20414
  teamLogs: () => teamLogs
19352
20415
  });
19353
- import { readFileSync as readFileSync23 } from "node:fs";
20416
+ import { readFileSync as readFileSync24 } from "node:fs";
19354
20417
  async function teamLogs() {
19355
20418
  const logPath = cclensPath("daemon.log");
19356
20419
  try {
19357
- const lines = readFileSync23(logPath, "utf8").trim().split("\n");
20420
+ const lines = readFileSync24(logPath, "utf8").trim().split("\n");
19358
20421
  const teamLines = lines.filter((l) => l.includes("[sync] ") || l.includes("team "));
19359
20422
  if (teamLines.length === 0) {
19360
20423
  console.log("No team-related log entries found.");
@@ -19482,7 +20545,7 @@ __export(runs_exports, {
19482
20545
  runs: () => runs
19483
20546
  });
19484
20547
  import { execSync as execSync2 } from "node:child_process";
19485
- import { existsSync as existsSync20, readFileSync as readFileSync24, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
20548
+ import { existsSync as existsSync21, readFileSync as readFileSync25, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
19486
20549
  import { join as join16 } from "node:path";
19487
20550
  async function runs(args2) {
19488
20551
  const json = args2.includes("--json");
@@ -19567,8 +20630,8 @@ function listActiveRuns() {
19567
20630
  return runs2.sort((a, b) => a.elapsed_s - b.elapsed_s);
19568
20631
  }
19569
20632
  function readSpend(sinceMs) {
19570
- if (!existsSync20(SPEND_PATH)) return [];
19571
- const lines = readFileSync24(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
20633
+ if (!existsSync21(SPEND_PATH)) return [];
20634
+ const lines = readFileSync25(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
19572
20635
  const out = [];
19573
20636
  for (const line of lines) {
19574
20637
  try {
@@ -19689,23 +20752,23 @@ function ageLabel(ms) {
19689
20752
  return `${Math.floor(ms / 864e5)}d`;
19690
20753
  }
19691
20754
  function listTraceFiles() {
19692
- if (!existsSync20(RUNS_DIR2)) return [];
20755
+ if (!existsSync21(RUNS_DIR2)) return [];
19693
20756
  const entries2 = readdirSync6(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
19694
20757
  return entries2.map((f) => {
19695
- const path7 = join16(RUNS_DIR2, f);
19696
- const st = statSync8(path7);
19697
- return { runId: f.replace(/\.jsonl$/, ""), path: path7, mtimeMs: st.mtimeMs };
20758
+ const path9 = join16(RUNS_DIR2, f);
20759
+ const st = statSync8(path9);
20760
+ return { runId: f.replace(/\.jsonl$/, ""), path: path9, mtimeMs: st.mtimeMs };
19698
20761
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
19699
20762
  }
19700
20763
  function resolveRunId(arg) {
19701
- if (!existsSync20(RUNS_DIR2)) return null;
20764
+ if (!existsSync21(RUNS_DIR2)) return null;
19702
20765
  if (arg === "latest") {
19703
20766
  const all2 = listTraceFiles();
19704
20767
  if (all2.length === 0) return null;
19705
20768
  return { runId: all2[0].runId, path: all2[0].path };
19706
20769
  }
19707
20770
  const exact = join16(RUNS_DIR2, `${arg}.jsonl`);
19708
- if (existsSync20(exact)) return { runId: arg, path: exact };
20771
+ if (existsSync21(exact)) return { runId: arg, path: exact };
19709
20772
  const all = listTraceFiles();
19710
20773
  const matches = all.filter((r) => r.runId.includes(arg));
19711
20774
  if (matches.length === 1) return { runId: matches[0].runId, path: matches[0].path };
@@ -19716,8 +20779,8 @@ function resolveRunId(arg) {
19716
20779
  }
19717
20780
  return null;
19718
20781
  }
19719
- function readTrace(path7) {
19720
- return readFileSync24(path7, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
20782
+ function readTrace(path9) {
20783
+ return readFileSync25(path9, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
19721
20784
  try {
19722
20785
  return JSON.parse(l);
19723
20786
  } catch {
@@ -19729,7 +20792,7 @@ async function inspect(arg, follow, json) {
19729
20792
  const r = resolveRunId(arg);
19730
20793
  if (!r) {
19731
20794
  console.error(`run not found: ${arg}`);
19732
- if (existsSync20(RUNS_DIR2)) {
20795
+ if (existsSync21(RUNS_DIR2)) {
19733
20796
  const all = listTraceFiles().slice(0, 5);
19734
20797
  if (all.length > 0) {
19735
20798
  console.error(`
@@ -19909,7 +20972,7 @@ async function main() {
19909
20972
  case "version":
19910
20973
  case "--version":
19911
20974
  case "-v":
19912
- console.log(`fleetlens ${"0.16.0"}`);
20975
+ console.log(`fleetlens ${"0.16.2"}`);
19913
20976
  break;
19914
20977
  case "help":
19915
20978
  case "--help":
@@ -19936,7 +20999,7 @@ Advanced:
19936
20999
  start --no-daemon Start only the web server (no daemon)
19937
21000
  daemon <start|stop|status|logs> Manage the usage daemon by itself
19938
21001
  autostart <install|uninstall|status> Run the usage daemon at login (macOS launchd)
19939
- menubar <install|uninstall|open|status> Native macOS menu bar widget (Claude/Codex/Z.ai usage)
21002
+ menubar <install|uninstall|open|status> Native macOS menu bar widget (Claude/Codex/Z.ai plan usage; Grok sessions on the dashboard)
19940
21003
 
19941
21004
  Team:
19942
21005
  team join <url> <token> Pair with a team server (browser setup)