fleetlens 0.15.3 → 0.15.4

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 (155) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +2 -0
  3. package/app/apps/web/.next/build-manifest.json +3 -3
  4. package/app/apps/web/.next/prerender-manifest.json +3 -3
  5. package/app/apps/web/.next/routes-manifest.json +12 -0
  6. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  7. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  8. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/app/apps/web/.next/server/app/_not-found/page.js +1 -1
  14. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  17. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  18. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  20. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  21. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/menubar/route/app-paths-manifest.json +3 -0
  23. package/app/apps/web/.next/server/app/api/menubar/route/build-manifest.json +9 -0
  24. package/app/apps/web/.next/server/app/api/menubar/route/server-reference-manifest.json +4 -0
  25. package/app/apps/web/.next/server/app/api/menubar/route.js +6 -0
  26. package/app/apps/web/.next/server/app/api/menubar/route.js.map +5 -0
  27. package/app/apps/web/.next/server/app/api/menubar/route.js.nft.json +1 -0
  28. package/app/apps/web/.next/server/app/api/menubar/route_client-reference-manifest.js +3 -0
  29. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js +1 -1
  30. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -1
  31. package/app/apps/web/.next/server/app/api/projects/open-folder/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  33. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  34. package/app/apps/web/.next/server/app/api/settings/credentials/route/app-paths-manifest.json +3 -0
  35. package/app/apps/web/.next/server/app/api/settings/credentials/route/build-manifest.json +9 -0
  36. package/app/apps/web/.next/server/app/api/settings/credentials/route/server-reference-manifest.json +4 -0
  37. package/app/apps/web/.next/server/app/api/settings/credentials/route.js +10 -0
  38. package/app/apps/web/.next/server/app/api/settings/credentials/route.js.map +5 -0
  39. package/app/apps/web/.next/server/app/api/settings/credentials/route.js.nft.json +1 -0
  40. package/app/apps/web/.next/server/app/api/settings/credentials/route_client-reference-manifest.js +3 -0
  41. package/app/apps/web/.next/server/app/api/settings/route.js +4 -4
  42. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  43. package/app/apps/web/.next/server/app/changelog/page.js +1 -1
  44. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  45. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  46. package/app/apps/web/.next/server/app/day/[date]/page.js +1 -1
  47. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  48. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  49. package/app/apps/web/.next/server/app/day/page.js +1 -1
  50. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  51. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  52. package/app/apps/web/.next/server/app/digest/[date]/page.js +1 -1
  53. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  54. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  55. package/app/apps/web/.next/server/app/digest/page.js +1 -1
  56. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  57. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  58. package/app/apps/web/.next/server/app/insights/[key]/page.js +1 -1
  59. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  60. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  61. package/app/apps/web/.next/server/app/insights/page.js +1 -1
  62. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  63. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  64. package/app/apps/web/.next/server/app/page.js +1 -1
  65. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  66. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  67. package/app/apps/web/.next/server/app/parallelism/page.js +1 -1
  68. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  69. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  70. package/app/apps/web/.next/server/app/print/[key]/page.js +1 -1
  71. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -1
  72. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
  73. package/app/apps/web/.next/server/app/projects/[slug]/page.js +1 -1
  74. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  75. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  76. package/app/apps/web/.next/server/app/projects/page.js +1 -1
  77. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  78. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  79. package/app/apps/web/.next/server/app/runs/page.js +1 -1
  80. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  81. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  82. package/app/apps/web/.next/server/app/sessions/[id]/page.js +1 -1
  83. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  84. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  85. package/app/apps/web/.next/server/app/sessions/page.js +1 -1
  86. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  87. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  88. package/app/apps/web/.next/server/app/settings/page.js +2 -2
  89. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  90. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  91. package/app/apps/web/.next/server/app/team/onboarding/page.js +1 -1
  92. package/app/apps/web/.next/server/app/team/onboarding/page.js.nft.json +1 -1
  93. package/app/apps/web/.next/server/app/team/onboarding/page_client-reference-manifest.js +1 -1
  94. package/app/apps/web/.next/server/app/team/page.js +1 -1
  95. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  96. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  97. package/app/apps/web/.next/server/app/usage/page.js +1 -1
  98. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  99. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  100. package/app/apps/web/.next/server/app-paths-manifest.json +2 -0
  101. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_settings_credentials_route_actions_04an_i2.js +3 -0
  102. package/app/apps/web/.next/server/chunks/[root-of-the-server]__05z0pcw._.js +3 -0
  103. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0_nle98._.js +3 -0
  104. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0b5r~-1._.js +3 -0
  105. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0a0~7d6._.js → [root-of-the-server]__0t7i-hy._.js} +2 -2
  106. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_menubar_route_actions_0xep8_i.js +3 -0
  107. package/app/apps/web/.next/server/chunks/{node_modules_next_036my~r._.js → node_modules_next_04~_e52._.js} +5 -5
  108. package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +14 -14
  109. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +1 -1
  110. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +1 -1
  111. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0g-tomj._.js +1 -1
  112. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0nr2~y1._.js +3 -0
  113. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +1 -1
  114. package/app/apps/web/.next/server/chunks/ssr/{_0xu2pvc._.js → _0k8yioi._.js} +2 -2
  115. package/app/apps/web/.next/server/chunks/ssr/apps_web_0~aj0~u._.js +3 -0
  116. package/app/apps/web/.next/server/chunks/ssr/{apps_web_components_0txtsv5._.js → apps_web_components_0x014hn._.js} +2 -2
  117. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
  118. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
  119. package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +1 -1
  120. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0mx_509._.js +1 -1
  121. package/app/apps/web/.next/server/functions-config-manifest.json +2 -0
  122. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  123. package/app/apps/web/.next/server/middleware-manifest.json +5 -5
  124. package/app/apps/web/.next/server/pages/500.html +1 -1
  125. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  126. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  127. package/app/apps/web/.next/static/chunks/0-z49mtd-zwgv.js +1 -0
  128. package/app/apps/web/.next/static/chunks/043slkg3juwck.js +1 -0
  129. package/app/apps/web/.next/static/chunks/{0_ujxc0.z66xb.js → 0g0hv.dt-de9g.js} +3 -3
  130. package/app/apps/web/.next/static/chunks/0t2on1dhydyb2.css +1 -0
  131. package/app/apps/web/app/api/menubar/route.ts +66 -0
  132. package/app/apps/web/app/api/settings/credentials/route.ts +45 -0
  133. package/app/apps/web/app/layout.tsx +2 -0
  134. package/app/apps/web/app/settings/page.tsx +26 -0
  135. package/app/apps/web/app/usage/page.tsx +80 -0
  136. package/app/apps/web/components/menubar-install-banner.tsx +117 -0
  137. package/app/apps/web/components/menubar-install.tsx +107 -0
  138. package/app/apps/web/components/zai-credentials-form.tsx +116 -0
  139. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  140. package/app/apps/web/lib/menubar-data.ts +50 -0
  141. package/app/apps/web/lib/usage-data.ts +4 -0
  142. package/app/apps/web/package.json +1 -1
  143. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  144. package/dist/daemon-worker.js +321 -152
  145. package/dist/index.js +597 -173
  146. package/package.json +3 -2
  147. package/app/apps/web/.next/server/chunks/[root-of-the-server]__065lib8._.js +0 -3
  148. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0c00i76._.js +0 -3
  149. package/app/apps/web/.next/server/chunks/ssr/apps_web_0q2x4a~._.js +0 -3
  150. package/app/apps/web/.next/static/chunks/00a9oyw~h5i1p.js +0 -1
  151. package/app/apps/web/.next/static/chunks/040s42ypidk7s.css +0 -1
  152. package/app/apps/web/.next/static/chunks/0bhwd68o~-xc_.js +0 -1
  153. /package/app/apps/web/.next/static/{lIz-6F0SEIL9sgFO3XTJp → nmAGY0LiBgXuibWTKZ1RD}/_buildManifest.js +0 -0
  154. /package/app/apps/web/.next/static/{lIz-6F0SEIL9sgFO3XTJp → nmAGY0LiBgXuibWTKZ1RD}/_clientMiddlewareManifest.js +0 -0
  155. /package/app/apps/web/.next/static/{lIz-6F0SEIL9sgFO3XTJp → nmAGY0LiBgXuibWTKZ1RD}/_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, agentMetadata, KNOWN_AGENT_KINDS;
678
+ var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, ZAI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
679
679
  var init_agent_metadata = __esm({
680
680
  "../parser/dist/agent-metadata.js"() {
681
681
  "use strict";
@@ -714,12 +714,20 @@ var init_agent_metadata = __esm({
714
714
  accentColor: "rgb(217, 119, 87)",
715
715
  iconChar: "\u2318"
716
716
  };
717
+ ZAI_METADATA = {
718
+ kind: "zai",
719
+ displayName: "Z.ai",
720
+ shortLabel: "Z.ai",
721
+ accentColor: "rgb(59, 130, 246)",
722
+ iconChar: "Z"
723
+ };
717
724
  agentMetadata = [
718
725
  CLAUDE_CODE_METADATA,
719
726
  CODEX_METADATA,
720
727
  GEMINI_METADATA,
721
728
  ANTIGRAVITY_METADATA,
722
- COWORK_METADATA
729
+ COWORK_METADATA,
730
+ ZAI_METADATA
723
731
  ];
724
732
  KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
725
733
  }
@@ -3172,13 +3180,16 @@ async function getLatestCodexUsage(opts = {}) {
3172
3180
  const fiveResetUnix = numberOf(primary?.resets_at);
3173
3181
  const sevenResetUnix = numberOf(secondary?.resets_at);
3174
3182
  const planType = typeof rl.plan_type === "string" ? rl.plan_type : null;
3183
+ const nowMs = Date.now();
3184
+ const fiveExpired = fiveResetUnix !== void 0 && nowMs > fiveResetUnix * 1e3;
3185
+ const sevenExpired = sevenResetUnix !== void 0 && nowMs > sevenResetUnix * 1e3;
3175
3186
  return {
3176
3187
  five_hour: {
3177
- utilization: fivePct ?? null,
3188
+ utilization: fiveExpired ? 0 : fivePct ?? null,
3178
3189
  resets_at: fiveResetUnix !== void 0 ? new Date(fiveResetUnix * 1e3).toISOString() : null
3179
3190
  },
3180
3191
  seven_day: {
3181
- utilization: sevenPct ?? null,
3192
+ utilization: sevenExpired ? 0 : sevenPct ?? null,
3182
3193
  resets_at: sevenResetUnix !== void 0 ? new Date(sevenResetUnix * 1e3).toISOString() : null
3183
3194
  },
3184
3195
  plan_type: planType,
@@ -4516,6 +4527,7 @@ __export(fs_exports, {
4516
4527
  RICH_ROLLUP_SCHEMA_VERSION: () => RICH_ROLLUP_SCHEMA_VERSION,
4517
4528
  agentSources: () => agentSources,
4518
4529
  antigravitySessionLocalDay: () => antigravitySessionLocalDay,
4530
+ appendUsageSnapshot: () => appendUsageSnapshot,
4519
4531
  buildCalibrationCurve: () => buildCalibrationCurve,
4520
4532
  cacheStats: () => cacheStats,
4521
4533
  cclensHome: () => cclensHome,
@@ -4549,6 +4561,7 @@ __export(fs_exports, {
4549
4561
  loadTeamForSession: () => loadTeamForSession,
4550
4562
  loadUsageByDay: () => loadUsageByDay,
4551
4563
  loadWorkflowAgentDetail: () => loadWorkflowAgentDetail,
4564
+ pruneUsageAgent: () => pruneUsageAgent,
4552
4565
  readGitFolder: () => readGitFolder,
4553
4566
  readJsonlFile: () => readJsonlFile,
4554
4567
  readTeamConfig: () => readTeamConfig,
@@ -4558,7 +4571,7 @@ __export(fs_exports, {
4558
4571
  walkJsonlFiles: () => walkJsonlFiles,
4559
4572
  writeTeamConfig: () => writeTeamConfig
4560
4573
  });
4561
- import { promises as fs6 } from "node:fs";
4574
+ import { promises as fs6, existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
4562
4575
  import os6 from "node:os";
4563
4576
  import path6 from "node:path";
4564
4577
  function cclensHome() {
@@ -4604,6 +4617,27 @@ async function getAnySession(id) {
4604
4617
  function usageLogPath() {
4605
4618
  return cclensPath("usage.jsonl");
4606
4619
  }
4620
+ function appendUsageSnapshot(snapshot) {
4621
+ const p = usageLogPath();
4622
+ mkdirSync3(path6.dirname(p), { recursive: true });
4623
+ appendFileSync(p, JSON.stringify(snapshot) + "\n", "utf8");
4624
+ }
4625
+ function pruneUsageAgent(agent) {
4626
+ const p = usageLogPath();
4627
+ if (!existsSync2(p))
4628
+ return;
4629
+ const kept = readFileSync4(p, "utf8").split("\n").filter((line) => {
4630
+ if (!line.trim())
4631
+ return false;
4632
+ try {
4633
+ return JSON.parse(line).agent !== agent;
4634
+ } catch {
4635
+ return true;
4636
+ }
4637
+ });
4638
+ mkdirSync3(path6.dirname(p), { recursive: true });
4639
+ writeFileSync3(p, kept.join("\n") + (kept.length ? "\n" : ""), "utf8");
4640
+ }
4607
4641
  async function loadUsageByDay(start2, end) {
4608
4642
  let raw;
4609
4643
  try {
@@ -4909,7 +4943,7 @@ __export(server_exports, {
4909
4943
  import { spawn } from "node:child_process";
4910
4944
  import { join as join3, dirname as dirname3 } from "node:path";
4911
4945
  import { fileURLToPath } from "node:url";
4912
- import { existsSync as existsSync2 } from "node:fs";
4946
+ import { existsSync as existsSync3 } from "node:fs";
4913
4947
  import { homedir as homedir2 } from "node:os";
4914
4948
  function appDir() {
4915
4949
  const here = dirname3(fileURLToPath(import.meta.url));
@@ -4924,7 +4958,7 @@ function getServerStatus() {
4924
4958
  return { running: false };
4925
4959
  }
4926
4960
  function isServerStale(status2) {
4927
- return status2.running === true && status2.version !== "0.15.3";
4961
+ return status2.running === true && status2.version !== "0.15.4";
4928
4962
  }
4929
4963
  async function ensureCurrentServer(opts = {}) {
4930
4964
  const status2 = getServerStatus();
@@ -4958,7 +4992,7 @@ async function ensureCurrentServer(opts = {}) {
4958
4992
  async function startServer(opts = {}) {
4959
4993
  const port = opts.port ?? (parseInt(process.env.CCLENS_PORT ?? "", 10) || DEFAULT_PORT);
4960
4994
  const serverJs = join3(appDir(), "server.js");
4961
- if (!existsSync2(serverJs)) {
4995
+ if (!existsSync3(serverJs)) {
4962
4996
  throw new Error(`Server not found at ${serverJs}. Reinstall with: npm install -g fleetlens`);
4963
4997
  }
4964
4998
  const portInUse = await checkPort(port);
@@ -4980,7 +5014,7 @@ async function startServer(opts = {}) {
4980
5014
  });
4981
5015
  child.unref();
4982
5016
  const pid = child.pid;
4983
- writePid(PID_FILE, pid, port, "0.15.3");
5017
+ writePid(PID_FILE, pid, port, "0.15.4");
4984
5018
  await waitForHealth(`http://localhost:${port}`, 3e4);
4985
5019
  return { pid, port };
4986
5020
  }
@@ -5049,17 +5083,18 @@ __export(storage_exports, {
5049
5083
  appendSnapshot: () => appendSnapshot,
5050
5084
  latestClaudeCodeSnapshot: () => latestClaudeCodeSnapshot,
5051
5085
  latestSnapshot: () => latestSnapshot,
5086
+ pruneAgent: () => pruneAgent,
5052
5087
  readSnapshots: () => readSnapshots
5053
5088
  });
5054
- import { appendFileSync, mkdirSync as mkdirSync3, readFileSync as readFileSync4, existsSync as existsSync3 } from "node:fs";
5089
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "node:fs";
5055
5090
  import { dirname as dirname4 } from "node:path";
5056
5091
  function appendSnapshot(filePath, snapshot) {
5057
- mkdirSync3(dirname4(filePath), { recursive: true });
5058
- appendFileSync(filePath, JSON.stringify(snapshot) + "\n", "utf8");
5092
+ mkdirSync4(dirname4(filePath), { recursive: true });
5093
+ appendFileSync2(filePath, JSON.stringify(snapshot) + "\n", "utf8");
5059
5094
  }
5060
5095
  function readSnapshots(filePath) {
5061
- if (!existsSync3(filePath)) return [];
5062
- const content = readFileSync4(filePath, "utf8");
5096
+ if (!existsSync4(filePath)) return [];
5097
+ const content = readFileSync5(filePath, "utf8");
5063
5098
  const snapshots = [];
5064
5099
  for (const line of content.split("\n")) {
5065
5100
  if (!line.trim()) continue;
@@ -5074,6 +5109,19 @@ function latestSnapshot(filePath) {
5074
5109
  const all = readSnapshots(filePath);
5075
5110
  return all.length > 0 ? all[all.length - 1] : null;
5076
5111
  }
5112
+ function pruneAgent(filePath, agent) {
5113
+ if (!existsSync4(filePath)) return;
5114
+ const kept = readFileSync5(filePath, "utf8").split("\n").filter((line) => {
5115
+ if (!line.trim()) return false;
5116
+ try {
5117
+ return JSON.parse(line).agent !== agent;
5118
+ } catch {
5119
+ return true;
5120
+ }
5121
+ });
5122
+ mkdirSync4(dirname4(filePath), { recursive: true });
5123
+ writeFileSync4(filePath, kept.join("\n") + (kept.length ? "\n" : ""), "utf8");
5124
+ }
5077
5125
  function latestClaudeCodeSnapshot(filePath) {
5078
5126
  const all = readSnapshots(filePath);
5079
5127
  for (let i = all.length - 1; i >= 0; i--) {
@@ -5099,7 +5147,7 @@ __export(daemon_exports, {
5099
5147
  import { spawn as spawn2 } from "node:child_process";
5100
5148
  import { join as join4, dirname as dirname5 } from "node:path";
5101
5149
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5102
- import { existsSync as existsSync4, statSync as statSync2, readFileSync as readFileSync5 } from "node:fs";
5150
+ import { existsSync as existsSync5, statSync as statSync2, readFileSync as readFileSync6 } from "node:fs";
5103
5151
  function startDaemonSilent() {
5104
5152
  cleanStalePid(DAEMON_PID, DAEMON_MARKERS);
5105
5153
  const existing = readPid(DAEMON_PID);
@@ -5107,7 +5155,7 @@ function startDaemonSilent() {
5107
5155
  return { started: false, pid: existing.pid, alreadyRunning: true };
5108
5156
  }
5109
5157
  const script = workerPath();
5110
- if (!existsSync4(script)) {
5158
+ if (!existsSync5(script)) {
5111
5159
  return {
5112
5160
  started: false,
5113
5161
  pid: null,
@@ -5141,7 +5189,7 @@ function getDaemonStatusInfo() {
5141
5189
  const running = entry !== null && isProcessAlive(entry.pid, DAEMON_MARKERS);
5142
5190
  const latest = latestSnapshot(USAGE_LOG);
5143
5191
  const lastSnapshotAgeMs = latest ? Date.now() - new Date(latest.captured_at).getTime() : null;
5144
- const usageLogSize = existsSync4(USAGE_LOG) ? statSync2(USAGE_LOG).size : null;
5192
+ const usageLogSize = existsSync5(USAGE_LOG) ? statSync2(USAGE_LOG).size : null;
5145
5193
  return {
5146
5194
  running,
5147
5195
  pid: running ? entry.pid : null,
@@ -5217,11 +5265,11 @@ function daemonStatus() {
5217
5265
  }
5218
5266
  }
5219
5267
  function daemonLogs() {
5220
- if (!existsSync4(DAEMON_LOG)) {
5268
+ if (!existsSync5(DAEMON_LOG)) {
5221
5269
  console.log("No daemon logs yet.");
5222
5270
  return;
5223
5271
  }
5224
- const content = readFileSync5(DAEMON_LOG, "utf8");
5272
+ const content = readFileSync6(DAEMON_LOG, "utf8");
5225
5273
  const lines = content.trim().split("\n").slice(-20);
5226
5274
  for (const line of lines) process.stdout.write(line + "\n");
5227
5275
  }
@@ -5241,7 +5289,7 @@ var init_daemon = __esm({
5241
5289
 
5242
5290
  // src/updater.ts
5243
5291
  import { execSync, spawnSync } from "node:child_process";
5244
- import { existsSync as existsSync5, readFileSync as readFileSync6, realpathSync as realpathSync2 } from "node:fs";
5292
+ import { existsSync as existsSync6, readFileSync as readFileSync7, realpathSync as realpathSync2 } from "node:fs";
5245
5293
  import { dirname as dirname6, join as join5 } from "node:path";
5246
5294
  function shouldUpdate(local, remote) {
5247
5295
  const l = local.split(".").map(Number);
@@ -5285,7 +5333,7 @@ function verifyInstalledVersion() {
5285
5333
  timeout: 5e3
5286
5334
  }).trim();
5287
5335
  const pkgPath = join5(globalRoot, PACKAGE_NAME, "package.json");
5288
- const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
5336
+ const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
5289
5337
  if (!pkg.version) {
5290
5338
  return { ok: false, reason: `no version field in ${pkgPath}` };
5291
5339
  }
@@ -5349,9 +5397,9 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
5349
5397
  console.warn(
5350
5398
  ` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
5351
5399
  );
5352
- } else if (verify.installedVersion !== "0.15.3") {
5400
+ } else if (verify.installedVersion !== "0.15.4") {
5353
5401
  console.log(
5354
- ` \u2192 This process is still running ${"0.15.3"}. Next invocation will use ${verify.installedVersion}.`
5402
+ ` \u2192 This process is still running ${"0.15.4"}. Next invocation will use ${verify.installedVersion}.`
5355
5403
  );
5356
5404
  }
5357
5405
  }
@@ -5370,7 +5418,7 @@ function reExec() {
5370
5418
  let script = process.argv[1] ?? "";
5371
5419
  if (verify.ok) {
5372
5420
  const candidate = join5(verify.installedPath, "dist", "index.js");
5373
- if (existsSync5(candidate)) script = candidate;
5421
+ if (existsSync6(candidate)) script = candidate;
5374
5422
  }
5375
5423
  const result = spawnSync(process.argv[0], [script, ...process.argv.slice(2)], {
5376
5424
  stdio: "inherit",
@@ -5386,14 +5434,14 @@ async function getUpdateAvailability() {
5386
5434
  if (isDevMode()) return null;
5387
5435
  const latest = await fetchLatestVersion();
5388
5436
  if (latest === null) return {
5389
- current: "0.15.3",
5437
+ current: "0.15.4",
5390
5438
  latest: null,
5391
5439
  updateAvailable: false
5392
5440
  };
5393
5441
  return {
5394
- current: "0.15.3",
5442
+ current: "0.15.4",
5395
5443
  latest,
5396
- updateAvailable: shouldUpdate("0.15.3", latest)
5444
+ updateAvailable: shouldUpdate("0.15.4", latest)
5397
5445
  };
5398
5446
  }
5399
5447
  async function checkForUpdate() {
@@ -5483,7 +5531,7 @@ async function restartServices(state) {
5483
5531
  }
5484
5532
  async function forceUpdate() {
5485
5533
  const latest = await fetchLatestVersion();
5486
- const current = "0.15.3";
5534
+ const current = "0.15.4";
5487
5535
  if (latest === null) {
5488
5536
  console.error("Could not reach npm registry. Check your network.");
5489
5537
  process.exit(1);
@@ -5535,7 +5583,7 @@ __export(autostart_exports, {
5535
5583
  maybePromptAutostart: () => maybePromptAutostart,
5536
5584
  recordOptOut: () => recordOptOut
5537
5585
  });
5538
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync, readFileSync as readFileSync7, realpathSync as realpathSync3 } from "node:fs";
5586
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, rmSync, readFileSync as readFileSync8, realpathSync as realpathSync3 } from "node:fs";
5539
5587
  import { homedir as homedir3 } from "node:os";
5540
5588
  import { join as join6, dirname as dirname7 } from "node:path";
5541
5589
  import { execFile } from "node:child_process";
@@ -5548,14 +5596,14 @@ function isMac() {
5548
5596
  return process.platform === "darwin";
5549
5597
  }
5550
5598
  function isAutostartInstalled() {
5551
- return isMac() && existsSync6(plistPath());
5599
+ return isMac() && existsSync7(plistPath());
5552
5600
  }
5553
5601
  function isStalePlistContent(content) {
5554
5602
  return content.includes("<string>daemon</string>");
5555
5603
  }
5556
5604
  function installedPlistIsStale() {
5557
5605
  try {
5558
- return isStalePlistContent(readFileSync7(plistPath(), "utf8"));
5606
+ return isStalePlistContent(readFileSync8(plistPath(), "utf8"));
5559
5607
  } catch {
5560
5608
  return false;
5561
5609
  }
@@ -5606,8 +5654,8 @@ async function installAutostart() {
5606
5654
  const scriptPath = resolveScriptPath();
5607
5655
  const logPath = cclensPath("daemon-autostart.log");
5608
5656
  const p = plistPath();
5609
- mkdirSync4(dirname7(p), { recursive: true });
5610
- writeFileSync3(p, buildPlist({ nodePath, scriptPath, logPath }), "utf8");
5657
+ mkdirSync5(dirname7(p), { recursive: true });
5658
+ writeFileSync5(p, buildPlist({ nodePath, scriptPath, logPath }), "utf8");
5611
5659
  await runLaunchctl(["unload", p]).catch(() => {
5612
5660
  });
5613
5661
  await runLaunchctl(["load", "-w", p]);
@@ -5627,7 +5675,7 @@ async function uninstallAutostart() {
5627
5675
  }
5628
5676
  const p = plistPath();
5629
5677
  recordOptOut();
5630
- if (!existsSync6(p)) {
5678
+ if (!existsSync7(p)) {
5631
5679
  console.log("Autostart is not installed \u2014 nothing to remove. Noted your opt-out; team join won't enable it.");
5632
5680
  return;
5633
5681
  }
@@ -5660,7 +5708,7 @@ async function statusAutostart() {
5660
5708
  return;
5661
5709
  }
5662
5710
  const p = plistPath();
5663
- const present = existsSync6(p);
5711
+ const present = existsSync7(p);
5664
5712
  let loaded = false;
5665
5713
  try {
5666
5714
  const { stdout } = await execFileAsync("launchctl", ["list"]);
@@ -5675,7 +5723,7 @@ function promptFlagPath() {
5675
5723
  }
5676
5724
  function readFlags() {
5677
5725
  try {
5678
- return JSON.parse(readFileSync7(promptFlagPath(), "utf8"));
5726
+ return JSON.parse(readFileSync8(promptFlagPath(), "utf8"));
5679
5727
  } catch {
5680
5728
  return {};
5681
5729
  }
@@ -5683,8 +5731,8 @@ function readFlags() {
5683
5731
  function writeFlags(patch) {
5684
5732
  const p = promptFlagPath();
5685
5733
  try {
5686
- mkdirSync4(dirname7(p), { recursive: true });
5687
- writeFileSync3(p, JSON.stringify({ ...readFlags(), ...patch }, null, 2), "utf8");
5734
+ mkdirSync5(dirname7(p), { recursive: true });
5735
+ writeFileSync5(p, JSON.stringify({ ...readFlags(), ...patch }, null, 2), "utf8");
5688
5736
  } catch {
5689
5737
  }
5690
5738
  }
@@ -5896,7 +5944,7 @@ async function status() {
5896
5944
  console.log(`Server: running on ${url} (PID ${server.pid}, v${ver})`);
5897
5945
  if (isServerStale(server)) {
5898
5946
  console.log(
5899
- ` \u26A0 serving stale ${ver} (CLI is ${"0.15.3"}) \u2014 run 'fleetlens start' to restart on the current version`
5947
+ ` \u26A0 serving stale ${ver} (CLI is ${"0.15.4"}) \u2014 run 'fleetlens start' to restart on the current version`
5900
5948
  );
5901
5949
  }
5902
5950
  } else {
@@ -5978,7 +6026,7 @@ var init_update = __esm({
5978
6026
 
5979
6027
  // src/usage/token.ts
5980
6028
  import { execFileSync as execFileSync2 } from "node:child_process";
5981
- import { readFileSync as readFileSync8 } from "node:fs";
6029
+ import { readFileSync as readFileSync9 } from "node:fs";
5982
6030
  import { homedir as homedir4, platform } from "node:os";
5983
6031
  import { join as join7 } from "node:path";
5984
6032
  function readOAuthCredentials() {
@@ -6006,7 +6054,7 @@ function readFromCredentialsFile() {
6006
6054
  ];
6007
6055
  for (const path7 of candidates) {
6008
6056
  try {
6009
- const blob = readFileSync8(path7, "utf8");
6057
+ const blob = readFileSync9(path7, "utf8");
6010
6058
  const creds = extractCredentials(blob);
6011
6059
  if (creds) return creds;
6012
6060
  } catch {
@@ -7001,6 +7049,7 @@ __export(dist_exports, {
7001
7049
  RATE_PER_PCT: () => RATE_PER_PCT,
7002
7050
  RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
7003
7051
  RATE_PER_PCT_7D: () => RATE_PER_PCT_7D,
7052
+ ZAI_METADATA: () => ZAI_METADATA,
7004
7053
  agentMetadata: () => agentMetadata,
7005
7054
  aggregateConcurrency: () => aggregateConcurrency,
7006
7055
  buildGanttDay: () => buildGanttDay,
@@ -7830,11 +7879,11 @@ var init_dist2 = __esm({
7830
7879
  });
7831
7880
 
7832
7881
  // ../entries/dist/digest-fs.js
7833
- import { readFileSync as readFileSync9, readdirSync, writeFileSync as writeFileSync4, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "node:fs";
7882
+ import { readFileSync as readFileSync10, readdirSync, writeFileSync as writeFileSync6, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync6, existsSync as existsSync8 } from "node:fs";
7834
7883
  import { dirname as dirname8, join as join8 } from "node:path";
7835
7884
  function parseDigestFile(path7, expectedVersion) {
7836
7885
  try {
7837
- const parsed = JSON.parse(readFileSync9(path7, "utf8"));
7886
+ const parsed = JSON.parse(readFileSync10(path7, "utf8"));
7838
7887
  if (!parsed || typeof parsed !== "object")
7839
7888
  return null;
7840
7889
  if (parsed.version !== expectedVersion)
@@ -7855,9 +7904,9 @@ function digestsDir() {
7855
7904
  }
7856
7905
  function __setDigestsDirForTest(path7) {
7857
7906
  digestsDirCached = path7;
7858
- mkdirSync5(join8(path7, "day"), { recursive: true });
7859
- mkdirSync5(join8(path7, "week"), { recursive: true });
7860
- mkdirSync5(join8(path7, "month"), { recursive: true });
7907
+ mkdirSync6(join8(path7, "day"), { recursive: true });
7908
+ mkdirSync6(join8(path7, "week"), { recursive: true });
7909
+ mkdirSync6(join8(path7, "month"), { recursive: true });
7861
7910
  }
7862
7911
  function dayDigestPath(date) {
7863
7912
  return join8(digestsDir(), "day", `${date}.json`);
@@ -7870,9 +7919,9 @@ function monthDigestPath(yearMonth) {
7870
7919
  }
7871
7920
  function writeDayDigest(digest2) {
7872
7921
  const final = dayDigestPath(digest2.key);
7873
- mkdirSync5(dirname8(final), { recursive: true });
7922
+ mkdirSync6(dirname8(final), { recursive: true });
7874
7923
  const tmp = `${final}.tmp`;
7875
- writeFileSync4(tmp, JSON.stringify(digest2, null, 2), "utf8");
7924
+ writeFileSync6(tmp, JSON.stringify(digest2, null, 2), "utf8");
7876
7925
  if (process.platform !== "win32") {
7877
7926
  try {
7878
7927
  chmodSync(tmp, 384);
@@ -7883,7 +7932,7 @@ function writeDayDigest(digest2) {
7883
7932
  }
7884
7933
  function readDayDigest(date) {
7885
7934
  const p = dayDigestPath(date);
7886
- if (!existsSync7(p))
7935
+ if (!existsSync8(p))
7887
7936
  return null;
7888
7937
  return parseDigestFile(p, CURRENT_DAY_DIGEST_SCHEMA_VERSION);
7889
7938
  }
@@ -7906,9 +7955,9 @@ function __clearTodayCacheForTest() {
7906
7955
  }
7907
7956
  function writeWeekDigest(digest2) {
7908
7957
  const final = weekDigestPath(digest2.key);
7909
- mkdirSync5(dirname8(final), { recursive: true });
7958
+ mkdirSync6(dirname8(final), { recursive: true });
7910
7959
  const tmp = `${final}.tmp`;
7911
- writeFileSync4(tmp, JSON.stringify(digest2, null, 2), "utf8");
7960
+ writeFileSync6(tmp, JSON.stringify(digest2, null, 2), "utf8");
7912
7961
  if (process.platform !== "win32") {
7913
7962
  try {
7914
7963
  chmodSync(tmp, 384);
@@ -7919,13 +7968,13 @@ function writeWeekDigest(digest2) {
7919
7968
  }
7920
7969
  function readWeekDigest(monday) {
7921
7970
  const p = weekDigestPath(monday);
7922
- if (!existsSync7(p))
7971
+ if (!existsSync8(p))
7923
7972
  return null;
7924
7973
  return parseDigestFile(p, CURRENT_WEEK_DIGEST_SCHEMA_VERSION);
7925
7974
  }
7926
7975
  function listWeekDigestKeys() {
7927
7976
  const dir = join8(digestsDir(), "week");
7928
- if (!existsSync7(dir))
7977
+ if (!existsSync8(dir))
7929
7978
  return [];
7930
7979
  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));
7931
7980
  }
@@ -7943,9 +7992,9 @@ function setCurrentWeekDigestInCache(monday, digest2, nowMs) {
7943
7992
  }
7944
7993
  function writeMonthDigest(digest2) {
7945
7994
  const final = monthDigestPath(digest2.key);
7946
- mkdirSync5(dirname8(final), { recursive: true });
7995
+ mkdirSync6(dirname8(final), { recursive: true });
7947
7996
  const tmp = `${final}.tmp`;
7948
- writeFileSync4(tmp, JSON.stringify(digest2, null, 2), "utf8");
7997
+ writeFileSync6(tmp, JSON.stringify(digest2, null, 2), "utf8");
7949
7998
  if (process.platform !== "win32") {
7950
7999
  try {
7951
8000
  chmodSync(tmp, 384);
@@ -7956,13 +8005,13 @@ function writeMonthDigest(digest2) {
7956
8005
  }
7957
8006
  function readMonthDigest(yearMonth) {
7958
8007
  const p = monthDigestPath(yearMonth);
7959
- if (!existsSync7(p))
8008
+ if (!existsSync8(p))
7960
8009
  return null;
7961
8010
  return parseDigestFile(p, CURRENT_MONTH_DIGEST_SCHEMA_VERSION);
7962
8011
  }
7963
8012
  function listMonthDigestKeys() {
7964
8013
  const dir = join8(digestsDir(), "month");
7965
- if (!existsSync7(dir))
8014
+ if (!existsSync8(dir))
7966
8015
  return [];
7967
8016
  return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}$/.test(k));
7968
8017
  }
@@ -8024,7 +8073,7 @@ __export(fs_exports2, {
8024
8073
  writeMonthDigest: () => writeMonthDigest,
8025
8074
  writeWeekDigest: () => writeWeekDigest
8026
8075
  });
8027
- import { readFileSync as readFileSync10, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, renameSync as renameSync3, existsSync as existsSync8 } from "node:fs";
8076
+ import { readFileSync as readFileSync11, readdirSync as readdirSync2, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, renameSync as renameSync3, existsSync as existsSync9 } from "node:fs";
8028
8077
  import { randomBytes } from "node:crypto";
8029
8078
  import { join as join9 } from "node:path";
8030
8079
  function entriesDir() {
@@ -8036,7 +8085,7 @@ function entriesDir() {
8036
8085
  }
8037
8086
  function __setEntriesDirForTest(path7) {
8038
8087
  entriesDirCached = path7;
8039
- mkdirSync6(path7, { recursive: true });
8088
+ mkdirSync7(path7, { recursive: true });
8040
8089
  }
8041
8090
  function pathFor(sessionId, localDay2) {
8042
8091
  return join9(entriesDir(), `${entryKey(sessionId, localDay2)}.json`);
@@ -8046,11 +8095,11 @@ function tmpPathFor(final) {
8046
8095
  }
8047
8096
  function writeEntry(entry) {
8048
8097
  const dir = entriesDir();
8049
- mkdirSync6(dir, { recursive: true });
8098
+ mkdirSync7(dir, { recursive: true });
8050
8099
  const final = pathFor(entry.session_id, entry.local_day);
8051
8100
  const tmp = tmpPathFor(final);
8052
8101
  const json = JSON.stringify(entry, null, 2);
8053
- writeFileSync5(tmp, json, { encoding: "utf8" });
8102
+ writeFileSync7(tmp, json, { encoding: "utf8" });
8054
8103
  renameSync3(tmp, final);
8055
8104
  }
8056
8105
  function enrichmentInputHash(e) {
@@ -8070,7 +8119,7 @@ function enrichmentInputHash(e) {
8070
8119
  }
8071
8120
  function writeEntryPreservingEnrichment(fresh) {
8072
8121
  const dir = entriesDir();
8073
- mkdirSync6(dir, { recursive: true });
8122
+ mkdirSync7(dir, { recursive: true });
8074
8123
  const final = pathFor(fresh.session_id, fresh.local_day);
8075
8124
  const existing = readEntry(fresh.session_id, fresh.local_day);
8076
8125
  let toWrite = fresh;
@@ -8078,22 +8127,22 @@ function writeEntryPreservingEnrichment(fresh) {
8078
8127
  toWrite = { ...fresh, enrichment: existing.enrichment };
8079
8128
  }
8080
8129
  const tmp = tmpPathFor(final);
8081
- writeFileSync5(tmp, JSON.stringify(toWrite, null, 2), { encoding: "utf8" });
8130
+ writeFileSync7(tmp, JSON.stringify(toWrite, null, 2), { encoding: "utf8" });
8082
8131
  renameSync3(tmp, final);
8083
8132
  }
8084
8133
  function readEntry(sessionId, localDay2) {
8085
8134
  const p = pathFor(sessionId, localDay2);
8086
- if (!existsSync8(p))
8135
+ if (!existsSync9(p))
8087
8136
  return null;
8088
- const raw = readFileSync10(p, "utf8");
8137
+ const raw = readFileSync11(p, "utf8");
8089
8138
  return JSON.parse(raw);
8090
8139
  }
8091
8140
  function entryExists(sessionId, localDay2) {
8092
- return existsSync8(pathFor(sessionId, localDay2));
8141
+ return existsSync9(pathFor(sessionId, localDay2));
8093
8142
  }
8094
8143
  function listEntryKeys() {
8095
8144
  const dir = entriesDir();
8096
- if (!existsSync8(dir))
8145
+ if (!existsSync9(dir))
8097
8146
  return [];
8098
8147
  return readdirSync2(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
8099
8148
  }
@@ -12372,7 +12421,7 @@ RESPOND WITH ONLY VALID JSON (no prose, no code fence):
12372
12421
  });
12373
12422
 
12374
12423
  // ../entries/dist/tmux-runner.js
12375
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6, existsSync as existsSync9, readdirSync as readdirSync3, realpathSync as realpathSync4, readFileSync as readFileSync11, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
12424
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, existsSync as existsSync10, readdirSync as readdirSync3, realpathSync as realpathSync4, readFileSync as readFileSync12, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
12376
12425
  import { join as join10 } from "node:path";
12377
12426
  import { homedir as homedir5 } from "node:os";
12378
12427
  import { spawnSync as spawnSync2 } from "node:child_process";
@@ -12391,15 +12440,15 @@ function tmuxRunnerAvailable() {
12391
12440
  }
12392
12441
  function runtimeCwd() {
12393
12442
  const dir = join10(homedir5(), ".cclens", "runtime");
12394
- if (!existsSync9(dir))
12395
- mkdirSync7(dir, { recursive: true });
12443
+ if (!existsSync10(dir))
12444
+ mkdirSync8(dir, { recursive: true });
12396
12445
  return realpathSync4(dir);
12397
12446
  }
12398
12447
  function ensureRuntimeCwdTrusted(cwd) {
12399
12448
  const cfgPath = join10(homedir5(), ".claude.json");
12400
12449
  let cfg;
12401
12450
  try {
12402
- cfg = JSON.parse(readFileSync11(cfgPath, "utf8"));
12451
+ cfg = JSON.parse(readFileSync12(cfgPath, "utf8"));
12403
12452
  } catch {
12404
12453
  return;
12405
12454
  }
@@ -12414,7 +12463,7 @@ function ensureRuntimeCwdTrusted(cwd) {
12414
12463
  cfg.projects = projects;
12415
12464
  const tmp = `${cfgPath}.cclens-tmp-${process.pid}`;
12416
12465
  try {
12417
- writeFileSync6(tmp, JSON.stringify(cfg, null, 2));
12466
+ writeFileSync8(tmp, JSON.stringify(cfg, null, 2));
12418
12467
  renameSync4(tmp, cfgPath);
12419
12468
  } catch {
12420
12469
  try {
@@ -12444,13 +12493,13 @@ async function runClaudeUnderTmuxImpl(args2) {
12444
12493
  const systemFile = join10(cwd, `system-${runId}.txt`);
12445
12494
  const userFile = join10(cwd, `user-${runId}.txt`);
12446
12495
  const wrapper = join10(cwd, `run-${runId}.sh`);
12447
- writeFileSync6(systemFile, args2.systemPrompt);
12448
- writeFileSync6(userFile, args2.reminder ? `${args2.userPrompt}
12496
+ writeFileSync8(systemFile, args2.systemPrompt);
12497
+ writeFileSync8(userFile, args2.reminder ? `${args2.userPrompt}
12449
12498
 
12450
12499
  ---
12451
12500
 
12452
12501
  ${args2.reminder}` : args2.userPrompt);
12453
- writeFileSync6(wrapper, `#!/bin/bash
12502
+ writeFileSync8(wrapper, `#!/bin/bash
12454
12503
  SYS="$(cat ${shellEscape(systemFile)})"
12455
12504
  USR="$(cat ${shellEscape(userFile)})"
12456
12505
  exec ${shellEscape(claudeBin)} \\
@@ -12549,7 +12598,7 @@ function snapshotAllTranscripts() {
12549
12598
  function readJsonlCwd(path7, maxLines = 8) {
12550
12599
  let raw;
12551
12600
  try {
12552
- raw = readFileSync11(path7, "utf8");
12601
+ raw = readFileSync12(path7, "utf8");
12553
12602
  } catch {
12554
12603
  return void 0;
12555
12604
  }
@@ -12606,7 +12655,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
12606
12655
  function parseTranscript2(path7, defaultModel) {
12607
12656
  let raw;
12608
12657
  try {
12609
- raw = readFileSync11(path7, "utf8");
12658
+ raw = readFileSync12(path7, "utf8");
12610
12659
  } catch {
12611
12660
  return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
12612
12661
  }
@@ -12700,13 +12749,13 @@ var init_tmux_runner = __esm({
12700
12749
 
12701
12750
  // ../entries/dist/llm-runner.js
12702
12751
  import { spawn as spawn3 } from "node:child_process";
12703
- import { mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "node:fs";
12752
+ import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as existsSync11 } from "node:fs";
12704
12753
  import { join as join11 } from "node:path";
12705
12754
  import { randomUUID } from "node:crypto";
12706
12755
  function ensureRunsDir() {
12707
- if (!existsSync10(RUNS_DIR)) {
12756
+ if (!existsSync11(RUNS_DIR)) {
12708
12757
  try {
12709
- mkdirSync8(RUNS_DIR, { recursive: true });
12758
+ mkdirSync9(RUNS_DIR, { recursive: true });
12710
12759
  } catch {
12711
12760
  }
12712
12761
  }
@@ -12737,13 +12786,13 @@ function tracePath(runId) {
12737
12786
  }
12738
12787
  function safeAppend(path7, line) {
12739
12788
  try {
12740
- appendFileSync2(path7, line);
12789
+ appendFileSync3(path7, line);
12741
12790
  } catch {
12742
12791
  }
12743
12792
  }
12744
12793
  function safeWrite(path7, line) {
12745
12794
  try {
12746
- writeFileSync7(path7, line);
12795
+ writeFileSync9(path7, line);
12747
12796
  } catch {
12748
12797
  }
12749
12798
  }
@@ -13149,7 +13198,7 @@ var init_enrich2 = __esm({
13149
13198
  });
13150
13199
 
13151
13200
  // ../entries/dist/budget.js
13152
- import { appendFileSync as appendFileSync3, readFileSync as readFileSync12, existsSync as existsSync11, mkdirSync as mkdirSync9 } from "node:fs";
13201
+ import { appendFileSync as appendFileSync4, readFileSync as readFileSync13, existsSync as existsSync12, mkdirSync as mkdirSync10 } from "node:fs";
13153
13202
  import { dirname as dirname9 } from "node:path";
13154
13203
  function spendPath() {
13155
13204
  if (spendPathCached)
@@ -13162,17 +13211,17 @@ function __setSpendPathForTest(path7) {
13162
13211
  }
13163
13212
  function appendSpend(record) {
13164
13213
  const p = spendPath();
13165
- mkdirSync9(dirname9(p), { recursive: true });
13166
- appendFileSync3(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
13214
+ mkdirSync10(dirname9(p), { recursive: true });
13215
+ appendFileSync4(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
13167
13216
  }
13168
13217
  function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
13169
13218
  const p = spendPath();
13170
- if (!existsSync11(p))
13219
+ if (!existsSync12(p))
13171
13220
  return 0;
13172
13221
  const year = now.getUTCFullYear();
13173
13222
  const month2 = now.getUTCMonth();
13174
13223
  let total = 0;
13175
- const raw = readFileSync12(p, "utf8");
13224
+ const raw = readFileSync13(p, "utf8");
13176
13225
  for (const line of raw.split("\n")) {
13177
13226
  if (!line)
13178
13227
  continue;
@@ -13201,7 +13250,7 @@ var init_budget = __esm({
13201
13250
  });
13202
13251
 
13203
13252
  // ../entries/dist/pipeline-lock.js
13204
- import { writeFileSync as writeFileSync8, unlinkSync as unlinkSync4, existsSync as existsSync12, readFileSync as readFileSync13, statSync as statSync3 } from "node:fs";
13253
+ import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync13, readFileSync as readFileSync14, statSync as statSync3 } from "node:fs";
13205
13254
  function lockPath() {
13206
13255
  if (lockPathCached)
13207
13256
  return lockPathCached;
@@ -13212,7 +13261,7 @@ function __setInteractiveLockPathForTest(path7) {
13212
13261
  lockPathCached = path7;
13213
13262
  }
13214
13263
  function touchLock() {
13215
- writeFileSync8(lockPath(), String(process.pid), "utf8");
13264
+ writeFileSync10(lockPath(), String(process.pid), "utf8");
13216
13265
  }
13217
13266
  function writeInteractiveLock() {
13218
13267
  touchLock();
@@ -13246,13 +13295,13 @@ function pidAlive(pid) {
13246
13295
  }
13247
13296
  function interactiveLockFresh(nowMs) {
13248
13297
  const p = lockPath();
13249
- if (!existsSync12(p))
13298
+ if (!existsSync13(p))
13250
13299
  return false;
13251
13300
  try {
13252
13301
  const mtime = statSync3(p).mtimeMs;
13253
13302
  if (nowMs - mtime > STALE_MS)
13254
13303
  return false;
13255
- const pid = Number(readFileSync13(p, "utf8").trim());
13304
+ const pid = Number(readFileSync14(p, "utf8").trim());
13256
13305
  if (!Number.isFinite(pid) || pid <= 0)
13257
13306
  return false;
13258
13307
  if (!pidAlive(pid))
@@ -13358,7 +13407,7 @@ var init_queue = __esm({
13358
13407
  });
13359
13408
 
13360
13409
  // ../entries/dist/settings.js
13361
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync10, existsSync as existsSync13 } from "node:fs";
13410
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync11, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync11, existsSync as existsSync14 } from "node:fs";
13362
13411
  import { dirname as dirname10 } from "node:path";
13363
13412
  function settingsPath() {
13364
13413
  if (settingsPathCached)
@@ -13394,10 +13443,10 @@ function fromDisk(d) {
13394
13443
  }
13395
13444
  function readSettings() {
13396
13445
  const p = settingsPath();
13397
- if (!existsSync13(p))
13446
+ if (!existsSync14(p))
13398
13447
  return DEFAULT_SETTINGS;
13399
13448
  try {
13400
- const raw = readFileSync14(p, "utf8");
13449
+ const raw = readFileSync15(p, "utf8");
13401
13450
  return fromDisk(JSON.parse(raw));
13402
13451
  } catch {
13403
13452
  return DEFAULT_SETTINGS;
@@ -13405,9 +13454,9 @@ function readSettings() {
13405
13454
  }
13406
13455
  function writeSettings(s) {
13407
13456
  const p = settingsPath();
13408
- mkdirSync10(dirname10(p), { recursive: true });
13457
+ mkdirSync11(dirname10(p), { recursive: true });
13409
13458
  const tmp = `${p}.tmp`;
13410
- writeFileSync9(tmp, JSON.stringify(toDisk(s), null, 2), { encoding: "utf8" });
13459
+ writeFileSync11(tmp, JSON.stringify(toDisk(s), null, 2), { encoding: "utf8" });
13411
13460
  if (process.platform !== "win32") {
13412
13461
  chmodSync2(tmp, 384);
13413
13462
  }
@@ -16586,6 +16635,142 @@ var init_digest_month_pipeline = __esm({
16586
16635
  }
16587
16636
  });
16588
16637
 
16638
+ // ../entries/dist/credentials.js
16639
+ import { writeFileSync as writeFileSync12, readFileSync as readFileSync16, renameSync as renameSync6, chmodSync as chmodSync3, mkdirSync as mkdirSync12, existsSync as existsSync15, unlinkSync as unlinkSync5 } from "node:fs";
16640
+ import { dirname as dirname11 } from "node:path";
16641
+ async function fetchZaiUsage(candidate) {
16642
+ const key = candidate.trim();
16643
+ if (!key)
16644
+ throw new Error("empty key");
16645
+ const res = await fetch(ZAI_QUOTA_ENDPOINT, {
16646
+ headers: { Authorization: key, "Accept-Language": "en-US,en" }
16647
+ });
16648
+ if (!res.ok) {
16649
+ throw new Error(`Z.ai rejected the key (${res.status} ${res.statusText})`);
16650
+ }
16651
+ const body = await res.json().catch(() => {
16652
+ throw new Error("Z.ai returned an unparseable response");
16653
+ });
16654
+ if (body.code !== void 0 && body.code !== 200) {
16655
+ throw new Error(`Z.ai rejected the key (code ${body.code})`);
16656
+ }
16657
+ if (body.success === false) {
16658
+ throw new Error("Z.ai rejected the key");
16659
+ }
16660
+ const limits = body.data?.limits ?? [];
16661
+ let fiveHour = null;
16662
+ let sevenDay = null;
16663
+ let webSearch = null;
16664
+ for (const limit of limits) {
16665
+ const type = limit.type;
16666
+ if (type === "TIME_LIMIT") {
16667
+ const pct2 = typeof limit.percentage === "number" ? limit.percentage : null;
16668
+ webSearch = { used: pct2, limit: pct2 !== null ? 100 : null };
16669
+ continue;
16670
+ }
16671
+ if (type !== "TOKENS_LIMIT")
16672
+ continue;
16673
+ const unit = limit.unit;
16674
+ const pct = typeof limit.percentage === "number" ? limit.percentage : null;
16675
+ const resetsAt = typeof limit.nextResetTime === "number" ? new Date(limit.nextResetTime).toISOString() : null;
16676
+ const window = { utilization: pct, resets_at: resetsAt };
16677
+ if (unit === 6)
16678
+ sevenDay = sevenDay ?? window;
16679
+ else
16680
+ fiveHour = fiveHour ?? window;
16681
+ }
16682
+ return {
16683
+ captured_at: (/* @__PURE__ */ new Date()).toISOString(),
16684
+ agent: "zai",
16685
+ five_hour: fiveHour ?? { utilization: null, resets_at: null },
16686
+ seven_day: sevenDay ?? { utilization: null, resets_at: null },
16687
+ seven_day_opus: null,
16688
+ seven_day_sonnet: null,
16689
+ seven_day_oauth_apps: null,
16690
+ seven_day_cowork: null,
16691
+ extra_usage: null,
16692
+ plan_type: body.data?.level ?? null,
16693
+ web_search_quota: webSearch ?? null
16694
+ };
16695
+ }
16696
+ async function validateAndSnapshotZaiKey(key) {
16697
+ const snap = await fetchZaiUsage(key);
16698
+ appendUsageSnapshot(snap);
16699
+ return snap;
16700
+ }
16701
+ function deleteZaiKeyAndPrune() {
16702
+ deleteZaiKey();
16703
+ pruneUsageAgent("zai");
16704
+ }
16705
+ function credentialsPath() {
16706
+ return cclensPath("credentials.json");
16707
+ }
16708
+ function readCredentials() {
16709
+ const p = credentialsPath();
16710
+ if (!existsSync15(p))
16711
+ return {};
16712
+ try {
16713
+ const raw = readFileSync16(p, "utf8");
16714
+ return JSON.parse(raw);
16715
+ } catch {
16716
+ return {};
16717
+ }
16718
+ }
16719
+ function readCredentialsMasked() {
16720
+ const store = readCredentials();
16721
+ if (!store.zai?.apiKey)
16722
+ return {};
16723
+ const key = store.zai.apiKey;
16724
+ const hint = key.length > 12 ? `${key.slice(0, 6)}\u2026${key.slice(-6)}` : `${key.slice(0, 6)}\u2026`;
16725
+ return { zai: { configured: true, hint } };
16726
+ }
16727
+ function writeZaiKey(apiKey) {
16728
+ apiKey = apiKey.trim();
16729
+ if (!apiKey) {
16730
+ deleteZaiKey();
16731
+ return;
16732
+ }
16733
+ const store = readCredentials();
16734
+ store.zai = { ...store.zai ?? {}, apiKey };
16735
+ const p = credentialsPath();
16736
+ mkdirSync12(dirname11(p), { recursive: true });
16737
+ const tmp = `${p}.tmp`;
16738
+ writeFileSync12(tmp, JSON.stringify(store, null, 2), { encoding: "utf8" });
16739
+ if (process.platform !== "win32") {
16740
+ chmodSync3(tmp, 384);
16741
+ }
16742
+ renameSync6(tmp, p);
16743
+ }
16744
+ function deleteZaiKey() {
16745
+ const store = readCredentials();
16746
+ delete store.zai;
16747
+ const p = credentialsPath();
16748
+ if (Object.keys(store).length === 0) {
16749
+ try {
16750
+ unlinkSync5(p);
16751
+ } catch {
16752
+ }
16753
+ return;
16754
+ }
16755
+ const tmp = `${p}.tmp`;
16756
+ writeFileSync12(tmp, JSON.stringify(store, null, 2), { encoding: "utf8" });
16757
+ if (process.platform !== "win32") {
16758
+ chmodSync3(tmp, 384);
16759
+ }
16760
+ renameSync6(tmp, p);
16761
+ }
16762
+ function hasZaiKey() {
16763
+ return !!readCredentials().zai?.apiKey;
16764
+ }
16765
+ var ZAI_QUOTA_ENDPOINT;
16766
+ var init_credentials = __esm({
16767
+ "../entries/dist/credentials.js"() {
16768
+ "use strict";
16769
+ init_fs();
16770
+ ZAI_QUOTA_ENDPOINT = "https://api.z.ai/api/monitor/usage/quota/limit";
16771
+ }
16772
+ });
16773
+
16589
16774
  // ../entries/dist/node.js
16590
16775
  var node_exports = {};
16591
16776
  __export(node_exports, {
@@ -16616,19 +16801,25 @@ __export(node_exports, {
16616
16801
  computeInteractionGrammar: () => computeInteractionGrammar,
16617
16802
  computeInteractionModes: () => computeInteractionModes,
16618
16803
  computeWorkingShapes: () => computeWorkingShapes,
16804
+ deleteZaiKey: () => deleteZaiKey,
16805
+ deleteZaiKeyAndPrune: () => deleteZaiKeyAndPrune,
16619
16806
  enrichEntry: () => enrichEntry,
16807
+ fetchZaiUsage: () => fetchZaiUsage,
16620
16808
  generateDayDigest: () => generateDayDigest,
16621
16809
  generateMonthDigest: () => generateMonthDigest,
16622
16810
  generateWeekDigest: () => generateWeekDigest,
16623
16811
  getCurrentMonthDigestFromCache: () => getCurrentMonthDigestFromCache,
16624
16812
  getCurrentWeekDigestFromCache: () => getCurrentWeekDigestFromCache,
16625
16813
  getTodayDigestFromCache: () => getTodayDigestFromCache,
16814
+ hasZaiKey: () => hasZaiKey,
16626
16815
  interactiveLockFresh: () => interactiveLockFresh,
16627
16816
  listMonthDigestKeys: () => listMonthDigestKeys,
16628
16817
  listWeekDigestKeys: () => listWeekDigestKeys,
16629
16818
  mondayFor: () => mondayFor,
16630
16819
  mondaysInMonth: () => mondaysInMonth,
16631
16820
  monthToDateSpend: () => monthToDateSpend,
16821
+ readCredentials: () => readCredentials,
16822
+ readCredentialsMasked: () => readCredentialsMasked,
16632
16823
  readDayDigest: () => readDayDigest,
16633
16824
  readMonthDigest: () => readMonthDigest,
16634
16825
  readSettings: () => readSettings,
@@ -16643,12 +16834,14 @@ __export(node_exports, {
16643
16834
  setCurrentWeekDigestInCache: () => setCurrentWeekDigestInCache,
16644
16835
  setTodayDigestInCache: () => setTodayDigestInCache,
16645
16836
  tmuxRunnerAvailable: () => tmuxRunnerAvailable,
16837
+ validateAndSnapshotZaiKey: () => validateAndSnapshotZaiKey,
16646
16838
  weekDates: () => weekDates,
16647
16839
  writeDayDigest: () => writeDayDigest,
16648
16840
  writeInteractiveLock: () => writeInteractiveLock,
16649
16841
  writeMonthDigest: () => writeMonthDigest,
16650
16842
  writeSettings: () => writeSettings,
16651
- writeWeekDigest: () => writeWeekDigest
16843
+ writeWeekDigest: () => writeWeekDigest,
16844
+ writeZaiKey: () => writeZaiKey
16652
16845
  });
16653
16846
  var init_node = __esm({
16654
16847
  "../entries/dist/node.js"() {
@@ -16670,6 +16863,7 @@ var init_node = __esm({
16670
16863
  init_digest_month_pipeline();
16671
16864
  init_tmux_runner();
16672
16865
  init_digest_fs();
16866
+ init_credentials();
16673
16867
  }
16674
16868
  });
16675
16869
 
@@ -17139,6 +17333,230 @@ var init_digest = __esm({
17139
17333
  }
17140
17334
  });
17141
17335
 
17336
+ // src/commands/menubar.ts
17337
+ var menubar_exports = {};
17338
+ __export(menubar_exports, {
17339
+ menubar: () => menubar
17340
+ });
17341
+ import { existsSync as existsSync16, mkdirSync as mkdirSync13, cpSync, rmSync as rmSync2, readdirSync as readdirSync4, writeFileSync as writeFileSync13, realpathSync as realpathSync5 } from "node:fs";
17342
+ import { homedir as homedir6 } from "node:os";
17343
+ import { join as join12, dirname as dirname12 } from "node:path";
17344
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
17345
+ import { execFile as execFile2 } from "node:child_process";
17346
+ import { promisify as promisify2 } from "node:util";
17347
+ function isMac2() {
17348
+ return process.platform === "darwin";
17349
+ }
17350
+ function bundledAppPath() {
17351
+ const here = dirname12(fileURLToPath3(import.meta.url));
17352
+ return join12(here, "..", "menubar", APP_BUNDLE);
17353
+ }
17354
+ function resolveScriptPath2() {
17355
+ const argv1 = process.argv[1] ?? "";
17356
+ try {
17357
+ return realpathSync5(argv1);
17358
+ } catch {
17359
+ return argv1;
17360
+ }
17361
+ }
17362
+ function writeCliLaunchFile() {
17363
+ try {
17364
+ writeFileSync13(
17365
+ cclensPath("cli-launch.json"),
17366
+ JSON.stringify({ node: process.execPath, script: resolveScriptPath2() }),
17367
+ "utf8"
17368
+ );
17369
+ } catch {
17370
+ }
17371
+ }
17372
+ function installedAppPath() {
17373
+ return join12(homedir6(), "Applications", APP_BUNDLE);
17374
+ }
17375
+ async function isRunning() {
17376
+ try {
17377
+ const { stdout } = await execFileAsync2("pgrep", ["-x", BUNDLE_EXEC]);
17378
+ return stdout.trim().length > 0;
17379
+ } catch {
17380
+ return false;
17381
+ }
17382
+ }
17383
+ async function launchApp(path7) {
17384
+ await execFileAsync2("open", ["-a", path7]);
17385
+ }
17386
+ async function quitApp() {
17387
+ await execFileAsync2("osascript", ["-e", `tell application "${BUNDLE_EXEC}" to quit`]).catch(
17388
+ () => {
17389
+ }
17390
+ );
17391
+ await execFileAsync2("pkill", ["-x", BUNDLE_EXEC]).catch(() => {
17392
+ });
17393
+ }
17394
+ async function setLoginItem(enabled, appPath) {
17395
+ const script = enabled ? `tell application "System Events" to make login item at end with properties {path:"${appPath}", hidden:false}` : `tell application "System Events" to delete login item "${APP_BUNDLE.replace(".app", "")}"`;
17396
+ await execFileAsync2("osascript", ["-e", script]).catch(() => {
17397
+ });
17398
+ }
17399
+ async function installMenubar(opts) {
17400
+ if (!isMac2()) {
17401
+ console.log(NON_MAC_MSG2);
17402
+ return;
17403
+ }
17404
+ const src = bundledAppPath();
17405
+ if (!existsSync16(src)) {
17406
+ console.error(
17407
+ `Bundled widget not found at ${src}.
17408
+ 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.`
17409
+ );
17410
+ process.exit(1);
17411
+ }
17412
+ const destDir = join12(homedir6(), "Applications");
17413
+ mkdirSync13(destDir, { recursive: true });
17414
+ const dest = installedAppPath();
17415
+ if (await isRunning()) {
17416
+ console.log("Stopping the running widget\u2026");
17417
+ await quitApp();
17418
+ await new Promise((r) => setTimeout(r, 400));
17419
+ }
17420
+ rmSync2(dest, { recursive: true, force: true });
17421
+ cpSync(src, dest, { recursive: true });
17422
+ writeCliLaunchFile();
17423
+ console.log(`Installed \u2192 ${dest}`);
17424
+ if (opts.login) {
17425
+ await setLoginItem(true, dest);
17426
+ console.log("Login item enabled (launches at login).");
17427
+ }
17428
+ if (opts.open) {
17429
+ await launchApp(dest);
17430
+ console.log("Opened \u2014 check your menu bar (gauge icon on the right side).");
17431
+ } else {
17432
+ console.log(`Launch with: open -a "${dest}"`);
17433
+ }
17434
+ }
17435
+ async function uninstallMenubar() {
17436
+ if (!isMac2()) {
17437
+ console.log(NON_MAC_MSG2);
17438
+ return;
17439
+ }
17440
+ await setLoginItem(false, installedAppPath());
17441
+ if (await isRunning()) {
17442
+ console.log("Quitting the running widget\u2026");
17443
+ await quitApp();
17444
+ await new Promise((r) => setTimeout(r, 300));
17445
+ }
17446
+ const dest = installedAppPath();
17447
+ if (existsSync16(dest)) {
17448
+ rmSync2(dest, { recursive: true, force: true });
17449
+ console.log(`Removed ${dest}`);
17450
+ } else {
17451
+ console.log("Widget is not installed \u2014 nothing to remove.");
17452
+ }
17453
+ console.log("Login item cleared (if it was set).");
17454
+ }
17455
+ async function openMenubar() {
17456
+ if (!isMac2()) {
17457
+ console.log(NON_MAC_MSG2);
17458
+ return;
17459
+ }
17460
+ const dest = installedAppPath();
17461
+ if (!existsSync16(dest)) {
17462
+ console.log("Widget not installed yet. Run `fleetlens menubar install` first.");
17463
+ return;
17464
+ }
17465
+ if (await isRunning()) {
17466
+ console.log("Widget is already running.");
17467
+ return;
17468
+ }
17469
+ await launchApp(dest);
17470
+ console.log("Opened \u2014 check your menu bar.");
17471
+ }
17472
+ async function statusMenubar() {
17473
+ if (!isMac2()) {
17474
+ console.log(`Menu bar widget: macOS-only (not available on ${process.platform}).`);
17475
+ return;
17476
+ }
17477
+ const dest = installedAppPath();
17478
+ const installed = existsSync16(dest);
17479
+ const running = await isRunning();
17480
+ const bundled = existsSync16(bundledAppPath());
17481
+ console.log(`Menu bar widget: ${installed ? "installed" : "not installed"}${installed ? ` (${dest})` : ""}`);
17482
+ console.log(`Running: ${running ? "yes" : "no"}`);
17483
+ console.log(`Bundled in CLI: ${bundled ? "yes" : "no \u2014 this build ships without the widget"}`);
17484
+ if (installed) {
17485
+ try {
17486
+ const apps = readdirSync4(join12(homedir6(), "Applications"));
17487
+ const ours = apps.find((a) => a === APP_BUNDLE);
17488
+ console.log(`App bundle: ${ours ? "present in ~/Applications" : "missing"}`);
17489
+ } catch {
17490
+ }
17491
+ }
17492
+ }
17493
+ async function menubar(args2) {
17494
+ const sub = args2[0] ?? "status";
17495
+ const flags = args2.slice(1);
17496
+ const noOpen = flags.includes("--no-open");
17497
+ const noLogin = flags.includes("--no-login");
17498
+ switch (sub) {
17499
+ case "install": {
17500
+ await installMenubar({ open: !noOpen, login: !noLogin });
17501
+ break;
17502
+ }
17503
+ case "uninstall":
17504
+ case "remove":
17505
+ await uninstallMenubar();
17506
+ break;
17507
+ case "open":
17508
+ case "start":
17509
+ await openMenubar();
17510
+ break;
17511
+ case "stop":
17512
+ case "quit":
17513
+ if (await isRunning()) {
17514
+ await quitApp();
17515
+ console.log("Stopped.");
17516
+ } else {
17517
+ console.log("Widget is not running.");
17518
+ }
17519
+ break;
17520
+ case "status":
17521
+ await statusMenubar();
17522
+ break;
17523
+ case "help":
17524
+ case "--help":
17525
+ case "-h":
17526
+ console.log(`Usage: fleetlens menubar <install|uninstall|open|stop|status>
17527
+
17528
+ install [--no-open] [--no-login] Copy the native macOS menu bar widget to
17529
+ ~/Applications and launch it. Registers a
17530
+ login item by default.
17531
+ uninstall Quit + remove the widget, clear login item.
17532
+ open Launch the installed widget.
17533
+ stop Quit the running widget.
17534
+ status Show install/running/bundled state.
17535
+
17536
+ The widget tails ~/.cclens/usage.jsonl and shows live Claude Code / Codex
17537
+ plan utilization in the menu bar. Click it for a popover, or "Dashboard" to
17538
+ open http://localhost:3321.`);
17539
+ break;
17540
+ default:
17541
+ console.error(
17542
+ `Unknown menubar subcommand: ${sub}
17543
+ Usage: fleetlens menubar <install|uninstall|open|stop|status>`
17544
+ );
17545
+ process.exit(1);
17546
+ }
17547
+ }
17548
+ var execFileAsync2, APP_BUNDLE, BUNDLE_EXEC, NON_MAC_MSG2;
17549
+ var init_menubar = __esm({
17550
+ "src/commands/menubar.ts"() {
17551
+ "use strict";
17552
+ init_fs();
17553
+ execFileAsync2 = promisify2(execFile2);
17554
+ APP_BUNDLE = "FleetlensMenubar.app";
17555
+ BUNDLE_EXEC = "FleetlensMenubar";
17556
+ NON_MAC_MSG2 = "The Fleetlens menu bar widget is a native macOS app and is macOS-only. On Linux/Windows, keep using the dashboard at the printed URL.";
17557
+ }
17558
+ });
17559
+
17142
17560
  // src/team/config.ts
17143
17561
  var init_config = __esm({
17144
17562
  "src/team/config.ts"() {
@@ -17148,8 +17566,8 @@ var init_config = __esm({
17148
17566
  });
17149
17567
 
17150
17568
  // src/perception/build-entries.ts
17151
- import { statSync as statSync4, readFileSync as readFileSync15 } from "node:fs";
17152
- import { basename as basename2, dirname as dirname11 } from "node:path";
17569
+ import { statSync as statSync4, readFileSync as readFileSync17 } from "node:fs";
17570
+ import { basename as basename2, dirname as dirname13 } from "node:path";
17153
17571
  function decodeProjectDirName(projectDir) {
17154
17572
  if (projectDir.startsWith("-")) {
17155
17573
  return "/" + projectDir.slice(1).replace(/-/g, "/");
@@ -17158,7 +17576,7 @@ function decodeProjectDirName(projectDir) {
17158
17576
  }
17159
17577
  function buildEntriesForFile(filePath) {
17160
17578
  const stat = statSync4(filePath);
17161
- const raw = readFileSync15(filePath, "utf8");
17579
+ const raw = readFileSync17(filePath, "utf8");
17162
17580
  const rawLines = raw.split("\n").filter(Boolean).map((l) => {
17163
17581
  try {
17164
17582
  return JSON.parse(l);
@@ -17169,7 +17587,7 @@ function buildEntriesForFile(filePath) {
17169
17587
  if (rawLines.length === 0) return null;
17170
17588
  const { meta, events } = parseTranscript(rawLines);
17171
17589
  const fileName = basename2(filePath);
17172
- const projectDir = basename2(dirname11(filePath));
17590
+ const projectDir = basename2(dirname13(filePath));
17173
17591
  const sessionId = fileName.replace(/\.jsonl$/, "");
17174
17592
  const sd = {
17175
17593
  ...meta,
@@ -17423,7 +17841,7 @@ function buildIngestPayload(inputs) {
17423
17841
  return {
17424
17842
  ingestId: randomUUID2(),
17425
17843
  observedAt: (/* @__PURE__ */ new Date()).toISOString(),
17426
- cliVersion: "0.15.3",
17844
+ cliVersion: "0.15.4",
17427
17845
  ...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
17428
17846
  ...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
17429
17847
  ...richRollup ? { richRollup } : {},
@@ -17464,8 +17882,8 @@ var init_push = __esm({
17464
17882
  });
17465
17883
 
17466
17884
  // src/team/git-remote.ts
17467
- import { existsSync as existsSync14, readFileSync as readFileSync16, statSync as statSync5 } from "node:fs";
17468
- import { dirname as dirname12, isAbsolute as isAbsolute2, join as join12, resolve as resolve2 } from "node:path";
17885
+ import { existsSync as existsSync17, readFileSync as readFileSync18, statSync as statSync5 } from "node:fs";
17886
+ import { dirname as dirname14, isAbsolute as isAbsolute2, join as join13, resolve as resolve2 } from "node:path";
17469
17887
  function parseGithubRemote(url) {
17470
17888
  const m = url.trim().match(GITHUB_URL_RE);
17471
17889
  return m ? `${m[1]}/${m[2]}`.toLowerCase() : null;
@@ -17485,19 +17903,19 @@ function originUrl2(configText) {
17485
17903
  return null;
17486
17904
  }
17487
17905
  function gitConfigPathFor(dir) {
17488
- const dotGit = join12(dir, ".git");
17906
+ const dotGit = join13(dir, ".git");
17489
17907
  const st = statSync5(dotGit, { throwIfNoEntry: false });
17490
17908
  if (!st) return null;
17491
- if (st.isDirectory()) return join12(dotGit, "config");
17492
- const m = readFileSync16(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
17909
+ if (st.isDirectory()) return join13(dotGit, "config");
17910
+ const m = readFileSync18(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
17493
17911
  if (!m) return null;
17494
17912
  const gd = isAbsolute2(m[1]) ? m[1] : resolve2(dir, m[1]);
17495
- const commondirFile = join12(gd, "commondir");
17496
- if (existsSync14(commondirFile)) {
17497
- const common = readFileSync16(commondirFile, "utf8").trim();
17498
- return join12(isAbsolute2(common) ? common : resolve2(gd, common), "config");
17913
+ const commondirFile = join13(gd, "commondir");
17914
+ if (existsSync17(commondirFile)) {
17915
+ const common = readFileSync18(commondirFile, "utf8").trim();
17916
+ return join13(isAbsolute2(common) ? common : resolve2(gd, common), "config");
17499
17917
  }
17500
- return join12(gd, "config");
17918
+ return join13(gd, "config");
17501
17919
  }
17502
17920
  function createRepoResolver() {
17503
17921
  const cache = /* @__PURE__ */ new Map();
@@ -17507,14 +17925,14 @@ function createRepoResolver() {
17507
17925
  if (hit !== void 0) return hit;
17508
17926
  let repo = null;
17509
17927
  try {
17510
- for (let d = dir; ; d = dirname12(d)) {
17928
+ for (let d = dir; ; d = dirname14(d)) {
17511
17929
  const config = gitConfigPathFor(d);
17512
- if (config && existsSync14(config)) {
17513
- const url = originUrl2(readFileSync16(config, "utf8"));
17930
+ if (config && existsSync17(config)) {
17931
+ const url = originUrl2(readFileSync18(config, "utf8"));
17514
17932
  repo = url ? parseGithubRemote(url) : null;
17515
17933
  break;
17516
17934
  }
17517
- if (d === dirname12(d)) break;
17935
+ if (d === dirname14(d)) break;
17518
17936
  }
17519
17937
  } catch {
17520
17938
  repo = null;
@@ -17532,12 +17950,12 @@ var init_git_remote = __esm({
17532
17950
  });
17533
17951
 
17534
17952
  // src/team/queue.ts
17535
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync10, appendFileSync as appendFileSync4, statSync as statSync6, mkdirSync as mkdirSync11 } from "node:fs";
17536
- import { dirname as dirname13 } from "node:path";
17953
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync14, appendFileSync as appendFileSync5, statSync as statSync6, mkdirSync as mkdirSync14 } from "node:fs";
17954
+ import { dirname as dirname15 } from "node:path";
17537
17955
  function enqueuePayload(payload, queuePath = QUEUE_PATH) {
17538
- mkdirSync11(dirname13(queuePath), { recursive: true });
17956
+ mkdirSync14(dirname15(queuePath), { recursive: true });
17539
17957
  const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
17540
- appendFileSync4(queuePath, JSON.stringify(entry) + "\n", "utf8");
17958
+ appendFileSync5(queuePath, JSON.stringify(entry) + "\n", "utf8");
17541
17959
  try {
17542
17960
  const { size } = statSync6(queuePath);
17543
17961
  if (size > MAX_SIZE_BYTES) {
@@ -17549,7 +17967,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
17549
17967
  function dequeuePayloads(queuePath = QUEUE_PATH) {
17550
17968
  let lines;
17551
17969
  try {
17552
- lines = readFileSync17(queuePath, "utf8").trim().split("\n").filter(Boolean);
17970
+ lines = readFileSync19(queuePath, "utf8").trim().split("\n").filter(Boolean);
17553
17971
  } catch {
17554
17972
  return [];
17555
17973
  }
@@ -17564,18 +17982,18 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
17564
17982
  } catch {
17565
17983
  }
17566
17984
  }
17567
- writeFileSync10(queuePath, "", "utf8");
17985
+ writeFileSync14(queuePath, "", "utf8");
17568
17986
  return valid.map((e) => e.payload);
17569
17987
  }
17570
17988
  function pruneOldest(queuePath) {
17571
17989
  let lines;
17572
17990
  try {
17573
- lines = readFileSync17(queuePath, "utf8").trim().split("\n").filter(Boolean);
17991
+ lines = readFileSync19(queuePath, "utf8").trim().split("\n").filter(Boolean);
17574
17992
  } catch {
17575
17993
  return;
17576
17994
  }
17577
17995
  const keep = lines.slice(Math.floor(lines.length / 2));
17578
- writeFileSync10(queuePath, keep.join("\n") + "\n", "utf8");
17996
+ writeFileSync14(queuePath, keep.join("\n") + "\n", "utf8");
17579
17997
  }
17580
17998
  var QUEUE_PATH, MAX_SIZE_BYTES, MAX_AGE_MS;
17581
17999
  var init_queue2 = __esm({
@@ -17589,8 +18007,8 @@ var init_queue2 = __esm({
17589
18007
  });
17590
18008
 
17591
18009
  // src/usage/profile.ts
17592
- import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "node:fs";
17593
- import { dirname as dirname14 } from "node:path";
18010
+ import { existsSync as existsSync18, mkdirSync as mkdirSync15, readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "node:fs";
18011
+ import { dirname as dirname16 } from "node:path";
17594
18012
  function mapRateLimitTier(rateLimitTier) {
17595
18013
  switch (rateLimitTier) {
17596
18014
  case "default_claude_pro":
@@ -17630,9 +18048,9 @@ async function fetchProfile(nowMs = Date.now()) {
17630
18048
  };
17631
18049
  }
17632
18050
  function readCachedProfile(cachePath) {
17633
- if (!existsSync15(cachePath)) return null;
18051
+ if (!existsSync18(cachePath)) return null;
17634
18052
  try {
17635
- const raw = JSON.parse(readFileSync18(cachePath, "utf8"));
18053
+ const raw = JSON.parse(readFileSync20(cachePath, "utf8"));
17636
18054
  if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
17637
18055
  return raw;
17638
18056
  } catch {
@@ -17640,8 +18058,8 @@ function readCachedProfile(cachePath) {
17640
18058
  }
17641
18059
  }
17642
18060
  function writeCachedProfile(cachePath, profile, nowMs = Date.now()) {
17643
- mkdirSync12(dirname14(cachePath), { recursive: true });
17644
- writeFileSync11(
18061
+ mkdirSync15(dirname16(cachePath), { recursive: true });
18062
+ writeFileSync15(
17645
18063
  cachePath,
17646
18064
  JSON.stringify({ fetchedAtMs: nowMs, profile }, null, 2),
17647
18065
  { mode: 384 }
@@ -17821,11 +18239,11 @@ var init_backfill = __esm({
17821
18239
  });
17822
18240
 
17823
18241
  // src/team/sync-log.ts
17824
- import { readFileSync as readFileSync19 } from "node:fs";
18242
+ import { readFileSync as readFileSync21 } from "node:fs";
17825
18243
  function readPendingSyncLog(watermark) {
17826
18244
  let raw;
17827
18245
  try {
17828
- raw = readFileSync19(cclensPath("daemon.log"), "utf8");
18246
+ raw = readFileSync21(cclensPath("daemon.log"), "utf8");
17829
18247
  } catch {
17830
18248
  return { lines: [] };
17831
18249
  }
@@ -17853,12 +18271,12 @@ var init_sync_log = __esm({
17853
18271
  });
17854
18272
 
17855
18273
  // src/team/last-push.ts
17856
- import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync5, mkdirSync as mkdirSync13 } from "node:fs";
17857
- import { join as join13 } from "node:path";
18274
+ import { writeFileSync as writeFileSync16, unlinkSync as unlinkSync6, mkdirSync as mkdirSync16 } from "node:fs";
18275
+ import { join as join14 } from "node:path";
17858
18276
  function write(record, dir) {
17859
18277
  const d = dir ?? cclensHome();
17860
- mkdirSync13(d, { recursive: true });
17861
- writeFileSync12(join13(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
18278
+ mkdirSync16(d, { recursive: true });
18279
+ writeFileSync16(join14(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
17862
18280
  }
17863
18281
  function writeLastPushSuccess(payload, dir) {
17864
18282
  write({ pushedAt: (/* @__PURE__ */ new Date()).toISOString(), ok: true, payload }, dir);
@@ -17869,7 +18287,7 @@ function writeLastPushFailure(payload, error, dir) {
17869
18287
  function clearLastPush(dir) {
17870
18288
  const d = dir ?? cclensHome();
17871
18289
  try {
17872
- unlinkSync5(join13(d, LAST_PUSH_FILE));
18290
+ unlinkSync6(join14(d, LAST_PUSH_FILE));
17873
18291
  } catch {
17874
18292
  }
17875
18293
  }
@@ -17889,35 +18307,35 @@ __export(file_probe_exports, {
17889
18307
  probeArtifactSignals: () => probeArtifactSignals
17890
18308
  });
17891
18309
  import { createHash } from "node:crypto";
17892
- import { existsSync as existsSync16, readdirSync as readdirSync4, statSync as statSync7 } from "node:fs";
17893
- import { homedir as homedir6 } from "node:os";
17894
- import { join as join14, relative, resolve as resolve3, sep } from "node:path";
18310
+ import { existsSync as existsSync19, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
18311
+ import { homedir as homedir7 } from "node:os";
18312
+ import { join as join15, relative, resolve as resolve3, sep } from "node:path";
17895
18313
  import { execFileSync as execFileSync3 } from "node:child_process";
17896
18314
  function pathHash(relPath) {
17897
18315
  return createHash("sha256").update(relPath.split(sep).join("/")).digest("hex").slice(0, 32);
17898
18316
  }
17899
18317
  function defaultScanRoots(extraRoots = []) {
17900
18318
  const roots = [];
17901
- const home = join14(homedir6(), ".claude");
17902
- if (existsSync16(home)) roots.push({ root: home, label: "user" });
18319
+ const home = join15(homedir7(), ".claude");
18320
+ if (existsSync19(home)) roots.push({ root: home, label: "user" });
17903
18321
  for (const e of extraRoots) {
17904
18322
  const r = resolve3(e, ".claude");
17905
- if (existsSync16(r) && r !== home) roots.push({ root: r, label: "project" });
18323
+ if (existsSync19(r) && r !== home) roots.push({ root: r, label: "project" });
17906
18324
  }
17907
18325
  return roots;
17908
18326
  }
17909
18327
  function listMarkdownFiles(dir) {
17910
- if (!existsSync16(dir)) return [];
18328
+ if (!existsSync19(dir)) return [];
17911
18329
  const out = [];
17912
18330
  let entries2;
17913
18331
  try {
17914
- entries2 = readdirSync4(dir);
18332
+ entries2 = readdirSync5(dir);
17915
18333
  } catch {
17916
18334
  return [];
17917
18335
  }
17918
18336
  for (const name of entries2) {
17919
18337
  if (name.startsWith(".")) continue;
17920
- const full = join14(dir, name);
18338
+ const full = join15(dir, name);
17921
18339
  let stat;
17922
18340
  try {
17923
18341
  stat = statSync7(full);
@@ -17937,7 +18355,7 @@ function firstSeenDateOf(file) {
17937
18355
  const out = execFileSync3(
17938
18356
  "git",
17939
18357
  ["log", "--diff-filter=A", "--follow", "--format=%cs", "--", file],
17940
- { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname15(file) }
18358
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname17(file) }
17941
18359
  ).trim().split("\n").filter(Boolean);
17942
18360
  if (out.length > 0) return out[out.length - 1];
17943
18361
  } catch {
@@ -17949,7 +18367,7 @@ function firstSeenDateOf(file) {
17949
18367
  return todayLocal();
17950
18368
  }
17951
18369
  }
17952
- function dirname15(p) {
18370
+ function dirname17(p) {
17953
18371
  const i = p.lastIndexOf(sep);
17954
18372
  return i < 0 ? "." : p.slice(0, i);
17955
18373
  }
@@ -17976,8 +18394,8 @@ function todayLocal() {
17976
18394
  function scanAuthored(roots, subdir, day2) {
17977
18395
  const out = [];
17978
18396
  for (const r of roots) {
17979
- const dir = join14(r.root, subdir);
17980
- if (!existsSync16(dir)) continue;
18397
+ const dir = join15(r.root, subdir);
18398
+ if (!existsSync19(dir)) continue;
17981
18399
  for (const f of listMarkdownFiles(dir)) {
17982
18400
  const firstSeen = firstSeenDateOf(f);
17983
18401
  if (firstSeen !== day2) continue;
@@ -17990,8 +18408,8 @@ function scanAuthored(roots, subdir, day2) {
17990
18408
  function scanEdited(roots, day2) {
17991
18409
  const out = [];
17992
18410
  for (const r of roots) {
17993
- const dir = join14(r.root, "skills");
17994
- if (!existsSync16(dir)) continue;
18411
+ const dir = join15(r.root, "skills");
18412
+ if (!existsSync19(dir)) continue;
17995
18413
  for (const f of listMarkdownFiles(dir)) {
17996
18414
  const firstSeen = firstSeenDateOf(f);
17997
18415
  if (firstSeen === day2) continue;
@@ -18014,16 +18432,16 @@ function claudemdLineDelta(extraRoots, authorEmail, day2) {
18014
18432
  const candidates = [];
18015
18433
  for (const e of extraRoots) {
18016
18434
  const f = resolve3(e, "CLAUDE.md");
18017
- if (existsSync16(f)) candidates.push(f);
18435
+ if (existsSync19(f)) candidates.push(f);
18018
18436
  }
18019
- const homeClaudeMd = join14(homedir6(), "CLAUDE.md");
18020
- if (existsSync16(homeClaudeMd)) candidates.push(homeClaudeMd);
18437
+ const homeClaudeMd = join15(homedir7(), "CLAUDE.md");
18438
+ if (existsSync19(homeClaudeMd)) candidates.push(homeClaudeMd);
18021
18439
  for (const file of candidates) {
18022
18440
  try {
18023
18441
  const out = execFileSync3(
18024
18442
  "git",
18025
18443
  ["log", "--numstat", "--format=COMMIT %cs %ae", "--", file],
18026
- { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname15(file) }
18444
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname17(file) }
18027
18445
  );
18028
18446
  let currentDate = "";
18029
18447
  let currentEmail = "";
@@ -18674,10 +19092,10 @@ var daemon_log_exports = {};
18674
19092
  __export(daemon_log_exports, {
18675
19093
  appendDaemonLogLine: () => appendDaemonLogLine
18676
19094
  });
18677
- import { appendFileSync as appendFileSync5 } from "node:fs";
19095
+ import { appendFileSync as appendFileSync6 } from "node:fs";
18678
19096
  function appendDaemonLogLine(level, msg) {
18679
19097
  try {
18680
- appendFileSync5(
19098
+ appendFileSync6(
18681
19099
  cclensPath("daemon.log"),
18682
19100
  `${(/* @__PURE__ */ new Date()).toISOString()} ${level.toUpperCase()} ${msg}
18683
19101
  `,
@@ -18890,11 +19308,11 @@ var logs_exports = {};
18890
19308
  __export(logs_exports, {
18891
19309
  teamLogs: () => teamLogs
18892
19310
  });
18893
- import { readFileSync as readFileSync20 } from "node:fs";
19311
+ import { readFileSync as readFileSync22 } from "node:fs";
18894
19312
  async function teamLogs() {
18895
19313
  const logPath = cclensPath("daemon.log");
18896
19314
  try {
18897
- const lines = readFileSync20(logPath, "utf8").trim().split("\n");
19315
+ const lines = readFileSync22(logPath, "utf8").trim().split("\n");
18898
19316
  const teamLines = lines.filter((l) => l.includes("[sync] ") || l.includes("team "));
18899
19317
  if (teamLines.length === 0) {
18900
19318
  console.log("No team-related log entries found.");
@@ -19022,8 +19440,8 @@ __export(runs_exports, {
19022
19440
  runs: () => runs
19023
19441
  });
19024
19442
  import { execSync as execSync2 } from "node:child_process";
19025
- import { existsSync as existsSync17, readFileSync as readFileSync21, readdirSync as readdirSync5, statSync as statSync8 } from "node:fs";
19026
- import { join as join15 } from "node:path";
19443
+ import { existsSync as existsSync20, readFileSync as readFileSync23, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
19444
+ import { join as join16 } from "node:path";
19027
19445
  async function runs(args2) {
19028
19446
  const json = args2.includes("--json");
19029
19447
  const watch = args2.includes("--watch");
@@ -19107,8 +19525,8 @@ function listActiveRuns() {
19107
19525
  return runs2.sort((a, b) => a.elapsed_s - b.elapsed_s);
19108
19526
  }
19109
19527
  function readSpend(sinceMs) {
19110
- if (!existsSync17(SPEND_PATH)) return [];
19111
- const lines = readFileSync21(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
19528
+ if (!existsSync20(SPEND_PATH)) return [];
19529
+ const lines = readFileSync23(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
19112
19530
  const out = [];
19113
19531
  for (const line of lines) {
19114
19532
  try {
@@ -19229,23 +19647,23 @@ function ageLabel(ms) {
19229
19647
  return `${Math.floor(ms / 864e5)}d`;
19230
19648
  }
19231
19649
  function listTraceFiles() {
19232
- if (!existsSync17(RUNS_DIR2)) return [];
19233
- const entries2 = readdirSync5(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
19650
+ if (!existsSync20(RUNS_DIR2)) return [];
19651
+ const entries2 = readdirSync6(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
19234
19652
  return entries2.map((f) => {
19235
- const path7 = join15(RUNS_DIR2, f);
19653
+ const path7 = join16(RUNS_DIR2, f);
19236
19654
  const st = statSync8(path7);
19237
19655
  return { runId: f.replace(/\.jsonl$/, ""), path: path7, mtimeMs: st.mtimeMs };
19238
19656
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
19239
19657
  }
19240
19658
  function resolveRunId(arg) {
19241
- if (!existsSync17(RUNS_DIR2)) return null;
19659
+ if (!existsSync20(RUNS_DIR2)) return null;
19242
19660
  if (arg === "latest") {
19243
19661
  const all2 = listTraceFiles();
19244
19662
  if (all2.length === 0) return null;
19245
19663
  return { runId: all2[0].runId, path: all2[0].path };
19246
19664
  }
19247
- const exact = join15(RUNS_DIR2, `${arg}.jsonl`);
19248
- if (existsSync17(exact)) return { runId: arg, path: exact };
19665
+ const exact = join16(RUNS_DIR2, `${arg}.jsonl`);
19666
+ if (existsSync20(exact)) return { runId: arg, path: exact };
19249
19667
  const all = listTraceFiles();
19250
19668
  const matches = all.filter((r) => r.runId.includes(arg));
19251
19669
  if (matches.length === 1) return { runId: matches[0].runId, path: matches[0].path };
@@ -19257,7 +19675,7 @@ function resolveRunId(arg) {
19257
19675
  return null;
19258
19676
  }
19259
19677
  function readTrace(path7) {
19260
- return readFileSync21(path7, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
19678
+ return readFileSync23(path7, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
19261
19679
  try {
19262
19680
  return JSON.parse(l);
19263
19681
  } catch {
@@ -19269,7 +19687,7 @@ async function inspect(arg, follow, json) {
19269
19687
  const r = resolveRunId(arg);
19270
19688
  if (!r) {
19271
19689
  console.error(`run not found: ${arg}`);
19272
- if (existsSync17(RUNS_DIR2)) {
19690
+ if (existsSync20(RUNS_DIR2)) {
19273
19691
  const all = listTraceFiles().slice(0, 5);
19274
19692
  if (all.length > 0) {
19275
19693
  console.error(`
@@ -19431,6 +19849,11 @@ async function main() {
19431
19849
  await autostart2(args.slice(1));
19432
19850
  break;
19433
19851
  }
19852
+ case "menubar": {
19853
+ const { menubar: menubar2 } = await Promise.resolve().then(() => (init_menubar(), menubar_exports));
19854
+ await menubar2(args.slice(1));
19855
+ break;
19856
+ }
19434
19857
  case "team": {
19435
19858
  const { team: team2 } = await Promise.resolve().then(() => (init_team2(), team_exports));
19436
19859
  await team2(args.slice(1));
@@ -19444,7 +19867,7 @@ async function main() {
19444
19867
  case "version":
19445
19868
  case "--version":
19446
19869
  case "-v":
19447
- console.log(`fleetlens ${"0.15.3"}`);
19870
+ console.log(`fleetlens ${"0.15.4"}`);
19448
19871
  break;
19449
19872
  case "help":
19450
19873
  case "--help":
@@ -19471,6 +19894,7 @@ Advanced:
19471
19894
  start --no-daemon Start only the web server (no daemon)
19472
19895
  daemon <start|stop|status|logs> Manage the usage daemon by itself
19473
19896
  autostart <install|uninstall|status> Run the usage daemon at login (macOS launchd)
19897
+ menubar <install|uninstall|open|status> Native macOS menu bar widget (Claude/Codex/Z.ai usage)
19474
19898
 
19475
19899
  Team:
19476
19900
  team join <url> <token> Pair with a team server (browser setup)