fleetlens 0.13.0 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/build-manifest.json +8 -8
  3. package/app/apps/web/.next/prerender-manifest.json +3 -3
  4. package/app/apps/web/.next/server/app/_global-error/page/build-manifest.json +5 -5
  5. package/app/apps/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  6. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  7. package/app/apps/web/.next/server/app/_global-error.rsc +7 -7
  8. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  9. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  10. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  11. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  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/build-manifest.json +5 -5
  14. package/app/apps/web/.next/server/app/_not-found/page.js +1 -1
  15. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  18. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +1 -1
  19. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  20. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +1 -1
  21. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  23. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +1 -1
  24. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  25. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  26. package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
  27. package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -1
  29. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  31. package/app/apps/web/.next/server/app/api/runs/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  33. package/app/apps/web/.next/server/app/api/team-config/route.js.nft.json +1 -1
  34. package/app/apps/web/.next/server/app/api/workflow-agent/route.js.nft.json +1 -1
  35. package/app/apps/web/.next/server/app/changelog/page/build-manifest.json +5 -5
  36. package/app/apps/web/.next/server/app/changelog/page.js +1 -1
  37. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  38. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  39. package/app/apps/web/.next/server/app/day/[date]/page/build-manifest.json +5 -5
  40. package/app/apps/web/.next/server/app/day/[date]/page.js +1 -1
  41. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  42. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  43. package/app/apps/web/.next/server/app/day/page/build-manifest.json +5 -5
  44. package/app/apps/web/.next/server/app/day/page.js +1 -1
  45. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  46. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  47. package/app/apps/web/.next/server/app/digest/[date]/page/build-manifest.json +5 -5
  48. package/app/apps/web/.next/server/app/digest/[date]/page.js +1 -1
  49. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  50. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  51. package/app/apps/web/.next/server/app/digest/page/build-manifest.json +5 -5
  52. package/app/apps/web/.next/server/app/digest/page.js +1 -1
  53. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  54. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  55. package/app/apps/web/.next/server/app/insights/[key]/page/build-manifest.json +5 -5
  56. package/app/apps/web/.next/server/app/insights/[key]/page.js +1 -1
  57. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  58. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  59. package/app/apps/web/.next/server/app/insights/page/build-manifest.json +5 -5
  60. package/app/apps/web/.next/server/app/insights/page.js +3 -2
  61. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  62. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  63. package/app/apps/web/.next/server/app/page/build-manifest.json +5 -5
  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/build-manifest.json +5 -5
  68. package/app/apps/web/.next/server/app/parallelism/page.js +1 -1
  69. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  70. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  71. package/app/apps/web/.next/server/app/print/[key]/page/build-manifest.json +5 -5
  72. package/app/apps/web/.next/server/app/print/[key]/page.js +1 -1
  73. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -1
  74. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
  75. package/app/apps/web/.next/server/app/projects/[slug]/page/build-manifest.json +5 -5
  76. package/app/apps/web/.next/server/app/projects/[slug]/page.js +1 -1
  77. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  78. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  79. package/app/apps/web/.next/server/app/projects/page/build-manifest.json +5 -5
  80. package/app/apps/web/.next/server/app/projects/page.js +1 -1
  81. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  82. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  83. package/app/apps/web/.next/server/app/runs/page/build-manifest.json +5 -5
  84. package/app/apps/web/.next/server/app/runs/page.js +1 -1
  85. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  86. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  87. package/app/apps/web/.next/server/app/sessions/[id]/page/build-manifest.json +5 -5
  88. package/app/apps/web/.next/server/app/sessions/[id]/page.js +1 -1
  89. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  90. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  91. package/app/apps/web/.next/server/app/sessions/page/build-manifest.json +5 -5
  92. package/app/apps/web/.next/server/app/sessions/page.js +1 -1
  93. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  94. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  95. package/app/apps/web/.next/server/app/settings/page/build-manifest.json +5 -5
  96. package/app/apps/web/.next/server/app/settings/page.js +1 -1
  97. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  98. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  99. package/app/apps/web/.next/server/app/team/page/build-manifest.json +5 -5
  100. package/app/apps/web/.next/server/app/team/page.js +1 -1
  101. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  102. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  103. package/app/apps/web/.next/server/app/usage/page/build-manifest.json +5 -5
  104. package/app/apps/web/.next/server/app/usage/page.js +1 -1
  105. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  106. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  107. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0gril0u._.js +9 -0
  108. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0n79hpm._.js +9 -0
  109. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0~utv~v._.js +9 -0
  110. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +1 -1
  111. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +1 -1
  112. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0exckd4._.js +1 -1
  113. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0-1_njm._.js → [root-of-the-server]__0k1x-c9._.js} +2 -2
  114. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0lhwp-k._.js +8 -0
  115. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0n-ax-5._.js +1 -1
  116. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~.f_3z._.js +3 -3
  117. package/app/apps/web/.next/server/chunks/ssr/_0kajk31._.js +1 -1
  118. package/app/apps/web/.next/server/chunks/ssr/_0s3n5mz._.js +8 -0
  119. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  120. package/app/apps/web/.next/server/chunks/ssr/{_0jw2sm7._.js → _12mbgs5._.js} +2 -2
  121. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_day_[date]_day-view_tsx_0wjoe1u._.js +1 -1
  122. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_insights_page_tsx_071kwyw._.js +3 -0
  123. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_sessions_sessions-grid_tsx_0bri5x.._.js +3 -0
  124. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0l6hsch._.js +6 -0
  125. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
  126. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
  127. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0cepfi8._.js +3 -0
  128. package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +1 -1
  129. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0mx_509._.js +1 -1
  130. package/app/apps/web/.next/server/middleware-build-manifest.js +8 -8
  131. package/app/apps/web/.next/server/middleware-manifest.json +5 -5
  132. package/app/apps/web/.next/server/pages/500.html +1 -1
  133. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  134. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  135. package/app/apps/web/.next/static/chunks/02xxpexzk3rf-.js +1 -0
  136. package/app/apps/web/.next/static/chunks/{07lbm-sdh9c2j.js → 0389wb_f0j78j.js} +1 -1
  137. package/app/apps/web/.next/static/chunks/03gy1evbn94qu.js +6 -0
  138. package/app/apps/web/.next/static/chunks/03rd.3cc_t~yf.js +4 -0
  139. package/app/apps/web/.next/static/chunks/{0l4e3as18eexy.js → 0g223u9amib0q.js} +1 -1
  140. package/app/apps/web/.next/static/chunks/{0h3.-_s-k0mj3.js → 0i.hc~2bj0_3d.js} +1 -1
  141. package/app/apps/web/.next/static/chunks/0m7dd-2zd9vl2.js +4 -0
  142. package/app/apps/web/.next/static/chunks/0nqklmbs5s3ax.js +6 -0
  143. package/app/apps/web/.next/static/chunks/{073081qv4uyn8.js → 0p--hzrway8~3.js} +1 -1
  144. package/app/apps/web/.next/static/chunks/{0gblp_v.kiu-..js → 0qv-gw888_5nu.js} +1 -1
  145. package/app/apps/web/.next/static/chunks/{14bjditmmrn7l.js → 0tirv_vo6q8uc.js} +1 -1
  146. package/app/apps/web/.next/static/chunks/0uyctl-m8iydb.js +1 -0
  147. package/app/apps/web/.next/static/chunks/0~qdw1b2uz._5.js +10 -0
  148. package/app/apps/web/.next/static/chunks/{0n0n.0279ot6c.js → 14vx702c32kn6.js} +1 -1
  149. package/app/apps/web/.next/static/chunks/{turbopack-0lb9w090w5ezx.js → turbopack-0mxu3~9vk.brh.js} +1 -1
  150. package/app/apps/web/app/api/digest/_shared/digest-route-helpers.ts +178 -0
  151. package/app/apps/web/app/api/digest/day/[date]/route.ts +34 -128
  152. package/app/apps/web/app/api/digest/month/[yearMonth]/route.ts +36 -121
  153. package/app/apps/web/app/api/digest/week/[startDate]/route.ts +36 -123
  154. package/app/apps/web/app/insights/page.tsx +20 -5
  155. package/app/apps/web/app/parallelism/burst-detail-modal.tsx +637 -0
  156. package/app/apps/web/app/parallelism/concurrency-info-modal.tsx +228 -0
  157. package/app/apps/web/app/parallelism/gantt-chart-utils.ts +49 -0
  158. package/app/apps/web/app/parallelism/gantt-chart.tsx +24 -903
  159. package/app/apps/web/app/sessions/[id]/session-view/colors.ts +31 -0
  160. package/app/apps/web/app/sessions/[id]/session-view/debug-list.tsx +78 -0
  161. package/app/apps/web/app/sessions/[id]/session-view/drawer.tsx +414 -0
  162. package/app/apps/web/app/sessions/[id]/session-view/entry-day-strip.tsx +124 -0
  163. package/app/apps/web/app/sessions/[id]/session-view/header-stats.tsx +217 -0
  164. package/app/apps/web/app/sessions/[id]/session-view/helpers.ts +135 -0
  165. package/app/apps/web/app/sessions/[id]/session-view/minimap.tsx +1587 -0
  166. package/app/apps/web/app/sessions/[id]/session-view/subagent-drawer.tsx +339 -0
  167. package/app/apps/web/app/sessions/[id]/session-view/token-stats.tsx +111 -0
  168. package/app/apps/web/app/sessions/[id]/session-view/tooltip.tsx +63 -0
  169. package/app/apps/web/app/sessions/[id]/session-view/types.ts +46 -0
  170. package/app/apps/web/app/sessions/[id]/session-view/workflows-panel.tsx +944 -0
  171. package/app/apps/web/app/sessions/[id]/session-view/workflows-shared.tsx +104 -0
  172. package/app/apps/web/app/sessions/[id]/session-view.tsx +1513 -5018
  173. package/app/apps/web/app/sessions/[id]/team-tab/minimap-hover-card.tsx +201 -0
  174. package/app/apps/web/app/sessions/[id]/team-tab/minimap-idle-band.tsx +53 -0
  175. package/app/apps/web/app/sessions/[id]/team-tab/minimap-shared.ts +20 -0
  176. package/app/apps/web/app/sessions/[id]/team-tab/team-minimap.tsx +10 -265
  177. package/app/apps/web/app/sessions/sessions-grid.tsx +10 -10
  178. package/app/apps/web/components/digest-actions.tsx +103 -0
  179. package/app/apps/web/components/job-queue-widget.tsx +1 -1
  180. package/app/apps/web/components/month-digest-view.tsx +19 -64
  181. package/app/apps/web/components/searchable-select.tsx +215 -0
  182. package/app/apps/web/components/tail-mode.tsx +46 -9
  183. package/app/apps/web/components/week-digest-view.tsx +16 -71
  184. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  185. package/app/apps/web/lib/entries-index.ts +7 -8
  186. package/app/apps/web/lib/entries.ts +0 -9
  187. package/app/apps/web/lib/format.test.ts +221 -0
  188. package/app/apps/web/lib/format.ts +17 -0
  189. package/app/apps/web/lib/utilization-tone.test.ts +56 -0
  190. package/app/apps/web/package.json +1 -1
  191. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  192. package/dist/daemon-worker.js +35 -43
  193. package/dist/index.js +37 -49
  194. package/package.json +1 -1
  195. package/app/apps/web/.next/server/chunks/[root-of-the-server]__04j3tng._.js +0 -9
  196. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0cnh3k4._.js +0 -9
  197. package/app/apps/web/.next/server/chunks/[root-of-the-server]__132eosx._.js +0 -9
  198. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__136-0me._.js +0 -8
  199. package/app/apps/web/.next/server/chunks/ssr/_0w.cv64._.js +0 -8
  200. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_01d-iwx._.js +0 -6
  201. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0-lmm4p._.js +0 -3
  202. package/app/apps/web/.next/static/chunks/05k84gif3ucxm.js +0 -6
  203. package/app/apps/web/.next/static/chunks/0nnjldasalwdu.js +0 -4
  204. package/app/apps/web/.next/static/chunks/0okg13phslr1..js +0 -4
  205. package/app/apps/web/.next/static/chunks/0pzt9vemtzct8.js +0 -10
  206. package/app/apps/web/.next/static/chunks/0qmh5da6gfm56.js +0 -1
  207. package/app/apps/web/.next/static/chunks/0rnay-a.-jr8-.js +0 -1
  208. package/app/apps/web/.next/static/chunks/0snv3-2ux2xvv.js +0 -6
  209. /package/app/apps/web/.next/static/{rbp9x3iPbzrz-wxS-DAU5 → bZs5UyzsYBqC6MFY5n-M_}/_buildManifest.js +0 -0
  210. /package/app/apps/web/.next/static/{rbp9x3iPbzrz-wxS-DAU5 → bZs5UyzsYBqC6MFY5n-M_}/_clientMiddlewareManifest.js +0 -0
  211. /package/app/apps/web/.next/static/{rbp9x3iPbzrz-wxS-DAU5 → bZs5UyzsYBqC6MFY5n-M_}/_ssgManifest.js +0 -0
@@ -0,0 +1,228 @@
1
+ "use client";
2
+
3
+ import { useEffect } from "react";
4
+
5
+ export function ConcurrencyInfoModal({ onClose }: { onClose: () => void }) {
6
+ // Close on ESC.
7
+ useEffect(() => {
8
+ const onKey = (e: KeyboardEvent) => {
9
+ if (e.key === "Escape") onClose();
10
+ };
11
+ window.addEventListener("keydown", onKey);
12
+ return () => window.removeEventListener("keydown", onKey);
13
+ }, [onClose]);
14
+
15
+ return (
16
+ <div
17
+ role="dialog"
18
+ aria-modal="true"
19
+ aria-labelledby="concurrency-modal-title"
20
+ onClick={onClose}
21
+ style={{
22
+ position: "fixed",
23
+ inset: 0,
24
+ zIndex: 200,
25
+ background: "rgba(0, 0, 0, 0.5)",
26
+ backdropFilter: "blur(4px)",
27
+ WebkitBackdropFilter: "blur(4px)",
28
+ display: "flex",
29
+ alignItems: "center",
30
+ justifyContent: "center",
31
+ padding: 20,
32
+ }}
33
+ >
34
+ <div
35
+ onClick={(e) => e.stopPropagation()}
36
+ style={{
37
+ background: "var(--af-surface-elevated)",
38
+ border: "1px solid var(--af-border-subtle)",
39
+ borderRadius: 12,
40
+ maxWidth: 560,
41
+ width: "100%",
42
+ maxHeight: "85vh",
43
+ overflow: "auto",
44
+ boxShadow: "0 16px 48px rgba(0, 0, 0, 0.3)",
45
+ }}
46
+ >
47
+ <div
48
+ style={{
49
+ display: "flex",
50
+ alignItems: "center",
51
+ justifyContent: "space-between",
52
+ padding: "18px 22px",
53
+ borderBottom: "1px solid var(--af-border-subtle)",
54
+ }}
55
+ >
56
+ <h2
57
+ id="concurrency-modal-title"
58
+ style={{
59
+ margin: 0,
60
+ fontSize: 16,
61
+ fontWeight: 700,
62
+ letterSpacing: "-0.01em",
63
+ }}
64
+ >
65
+ How concurrency is measured
66
+ </h2>
67
+ <button
68
+ type="button"
69
+ onClick={onClose}
70
+ aria-label="Close"
71
+ style={{
72
+ background: "transparent",
73
+ border: "none",
74
+ color: "var(--af-text-tertiary)",
75
+ fontSize: 22,
76
+ lineHeight: 1,
77
+ cursor: "pointer",
78
+ padding: 0,
79
+ width: 28,
80
+ height: 28,
81
+ }}
82
+ >
83
+ ×
84
+ </button>
85
+ </div>
86
+
87
+ <div
88
+ style={{
89
+ padding: "18px 22px",
90
+ fontSize: 13,
91
+ color: "var(--af-text-secondary)",
92
+ lineHeight: 1.55,
93
+ }}
94
+ >
95
+ <p style={{ margin: "0 0 14px" }}>
96
+ A <strong style={{ color: "var(--af-text)" }}>concurrency burst</strong>{" "}
97
+ is a window of time when two or more Claude Code sessions were
98
+ actively working in parallel. The goal is to surface moments
99
+ when you were running a multi-agent fleet — not every accidental
100
+ tab overlap.
101
+ </p>
102
+
103
+ <h3
104
+ style={{
105
+ margin: "18px 0 8px",
106
+ fontSize: 12,
107
+ fontWeight: 700,
108
+ color: "var(--af-text)",
109
+ textTransform: "uppercase",
110
+ letterSpacing: "0.04em",
111
+ }}
112
+ >
113
+ 1. What counts as &quot;active&quot;
114
+ </h3>
115
+ <p style={{ margin: "0 0 6px" }}>
116
+ Each session&apos;s events are split into{" "}
117
+ <strong style={{ color: "var(--af-text)" }}>active segments</strong> —
118
+ stretches of time where no gap between consecutive events exceeds{" "}
119
+ <strong style={{ color: "var(--af-text)" }}>3 minutes</strong>. Any longer
120
+ gap (walked away, laptop closed, thinking) splits the session
121
+ into separate segments.
122
+ </p>
123
+ <p style={{ margin: "0 0 6px", fontSize: 12, color: "var(--af-text-tertiary)" }}>
124
+ This is the same definition used for the &quot;active time&quot; metric on
125
+ the dashboard, so numbers stay consistent.
126
+ </p>
127
+
128
+ <h3
129
+ style={{
130
+ margin: "18px 0 8px",
131
+ fontSize: 12,
132
+ fontWeight: 700,
133
+ color: "var(--af-text)",
134
+ textTransform: "uppercase",
135
+ letterSpacing: "0.04em",
136
+ }}
137
+ >
138
+ 2. Detecting overlap
139
+ </h3>
140
+ <p style={{ margin: "0 0 6px" }}>
141
+ A sweep-line walks every segment start/end across all sessions.
142
+ Whenever the active count is ≥2, that stretch becomes a raw
143
+ overlap. The <strong style={{ color: "var(--af-text)" }}>peak</strong>{" "}
144
+ reported on each burst is the maximum active count reached
145
+ anywhere inside it.
146
+ </p>
147
+
148
+ <h3
149
+ style={{
150
+ margin: "18px 0 8px",
151
+ fontSize: 12,
152
+ fontWeight: 700,
153
+ color: "var(--af-text)",
154
+ textTransform: "uppercase",
155
+ letterSpacing: "0.04em",
156
+ }}
157
+ >
158
+ 3. Cleaning up noise
159
+ </h3>
160
+ <p style={{ margin: "0 0 6px" }}>
161
+ Raw overlaps are noisy — a typical day produces dozens of
162
+ sub-minute artifacts from switching between sessions. Two rules
163
+ collapse them into human-readable bursts:
164
+ </p>
165
+ <ul style={{ margin: "6px 0 0 0", paddingLeft: 22 }}>
166
+ <li style={{ marginBottom: 4 }}>
167
+ <strong style={{ color: "var(--af-text)" }}>Drop under 1 minute</strong> —
168
+ overlaps shorter than that are almost always tab-switch
169
+ artifacts, not real parallel work.
170
+ </li>
171
+ <li>
172
+ <strong style={{ color: "var(--af-text)" }}>Merge within 10 minutes</strong> —
173
+ two overlaps separated by less than 10 minutes of idle time
174
+ fuse into a single burst. A morning of back-and-forth agent
175
+ work becomes one burst, not forty.
176
+ </li>
177
+ </ul>
178
+
179
+ <h3
180
+ style={{
181
+ margin: "18px 0 8px",
182
+ fontSize: 12,
183
+ fontWeight: 700,
184
+ color: "var(--af-text)",
185
+ textTransform: "uppercase",
186
+ letterSpacing: "0.04em",
187
+ }}
188
+ >
189
+ 4. Same-project vs cross-project
190
+ </h3>
191
+ <p style={{ margin: "0 0 6px" }}>
192
+ Bursts are colored by whether the involved sessions span more
193
+ than one project directory.{" "}
194
+ <span style={{ color: "rgba(167, 139, 250, 1)", fontWeight: 600 }}>
195
+ Purple = cross-project
196
+ </span>{" "}
197
+ — different repos running at once, usually genuine fleet work.{" "}
198
+ <span style={{ color: "rgba(45, 212, 191, 1)", fontWeight: 600 }}>
199
+ Teal = same-project
200
+ </span>{" "}
201
+ — multiple sessions in one repo, usually context-switching
202
+ inside a single task.
203
+ </p>
204
+
205
+ <h3
206
+ style={{
207
+ margin: "18px 0 8px",
208
+ fontSize: 12,
209
+ fontWeight: 700,
210
+ color: "var(--af-text)",
211
+ textTransform: "uppercase",
212
+ letterSpacing: "0.04em",
213
+ }}
214
+ >
215
+ Why bursts, not runs
216
+ </h3>
217
+ <p style={{ margin: "0 0 6px" }}>
218
+ An earlier version reported every raw overlap as a separate
219
+ &quot;parallel run&quot;. On a busy day that produced 40–80 entries,
220
+ most of them seconds long, most of them meaningless. Bursts are
221
+ the unit humans actually think in: &quot;this morning I was
222
+ running 3 agents at once for about 20 minutes.&quot;
223
+ </p>
224
+ </div>
225
+ </div>
226
+ </div>
227
+ );
228
+ }
@@ -0,0 +1,49 @@
1
+ import { canonicalProjectName } from "@claude-lens/parser";
2
+
3
+ export const ROW_HEIGHT = 30;
4
+ export const ROW_GAP = 3;
5
+ export const LABEL_WIDTH = 220;
6
+ export const HEADER_HEIGHT = 26;
7
+ export const BURST_RIBBON_HEIGHT = 24;
8
+ export const MIN_CHART_WIDTH = 700;
9
+ export const PAD_MS = 30 * 60 * 1000; // 30-min padding on each side
10
+
11
+ export const PROJECT_COLORS = [
12
+ "rgba(45, 212, 191, 0.75)",
13
+ "rgba(167, 139, 250, 0.75)",
14
+ "rgba(248, 113, 113, 0.75)",
15
+ "rgba(52, 211, 153, 0.75)",
16
+ "rgba(251, 191, 36, 0.75)",
17
+ "rgba(236, 72, 153, 0.75)",
18
+ "rgba(34, 211, 238, 0.75)",
19
+ "rgba(168, 85, 247, 0.75)",
20
+ "rgba(244, 114, 82, 0.75)",
21
+ "rgba(96, 165, 250, 0.75)",
22
+ ];
23
+
24
+ /**
25
+ * Hash a project key to a stable color. The key should be a canonical
26
+ * project identity (not a raw projectDir) so all worktrees of the same
27
+ * repo share one color — visually grouping "this repo's parallel work".
28
+ */
29
+ export function projectColor(projectKey: string): string {
30
+ let hash = 0;
31
+ for (let i = 0; i < projectKey.length; i++) {
32
+ hash = ((hash << 5) - hash + projectKey.charCodeAt(i)) | 0;
33
+ }
34
+ return PROJECT_COLORS[Math.abs(hash) % PROJECT_COLORS.length]!;
35
+ }
36
+
37
+ /** Color for a Gantt session, keyed by canonical project name. */
38
+ export function sessionColor(s: { projectName: string }): string {
39
+ return projectColor(canonicalProjectName(s.projectName));
40
+ }
41
+
42
+ export function stripXml(s: string): string {
43
+ return s.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
44
+ }
45
+
46
+ export function fmtTime(ms: number): string {
47
+ const d = new Date(ms);
48
+ return `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}`;
49
+ }