fleetlens 1.0.3 → 1.0.5

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 (110) 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 +2 -2
  12. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  13. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/app/apps/web/.next/server/app/agent/page.js +2 -2
  15. package/app/apps/web/.next/server/app/agent/page.js.nft.json +1 -1
  16. package/app/apps/web/.next/server/app/agent/page_client-reference-manifest.js +1 -1
  17. package/app/apps/web/.next/server/app/changelog/page.js +2 -2
  18. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  20. package/app/apps/web/.next/server/app/day/[date]/page.js +2 -2
  21. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  23. package/app/apps/web/.next/server/app/day/page.js +2 -2
  24. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  25. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  26. package/app/apps/web/.next/server/app/digest/[date]/page.js +2 -2
  27. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  29. package/app/apps/web/.next/server/app/digest/page.js +2 -2
  30. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  31. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  32. package/app/apps/web/.next/server/app/insights/[key]/page.js +2 -2
  33. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  34. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  35. package/app/apps/web/.next/server/app/insights/page.js +2 -2
  36. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  37. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  38. package/app/apps/web/.next/server/app/page.js +2 -2
  39. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  40. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  41. package/app/apps/web/.next/server/app/parallelism/page.js +2 -2
  42. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  43. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  44. package/app/apps/web/.next/server/app/print/[key]/page.js +2 -2
  45. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -1
  46. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
  47. package/app/apps/web/.next/server/app/projects/[slug]/page.js +2 -2
  48. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  49. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  50. package/app/apps/web/.next/server/app/projects/page.js +2 -2
  51. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  52. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  53. package/app/apps/web/.next/server/app/runs/page.js +2 -2
  54. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  55. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  56. package/app/apps/web/.next/server/app/sessions/[id]/page.js +2 -2
  57. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  58. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  59. package/app/apps/web/.next/server/app/sessions/page.js +2 -2
  60. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  61. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  62. package/app/apps/web/.next/server/app/settings/page.js +2 -2
  63. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  64. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  65. package/app/apps/web/.next/server/app/team/onboarding/page.js +2 -2
  66. package/app/apps/web/.next/server/app/team/onboarding/page.js.nft.json +1 -1
  67. package/app/apps/web/.next/server/app/team/onboarding/page_client-reference-manifest.js +1 -1
  68. package/app/apps/web/.next/server/app/team/page.js +2 -2
  69. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  70. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  71. package/app/apps/web/.next/server/app/usage/page.js +2 -2
  72. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  73. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  74. package/app/apps/web/.next/server/chunks/[root-of-the-server]__02.51sr._.js +1 -1
  75. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0zyh554._.js +1 -1
  76. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +1 -1
  77. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +1 -1
  78. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0f3q8gt._.js → [root-of-the-server]__0s~wd1k._.js} +2 -2
  79. package/app/apps/web/.next/server/chunks/ssr/_0k8yioi._.js +1 -1
  80. package/app/apps/web/.next/server/chunks/ssr/_0sz8~hl._.js +1 -1
  81. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0x014hn._.js +1 -1
  82. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
  83. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
  84. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0mx_509._.js +1 -1
  85. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  86. package/app/apps/web/.next/server/middleware-manifest.json +5 -5
  87. package/app/apps/web/.next/server/pages/500.html +1 -1
  88. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  89. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  90. package/app/apps/web/.next/static/chunks/0livk1wjx5m4o.js +14 -0
  91. package/app/apps/web/.next/static/chunks/0r~~~j3kmv7s_.js +1 -0
  92. package/app/apps/web/.next/static/chunks/14ql3hdixfx1j.js +1 -0
  93. package/app/apps/web/app/layout.tsx +3 -3
  94. package/app/apps/web/components/sidebar.tsx +4 -3
  95. package/app/apps/web/components/usage-sidebar.tsx +198 -43
  96. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  97. package/app/apps/web/lib/usage-data.ts +14 -9
  98. package/app/apps/web/lib/usage-display.test.ts +59 -0
  99. package/app/apps/web/lib/usage-display.ts +73 -0
  100. package/app/apps/web/package.json +1 -1
  101. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  102. package/dist/daemon-worker.js +61 -6
  103. package/dist/index.js +67 -12
  104. package/menubar/Fleetlens.app/Contents/Info.plist +2 -2
  105. package/menubar/Fleetlens.app/Contents/MacOS/FleetlensMenubar +0 -0
  106. package/package.json +1 -1
  107. package/app/apps/web/.next/static/chunks/0ntt~a0712~pv.js +0 -14
  108. /package/app/apps/web/.next/static/{Shk_TH0B6lHs9cBZekkf5 → 9SCQmb07YbEKELgH9eGzq}/_buildManifest.js +0 -0
  109. /package/app/apps/web/.next/static/{Shk_TH0B6lHs9cBZekkf5 → 9SCQmb07YbEKELgH9eGzq}/_clientMiddlewareManifest.js +0 -0
  110. /package/app/apps/web/.next/static/{Shk_TH0B6lHs9cBZekkf5 → 9SCQmb07YbEKELgH9eGzq}/_ssgManifest.js +0 -0
@@ -70,20 +70,25 @@ export const readUsageSnapshots = cache((): UsageSnapshot[] => {
70
70
  return snapshots;
71
71
  });
72
72
 
73
- export const latestUsageSnapshot = cache((): UsageSnapshot | null => {
73
+ /** Latest snapshot per agent (last line wins for each agent tag). */
74
+ export const latestUsageSnapshotsByAgent = cache((): Partial<Record<AgentKind, UsageSnapshot>> => {
74
75
  const all = readUsageSnapshots();
75
- // Sidebar's "current usage" widget is Claude-tier specific (extra_usage,
76
- // per-model 7d windows). Filter to Claude only so a Codex snapshot doesn't
77
- // accidentally end up as the latest source.
78
- const claude = all.filter((s) => (s.agent ?? "claude-code") === "claude-code");
79
- return claude.length > 0 ? claude[claude.length - 1]! : null;
76
+ const byAgent: Partial<Record<AgentKind, UsageSnapshot>> = {};
77
+ for (const s of all) {
78
+ const agent = (s.agent ?? "claude-code") as AgentKind;
79
+ byAgent[agent] = s;
80
+ }
81
+ return byAgent;
82
+ });
83
+
84
+ /** Claude-only latest. Kept for callers that still want the default plan. */
85
+ export const latestUsageSnapshot = cache((): UsageSnapshot | null => {
86
+ return latestUsageSnapshotsByAgent()["claude-code"] ?? null;
80
87
  });
81
88
 
82
89
  export const latestUsageSnapshotByAgent = cache(
83
90
  (agent: AgentKind): UsageSnapshot | null => {
84
- const all = readUsageSnapshots();
85
- const filtered = all.filter((s) => (s.agent ?? "claude-code") === agent);
86
- return filtered.length > 0 ? filtered[filtered.length - 1]! : null;
91
+ return latestUsageSnapshotsByAgent()[agent] ?? null;
87
92
  },
88
93
  );
89
94
 
@@ -2,6 +2,8 @@ import { describe, expect, it } from "vitest";
2
2
  import {
3
3
  copilotQuotaPresentation,
4
4
  copilotUnitLabel,
5
+ sidebarUsageRows,
6
+ sortUsageAgents,
5
7
  visibleUsageAgents,
6
8
  } from "./usage-display";
7
9
 
@@ -26,6 +28,63 @@ describe("visibleUsageAgents", () => {
26
28
  });
27
29
  });
28
30
 
31
+ describe("sortUsageAgents", () => {
32
+ it("puts Claude first and sorts the rest alphabetically", () => {
33
+ expect(sortUsageAgents(["grok", "claude-code", "codex", "zai"])).toEqual([
34
+ "claude-code",
35
+ "codex",
36
+ "grok",
37
+ "zai",
38
+ ]);
39
+ });
40
+ });
41
+
42
+ describe("sidebarUsageRows", () => {
43
+ const win = (u: number) => ({ utilization: u, resets_at: null });
44
+
45
+ it("returns empty when there is no snapshot", () => {
46
+ expect(sidebarUsageRows("claude-code", null)).toEqual([]);
47
+ });
48
+
49
+ it("shows 5h + 7d for Claude, and optional Sonnet", () => {
50
+ const snap = {
51
+ five_hour: win(10),
52
+ seven_day: win(40),
53
+ seven_day_sonnet: win(12),
54
+ };
55
+ expect(sidebarUsageRows("claude-code", snap).map((r) => r.label)).toEqual(["5h", "7d"]);
56
+ expect(
57
+ sidebarUsageRows("claude-code", snap, { showSonnet: true }).map((r) => r.label),
58
+ ).toEqual(["5h", "7d", "Sonnet 7d"]);
59
+ });
60
+
61
+ it("hides the retired Codex 5h meter when utilization is null", () => {
62
+ const snap = { five_hour: { utilization: null, resets_at: null }, seven_day: win(55) };
63
+ expect(sidebarUsageRows("codex", snap).map((r) => r.label)).toEqual(["7d"]);
64
+ });
65
+
66
+ it("uses monthly for Copilot and 7d-only for Grok", () => {
67
+ expect(
68
+ sidebarUsageRows("copilot", { monthly: win(3) }).map((r) => r.label),
69
+ ).toEqual(["Monthly"]);
70
+ expect(
71
+ sidebarUsageRows("grok", { seven_day: win(80) }).map((r) => r.label),
72
+ ).toEqual(["7d"]);
73
+ });
74
+
75
+ it("derives Copilot monthly windowMs from the calendar month of resets_at", () => {
76
+ // resets_at = Mar 1 00:00 UTC → previous month is February (non-leap 2026)
77
+ const febMs =
78
+ Date.UTC(2026, 2, 1) - Date.UTC(2026, 1, 1); // Mar 1 − Feb 1
79
+ const rows = sidebarUsageRows("copilot", {
80
+ monthly: { utilization: 20, resets_at: "2026-03-01T00:00:00.000Z" },
81
+ });
82
+ expect(rows).toHaveLength(1);
83
+ expect(rows[0]!.windowMs).toBe(febMs);
84
+ expect(rows[0]!.windowMs).toBe(28 * 24 * 3_600_000);
85
+ });
86
+ });
87
+
29
88
  describe("copilotQuotaPresentation", () => {
30
89
  it("does not claim unlimited use when Copilot omits a personal limit", () => {
31
90
  const display = copilotQuotaPresentation(null, {
@@ -11,6 +11,79 @@ export function visibleUsageAgents(snapshots: UsageAgentEvidence[]): AgentKind[]
11
11
  return Array.from(agents);
12
12
  }
13
13
 
14
+ /** Claude first, then the rest alphabetically — matches /usage tabs. */
15
+ export function sortUsageAgents(agents: AgentKind[]): AgentKind[] {
16
+ return [...agents].sort((a, b) => {
17
+ if (a === "claude-code") return -1;
18
+ if (b === "claude-code") return 1;
19
+ return a.localeCompare(b);
20
+ });
21
+ }
22
+
23
+ export type SidebarUsageRow = {
24
+ label: string;
25
+ window: { utilization: number | null; resets_at: string | null } | null;
26
+ windowMs: number;
27
+ };
28
+
29
+ const HOUR = 3_600_000;
30
+ const FIVE_HOURS_MS = 5 * HOUR;
31
+ const SEVEN_DAYS_MS = 7 * 24 * HOUR;
32
+ const MONTHLY_MS = 30 * 24 * HOUR;
33
+
34
+ /**
35
+ * Which meters the sidebar shows for an agent. Mirrors /usage so switching
36
+ * the sidebar agent doesn't invent windows that agent never reports.
37
+ */
38
+ export function sidebarUsageRows(
39
+ agent: AgentKind,
40
+ snapshot: {
41
+ five_hour?: { utilization: number | null; resets_at: string | null } | null;
42
+ seven_day?: { utilization: number | null; resets_at: string | null } | null;
43
+ seven_day_sonnet?: { utilization: number | null; resets_at: string | null } | null;
44
+ monthly?: { utilization: number | null; resets_at: string | null } | null;
45
+ } | null,
46
+ opts: { showSonnet?: boolean } = {},
47
+ ): SidebarUsageRow[] {
48
+ if (!snapshot) return [];
49
+
50
+ if (agent === "copilot") {
51
+ // Calendar-month length (same rule as UsageChart.cycleStart for monthly).
52
+ // A fixed 30d window mis-colors pace near ±15pp in Feb / 31-day months.
53
+ const monthly = snapshot.monthly ?? null;
54
+ let windowMs = MONTHLY_MS;
55
+ if (monthly?.resets_at) {
56
+ const endMs = new Date(monthly.resets_at).getTime();
57
+ if (Number.isFinite(endMs)) {
58
+ const reset = new Date(endMs);
59
+ const startMs = Date.UTC(reset.getUTCFullYear(), reset.getUTCMonth() - 1, 1);
60
+ windowMs = Math.max(HOUR, endMs - startMs);
61
+ }
62
+ }
63
+ return [{ label: "Monthly", window: monthly, windowMs }];
64
+ }
65
+ if (agent === "grok") {
66
+ return [{ label: "7d", window: snapshot.seven_day ?? null, windowMs: SEVEN_DAYS_MS }];
67
+ }
68
+ // Codex accounts that dropped the 5h limit only report 7d.
69
+ if (agent === "codex" && snapshot.five_hour?.utilization == null) {
70
+ return [{ label: "7d", window: snapshot.seven_day ?? null, windowMs: SEVEN_DAYS_MS }];
71
+ }
72
+
73
+ const rows: SidebarUsageRow[] = [
74
+ { label: "5h", window: snapshot.five_hour ?? null, windowMs: FIVE_HOURS_MS },
75
+ { label: "7d", window: snapshot.seven_day ?? null, windowMs: SEVEN_DAYS_MS },
76
+ ];
77
+ if (agent === "claude-code" && opts.showSonnet) {
78
+ rows.push({
79
+ label: "Sonnet 7d",
80
+ window: snapshot.seven_day_sonnet ?? null,
81
+ windowMs: SEVEN_DAYS_MS,
82
+ });
83
+ }
84
+ return rows;
85
+ }
86
+
14
87
  export type CopilotMonthlyQuota = {
15
88
  used: number | null;
16
89
  limit: number | null;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-lens/web",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "private": true,
5
5
  "description": "Local-only dashboard for Claude Code sessions. Reads ~/.claude/projects/*.jsonl and visualizes agent activity.",
6
6
  "license": "MIT",