fleetlens 0.6.4 → 0.7.1

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 (226) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +1 -0
  3. package/app/apps/web/.next/build-manifest.json +5 -5
  4. package/app/apps/web/.next/prerender-manifest.json +3 -3
  5. package/app/apps/web/.next/routes-manifest.json +6 -0
  6. package/app/apps/web/.next/server/app/_global-error/page/build-manifest.json +2 -2
  7. package/app/apps/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/app/apps/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/app/apps/web/.next/server/app/_not-found/page/build-manifest.json +2 -2
  17. package/app/apps/web/.next/server/app/_not-found/page.js +3 -3
  18. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/app/apps/web/.next/server/app/api/ask/route.js +2 -2
  21. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +3 -3
  23. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  24. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +3 -3
  25. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  26. package/app/apps/web/.next/server/app/api/digest/month-index/route.js +1 -1
  27. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +3 -3
  29. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/digest/week-index/route.js +1 -1
  31. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/api/events/route.js +2 -2
  33. package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
  34. package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -1
  35. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  36. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  37. package/app/apps/web/.next/server/app/api/settings/route.js +3 -3
  38. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  39. package/app/apps/web/.next/server/app/changelog/page/app-paths-manifest.json +3 -0
  40. package/app/apps/web/.next/server/app/changelog/page/build-manifest.json +17 -0
  41. package/app/apps/web/.next/server/app/changelog/page/next-font-manifest.json +6 -0
  42. package/app/apps/web/.next/server/app/changelog/page/react-loadable-manifest.json +1 -0
  43. package/app/apps/web/.next/server/app/changelog/page/server-reference-manifest.json +4 -0
  44. package/app/apps/web/.next/server/app/changelog/page.js +17 -0
  45. package/app/apps/web/.next/server/app/changelog/page.js.map +5 -0
  46. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -0
  47. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +3 -0
  48. package/app/apps/web/.next/server/app/day/[date]/page/build-manifest.json +2 -2
  49. package/app/apps/web/.next/server/app/day/[date]/page.js +4 -4
  50. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  51. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  52. package/app/apps/web/.next/server/app/day/page/build-manifest.json +2 -2
  53. package/app/apps/web/.next/server/app/day/page.js +3 -3
  54. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  55. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  56. package/app/apps/web/.next/server/app/digest/[date]/page/build-manifest.json +2 -2
  57. package/app/apps/web/.next/server/app/digest/[date]/page.js +3 -3
  58. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  59. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  60. package/app/apps/web/.next/server/app/digest/page/build-manifest.json +2 -2
  61. package/app/apps/web/.next/server/app/digest/page.js +3 -3
  62. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  63. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  64. package/app/apps/web/.next/server/app/insights/[key]/page/build-manifest.json +2 -2
  65. package/app/apps/web/.next/server/app/insights/[key]/page.js +3 -3
  66. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  67. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  68. package/app/apps/web/.next/server/app/insights/page/build-manifest.json +2 -2
  69. package/app/apps/web/.next/server/app/insights/page.js +3 -3
  70. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  71. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  72. package/app/apps/web/.next/server/app/page/build-manifest.json +2 -2
  73. package/app/apps/web/.next/server/app/page.js +4 -4
  74. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  75. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  76. package/app/apps/web/.next/server/app/parallelism/page/build-manifest.json +2 -2
  77. package/app/apps/web/.next/server/app/parallelism/page.js +3 -3
  78. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  79. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  80. package/app/apps/web/.next/server/app/projects/[slug]/page/build-manifest.json +2 -2
  81. package/app/apps/web/.next/server/app/projects/[slug]/page.js +4 -4
  82. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  83. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  84. package/app/apps/web/.next/server/app/projects/page/build-manifest.json +2 -2
  85. package/app/apps/web/.next/server/app/projects/page.js +4 -4
  86. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  87. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  88. package/app/apps/web/.next/server/app/runs/page/build-manifest.json +2 -2
  89. package/app/apps/web/.next/server/app/runs/page.js +3 -3
  90. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  91. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  92. package/app/apps/web/.next/server/app/sessions/[id]/page/build-manifest.json +2 -2
  93. package/app/apps/web/.next/server/app/sessions/[id]/page.js +4 -4
  94. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  95. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  96. package/app/apps/web/.next/server/app/sessions/page/build-manifest.json +2 -2
  97. package/app/apps/web/.next/server/app/sessions/page.js +4 -4
  98. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  99. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  100. package/app/apps/web/.next/server/app/settings/page/build-manifest.json +2 -2
  101. package/app/apps/web/.next/server/app/settings/page.js +3 -3
  102. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  103. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  104. package/app/apps/web/.next/server/app/usage/page/build-manifest.json +2 -2
  105. package/app/apps/web/.next/server/app/usage/page.js +3 -3
  106. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  107. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  108. package/app/apps/web/.next/server/app-paths-manifest.json +1 -0
  109. package/app/apps/web/.next/server/chunks/{[externals]__0o43ejh._.js → [externals]__0fpbr8-._.js} +2 -2
  110. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0-vgrh1._.js +1 -1
  111. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0.z48ue._.js +3 -0
  112. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0dctov1._.js +5 -0
  113. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0e8n_x4._.js +1 -1
  114. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0jprdks._.js +2 -2
  115. package/app/apps/web/.next/server/chunks/node_modules_next_036my~r._.js +1 -1
  116. package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ck.78s.js +1 -1
  117. package/app/apps/web/.next/server/chunks/packages_09hmrqx._.js +3 -0
  118. package/app/apps/web/.next/server/chunks/packages_118y1lp._.js +3 -0
  119. package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +26 -17
  120. package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_122oe0-.js +3 -0
  121. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0vvlth5._.js → [root-of-the-server]__02~v50d._.js} +2 -2
  122. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04eq6z2._.js +3 -0
  123. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__09rjz7_._.js +3 -0
  124. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0e.gxk3._.js +3 -0
  125. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0p1x6v2._.js +3 -0
  126. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +1 -1
  127. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0rvzdnx._.js +1 -1
  128. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0sp6.jt._.js +3 -0
  129. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0tejjy_._.js +3 -0
  130. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +3 -3
  131. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0wwa6gh._.js +1 -1
  132. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ytdqxt._.js +3 -0
  133. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0yv-a8z._.js +12 -0
  134. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__10~b4bf._.js +12 -0
  135. package/app/apps/web/.next/server/chunks/ssr/_02s1n-x._.js +1 -1
  136. package/app/apps/web/.next/server/chunks/ssr/_0woap-3._.js +1 -1
  137. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  138. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_changelog_page_actions_12_04gy.js +3 -0
  139. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_day_[date]_day-view_tsx_0wjoe1u._.js +1 -1
  140. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_settings_ai-features-form_tsx_01p699p._.js +1 -1
  141. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0ly1xes._.js +1 -1
  142. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0txtsv5._.js +1 -1
  143. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_changelog-mark-read_tsx_0hm41sv._.js +3 -0
  144. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0m67-xi._.js +3 -0
  145. package/app/apps/web/.next/server/chunks/ssr/{node_modules_0i2xw~e._.js → node_modules_0fx6-.x._.js} +2 -2
  146. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0uwo3v3.js +4 -0
  147. package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +1 -1
  148. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_10_oegc._.js +3 -0
  149. package/app/apps/web/.next/server/middleware-build-manifest.js +5 -5
  150. package/app/apps/web/.next/server/pages/500.html +1 -1
  151. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  152. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  153. package/app/apps/web/.next/static/chunks/0.3mqbj24kwtc.js +6 -0
  154. package/app/apps/web/.next/static/chunks/05b689hq3x49w.js +1 -0
  155. package/app/apps/web/.next/static/chunks/07-fq4im3pmjp.js +4 -0
  156. package/app/apps/web/.next/static/chunks/{0mykrrv810ra-.js → 0kjot8367asxe.js} +1 -1
  157. package/app/apps/web/.next/static/chunks/0n3-prt61k7pr.js +1 -0
  158. package/app/apps/web/.next/static/chunks/{0_7303jr0sf0w.js → 0q2vd~aj.1hpz.js} +3 -3
  159. package/app/apps/web/.next/static/chunks/0qmh5da6gfm56.js +1 -0
  160. package/app/apps/web/.next/static/chunks/{0k9pksi_i.odf.js → 111-bgx08j2nq.js} +1 -1
  161. package/app/apps/web/.next/static/chunks/179_t_igg8ghh.js +14 -0
  162. package/app/apps/web/.next/static/chunks/{turbopack-0_p36yduv.waj.js → turbopack-00w.w1u3c~d-6.js} +1 -1
  163. package/app/apps/web/app/api/ask/route.ts +1 -1
  164. package/app/apps/web/app/api/digest/week/[startDate]/route.ts +2 -1
  165. package/app/apps/web/app/api/settings/route.ts +1 -0
  166. package/app/apps/web/app/changelog/page.tsx +238 -0
  167. package/app/apps/web/app/insights/[key]/page.tsx +8 -2
  168. package/app/apps/web/app/layout.tsx +12 -7
  169. package/app/apps/web/app/page.tsx +19 -15
  170. package/app/apps/web/app/parallelism/gantt-chart.tsx +7 -18
  171. package/app/apps/web/app/projects/projects-view.tsx +3 -0
  172. package/app/apps/web/app/sessions/[id]/session-view.tsx +168 -41
  173. package/app/apps/web/app/sessions/page.tsx +22 -12
  174. package/app/apps/web/app/sessions/sessions-grid.tsx +82 -9
  175. package/app/apps/web/app/settings/ai-features-form.tsx +20 -1
  176. package/app/apps/web/app/settings/page.tsx +1 -0
  177. package/app/apps/web/app/usage/page.tsx +161 -52
  178. package/app/apps/web/components/agent-badge.tsx +43 -0
  179. package/app/apps/web/components/agent-icon.tsx +38 -0
  180. package/app/apps/web/components/agent-mix-chip.tsx +42 -0
  181. package/app/apps/web/components/{ask-claude.tsx → ask.tsx} +13 -12
  182. package/app/apps/web/components/changelog-icon.tsx +62 -0
  183. package/app/apps/web/components/changelog-mark-read.tsx +12 -0
  184. package/app/apps/web/components/day-digest.tsx +1 -1
  185. package/app/apps/web/components/live-sessions-widget.tsx +5 -1
  186. package/app/apps/web/components/outcome-pill.tsx +7 -2
  187. package/app/apps/web/components/sidebar.tsx +8 -1
  188. package/app/apps/web/components/week-digest.tsx +2 -0
  189. package/app/apps/web/lib/ai/session-summary.ts +1 -1
  190. package/app/apps/web/lib/calibration-data.ts +4 -64
  191. package/app/apps/web/lib/changelog-data.generated.ts +3 -0
  192. package/app/apps/web/lib/changelog.ts +67 -0
  193. package/app/apps/web/lib/cycle-peaks.test.ts +185 -0
  194. package/app/apps/web/lib/cycle-peaks.ts +104 -0
  195. package/app/apps/web/lib/data.ts +7 -8
  196. package/app/apps/web/lib/date-range.ts +9 -2
  197. package/app/apps/web/lib/usage-data.ts +24 -1
  198. package/app/apps/web/lib/validate-settings.ts +1 -0
  199. package/app/apps/web/package.json +1 -1
  200. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  201. package/dist/daemon-worker.js +3162 -2354
  202. package/dist/index.js +4419 -3742
  203. package/package.json +1 -1
  204. package/app/apps/web/.next/server/chunks/[externals]__0_xztrf._.js +0 -3
  205. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0455vu3._.js +0 -5
  206. package/app/apps/web/.next/server/chunks/packages_0e7q9u_._.js +0 -3
  207. package/app/apps/web/.next/server/chunks/packages_0n6p2ot._.js +0 -3
  208. package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_0bc7ptm.js +0 -3
  209. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0-94ji~._.js +0 -3
  210. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0_6.inc._.js +0 -3
  211. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gio_ck._.js +0 -3
  212. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0jdyefm._.js +0 -12
  213. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ln9jsw._.js +0 -3
  214. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0u5d7de._.js +0 -12
  215. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~_8vff._.js +0 -3
  216. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__11v.eqw._.js +0 -3
  217. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_usage-data_ts_0xtv99n._.js +0 -3
  218. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0-jvt~a._.js +0 -3
  219. package/app/apps/web/.next/static/chunks/04m3slg_5ph02.js +0 -1
  220. package/app/apps/web/.next/static/chunks/0coa1800xqgfj.js +0 -1
  221. package/app/apps/web/.next/static/chunks/0k1psab.bybh9.js +0 -14
  222. package/app/apps/web/.next/static/chunks/0xfu09fn_358k.js +0 -4
  223. package/app/apps/web/.next/static/chunks/17u2ww8ya5dv1.js +0 -6
  224. /package/app/apps/web/.next/static/{2jcMG-92q2XKei8dN7BMd → tiK9aMHXkgnKLNmxj9J1P}/_buildManifest.js +0 -0
  225. /package/app/apps/web/.next/static/{2jcMG-92q2XKei8dN7BMd → tiK9aMHXkgnKLNmxj9J1P}/_clientMiddlewareManifest.js +0 -0
  226. /package/app/apps/web/.next/static/{2jcMG-92q2XKei8dN7BMd → tiK9aMHXkgnKLNmxj9J1P}/_ssgManifest.js +0 -0
@@ -0,0 +1,238 @@
1
+ import { Fragment } from "react";
2
+ import { ENTRIES, LATEST_VERSION, type ChangelogEntry } from "@/lib/changelog";
3
+ import { ChangelogMarkRead } from "@/components/changelog-mark-read";
4
+
5
+ export const metadata = { title: "Changelog · Fleetlens" };
6
+
7
+ const SECTION_TONES: Record<string, { fg: string; bg: string }> = {
8
+ fixed: { fg: "#c4673b", bg: "rgba(196, 103, 59, 0.12)" },
9
+ added: { fg: "#3a8b5e", bg: "rgba(58, 139, 94, 0.12)" },
10
+ changed: { fg: "#5b6cc4", bg: "rgba(91, 108, 196, 0.12)" },
11
+ removed: { fg: "#a64545", bg: "rgba(166, 69, 69, 0.12)" },
12
+ };
13
+ const DEFAULT_TONE = { fg: "var(--af-text-tertiary)", bg: "var(--af-surface-hover)" };
14
+
15
+ export default function ChangelogPage() {
16
+ return (
17
+ <main style={{ maxWidth: 720, margin: "0 auto", padding: "32px 24px" }}>
18
+ <ChangelogMarkRead version={LATEST_VERSION} />
19
+ <header style={{ marginBottom: 28 }}>
20
+ <h1 style={{ fontSize: 22, fontWeight: 700, letterSpacing: "-0.01em", margin: 0 }}>
21
+ Changelog
22
+ </h1>
23
+ <p style={{ color: "var(--af-text-secondary)", fontSize: 13, marginTop: 6 }}>
24
+ Notable user-facing changes to the Fleetlens CLI.
25
+ </p>
26
+ </header>
27
+
28
+ {ENTRIES.length === 0 ? (
29
+ <p style={{ color: "var(--af-text-tertiary)", fontSize: 13 }}>
30
+ No releases recorded yet.
31
+ </p>
32
+ ) : (
33
+ <div>
34
+ {ENTRIES.map((entry, idx) => {
35
+ const prevDate = idx > 0 ? ENTRIES[idx - 1].date : null;
36
+ const showDateHeader = entry.date && entry.date !== prevDate;
37
+ return (
38
+ <Fragment key={entry.version}>
39
+ {showDateHeader && (
40
+ <DateHeader date={entry.date!} firstInList={idx === 0} />
41
+ )}
42
+ <EntryCard entry={entry} isLatest={idx === 0} />
43
+ </Fragment>
44
+ );
45
+ })}
46
+ </div>
47
+ )}
48
+ </main>
49
+ );
50
+ }
51
+
52
+ function DateHeader({ date, firstInList }: { date: string; firstInList: boolean }) {
53
+ const rel = relativeDate(date);
54
+ return (
55
+ <div
56
+ style={{
57
+ display: "flex",
58
+ alignItems: "baseline",
59
+ gap: 10,
60
+ marginTop: firstInList ? 0 : 22,
61
+ marginBottom: 10,
62
+ borderTop: firstInList ? "none" : "1px solid var(--af-border-subtle)",
63
+ paddingTop: firstInList ? 0 : 18,
64
+ }}
65
+ >
66
+ <span
67
+ style={{
68
+ fontSize: 11,
69
+ color: "var(--af-text-tertiary)",
70
+ textTransform: "uppercase",
71
+ letterSpacing: "0.08em",
72
+ fontWeight: 600,
73
+ fontFamily: "var(--font-mono)",
74
+ }}
75
+ >
76
+ {date}
77
+ </span>
78
+ {rel && (
79
+ <span style={{ fontSize: 11, color: "var(--af-text-tertiary)" }}>{rel}</span>
80
+ )}
81
+ </div>
82
+ );
83
+ }
84
+
85
+ function EntryCard({ entry, isLatest }: { entry: ChangelogEntry; isLatest: boolean }) {
86
+ const simple =
87
+ entry.sections.length === 1 && entry.sections[0].bullets.length === 1;
88
+
89
+ return (
90
+ <section id={`v${entry.version}`} style={{ marginBottom: 18 }}>
91
+ <div
92
+ style={{
93
+ display: "flex",
94
+ alignItems: "center",
95
+ gap: 8,
96
+ flexWrap: "wrap",
97
+ marginBottom: 8,
98
+ }}
99
+ >
100
+ <h2
101
+ style={{
102
+ fontSize: 15,
103
+ fontWeight: 700,
104
+ margin: 0,
105
+ fontFamily: "var(--font-mono)",
106
+ letterSpacing: "0.01em",
107
+ }}
108
+ >
109
+ v{entry.version}
110
+ </h2>
111
+ {simple && <SectionPill kind={entry.sections[0].kind} />}
112
+ {isLatest && <LatestPill />}
113
+ </div>
114
+
115
+ {entry.sections.length === 0 ? (
116
+ <p style={{ color: "var(--af-text-tertiary)", fontSize: 13 }}>
117
+ No details recorded.
118
+ </p>
119
+ ) : simple ? (
120
+ <p
121
+ style={{
122
+ margin: 0,
123
+ fontSize: 13.5,
124
+ color: "var(--af-text)",
125
+ lineHeight: 1.55,
126
+ }}
127
+ >
128
+ {renderInline(entry.sections[0].bullets[0])}
129
+ </p>
130
+ ) : (
131
+ entry.sections.map((s) => (
132
+ <div key={s.kind} style={{ marginBottom: 10 }}>
133
+ <div
134
+ style={{
135
+ fontSize: 11,
136
+ color: "var(--af-text-tertiary)",
137
+ textTransform: "uppercase",
138
+ letterSpacing: "0.06em",
139
+ fontWeight: 600,
140
+ marginBottom: 5,
141
+ }}
142
+ >
143
+ {s.kind}
144
+ </div>
145
+ <ul
146
+ style={{
147
+ margin: 0,
148
+ paddingLeft: 22,
149
+ fontSize: 13.5,
150
+ color: "var(--af-text)",
151
+ lineHeight: 1.55,
152
+ listStyleType: "disc",
153
+ }}
154
+ >
155
+ {s.bullets.map((b, i) => (
156
+ <li key={i} style={{ marginBottom: 6 }}>{renderInline(b)}</li>
157
+ ))}
158
+ </ul>
159
+ </div>
160
+ ))
161
+ )}
162
+ </section>
163
+ );
164
+ }
165
+
166
+ function SectionPill({ kind }: { kind: string }) {
167
+ const tone = SECTION_TONES[kind.toLowerCase()] ?? DEFAULT_TONE;
168
+ return (
169
+ <span
170
+ style={{
171
+ fontSize: 10,
172
+ fontWeight: 600,
173
+ textTransform: "uppercase",
174
+ letterSpacing: "0.08em",
175
+ padding: "2px 7px",
176
+ borderRadius: 99,
177
+ background: tone.bg,
178
+ color: tone.fg,
179
+ }}
180
+ >
181
+ {kind}
182
+ </span>
183
+ );
184
+ }
185
+
186
+ function LatestPill() {
187
+ return (
188
+ <span
189
+ style={{
190
+ fontSize: 10,
191
+ fontWeight: 500,
192
+ padding: "2px 7px",
193
+ borderRadius: 99,
194
+ background: "var(--af-surface-hover)",
195
+ color: "var(--af-text-tertiary)",
196
+ fontFamily: "var(--font-mono)",
197
+ letterSpacing: "0.02em",
198
+ }}
199
+ >
200
+ latest
201
+ </span>
202
+ );
203
+ }
204
+
205
+ function renderInline(text: string): React.ReactNode[] {
206
+ const parts = text.split(/(`[^`]+`)/g);
207
+ return parts.map((p, i) => {
208
+ if (p.startsWith("`") && p.endsWith("`") && p.length >= 2) {
209
+ return (
210
+ <code
211
+ key={i}
212
+ style={{
213
+ fontFamily: "var(--font-mono)",
214
+ background: "var(--af-surface-hover)",
215
+ padding: "1px 5px",
216
+ borderRadius: 4,
217
+ fontSize: "0.92em",
218
+ }}
219
+ >
220
+ {p.slice(1, -1)}
221
+ </code>
222
+ );
223
+ }
224
+ return <span key={i}>{p}</span>;
225
+ });
226
+ }
227
+
228
+ function relativeDate(date: string): string | null {
229
+ const t = Date.parse(`${date}T12:00:00`);
230
+ if (Number.isNaN(t)) return null;
231
+ const days = Math.round((Date.now() - t) / 86_400_000);
232
+ if (days < 0) return null;
233
+ if (days === 0) return "today";
234
+ if (days === 1) return "yesterday";
235
+ if (days < 14) return `${days} days ago`;
236
+ if (days < 60) return `${Math.round(days / 7)} weeks ago`;
237
+ return null;
238
+ }
@@ -23,8 +23,14 @@ export default async function SavedInsightPage({
23
23
  const weekMatch = WEEK_KEY.exec(key);
24
24
  if (weekMatch) {
25
25
  const monday = weekMatch[1]!;
26
- const cached = monday === currentWeekMonday()
27
- ? getCurrentWeekDigestFromCache(monday, Date.now())
26
+ // Current-week digests live in an in-memory TTL cache by default. When
27
+ // the user explicitly forces generation we ALSO persist to disk
28
+ // (digest-week-pipeline) so the result survives across Next.js route
29
+ // bundles — fall back to disk here so the page actually reads what
30
+ // they paid the LLM to produce.
31
+ const isCurrent = monday === currentWeekMonday();
32
+ const cached = isCurrent
33
+ ? (getCurrentWeekDigestFromCache(monday, Date.now()) ?? readWeekDigest(monday))
28
34
  : readWeekDigest(monday);
29
35
 
30
36
  const prev = shiftMonday(monday, -7);
@@ -8,29 +8,32 @@ import {
8
8
  type LiveEntrySummary,
9
9
  } from "@/components/live-sessions-widget";
10
10
  import { JobQueueWidget } from "@/components/job-queue-widget";
11
- import { listProjects, listSessions, walkJsonlFiles } from "@claude-lens/parser/fs";
11
+ import { listProjects, walkJsonlFiles } from "@claude-lens/parser/fs";
12
+ import { listSessions } from "@/lib/data";
12
13
  import { latestUsageSnapshot } from "@/lib/usage-data";
13
14
  import { buildEntriesIndex } from "@/lib/entries-index";
15
+ import { LATEST_VERSION as LATEST_CHANGELOG_VERSION } from "@/lib/changelog";
14
16
  import pkg from "../package.json" with { type: "json" };
15
17
  import "./globals.css";
16
18
 
17
19
  export const metadata: Metadata = {
18
20
  title: "Fleetlens",
19
- description: "Claude Code fleet analytics — local-only dashboard for sessions and agent fleets.",
21
+ description: "Multi-agent fleet analytics — local-only dashboard for Claude Code, Codex, and other coding-agent sessions.",
20
22
  };
21
23
 
22
24
  export const dynamic = "force-dynamic";
23
25
 
24
26
  export default async function RootLayout({ children }: { children: React.ReactNode }) {
25
- const [projects, allFiles, recentSessions, entriesIndex] = await Promise.all([
27
+ const [projects, allFiles, allSessions, entriesIndex] = await Promise.all([
26
28
  listProjects(),
27
29
  walkJsonlFiles(),
28
- // Only need the newest-mtime slice — the widget filters to the 45s
29
- // live window client-side.
30
- listSessions({ limit: 20 }),
30
+ // Pull from every registered agent source. The widget filters to the
31
+ // 45s live window client-side, so the slice is on freshness, not count.
32
+ listSessions(),
31
33
  buildEntriesIndex(),
32
34
  ]);
33
- const totalSessions = allFiles.length;
35
+ const recentSessions = allSessions.slice(0, 20);
36
+ const totalSessions = allSessions.length;
34
37
  const currentUsage = latestUsageSnapshot();
35
38
 
36
39
  // Project to the minimal shape the widget needs so we don't ship
@@ -45,6 +48,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
45
48
  lastTimestamp: s.lastTimestamp,
46
49
  teamName: s.teamName,
47
50
  agentName: s.agentName,
51
+ agent: s.agent,
48
52
  }));
49
53
 
50
54
  const liveEntrySummaries: Record<string, LiveEntrySummary> = {};
@@ -82,6 +86,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
82
86
  totalSessions={totalSessions}
83
87
  currentUsage={currentUsage}
84
88
  version={pkg.version}
89
+ latestChangelogVersion={LATEST_CHANGELOG_VERSION}
85
90
  />
86
91
  <main
87
92
  style={{
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Dashboard home — high-level metrics across all Claude Code sessions.
2
+ * Dashboard home — high-level metrics across every observed agent.
3
3
  *
4
4
  * Everything here is server-rendered from @claude-lens/parser/fs, then
5
5
  * passed down to small interactive client components (heatmap, chart).
@@ -7,6 +7,8 @@
7
7
 
8
8
  import {
9
9
  groupByProject,
10
+ type AgentKind,
11
+ agentMetadata,
10
12
  type SessionMeta,
11
13
  } from "@claude-lens/parser";
12
14
  import { DashboardView } from "@/components/dashboard-view";
@@ -110,19 +112,21 @@ export default async function DashboardHome({
110
112
  </h1>
111
113
  <p style={{ fontSize: 13, color: "var(--af-text-secondary)", marginTop: 4 }}>
112
114
  {sessions.length} of {allSessions.length} session
113
- {allSessions.length === 1 ? "" : "s"}, read from{" "}
114
- <code
115
- style={{
116
- fontFamily: "var(--font-mono)",
117
- fontSize: 11,
118
- background: "var(--af-border-subtle)",
119
- padding: "1px 6px",
120
- borderRadius: 4,
121
- }}
122
- >
123
- ~/.claude/projects
124
- </code>
125
- .
115
+ {allSessions.length === 1 ? "" : "s"} across{" "}
116
+ {(() => {
117
+ const counts = new Map<AgentKind, number>();
118
+ for (const s of allSessions) {
119
+ const k = (s.agent ?? "claude-code") as AgentKind;
120
+ counts.set(k, (counts.get(k) ?? 0) + 1);
121
+ }
122
+ const parts = agentMetadata
123
+ .map((m) => {
124
+ const n = counts.get(m.kind) ?? 0;
125
+ return n > 0 ? `${n} ${m.displayName}` : null;
126
+ })
127
+ .filter((s): s is string => s !== null);
128
+ return parts.length ? parts.join(" + ") : "no observed agents yet";
129
+ })()}.
126
130
  </p>
127
131
  </div>
128
132
  <DateRangeFilter current={range} />
@@ -246,7 +250,7 @@ export default async function DashboardHome({
246
250
  </div>
247
251
  <div>
248
252
  {recentSessions.length === 0 ? (
249
- <div className="af-empty">No sessions found in ~/.claude/projects</div>
253
+ <div className="af-empty">No sessions found from any registered agent source.</div>
250
254
  ) : (
251
255
  recentSessions.map((s) => (
252
256
  <Link
@@ -10,7 +10,8 @@ import {
10
10
  } from "@claude-lens/parser";
11
11
  import type { DayOutcome, EntryEnrichmentStatus } from "@claude-lens/entries";
12
12
  import { formatDuration, formatTokens, prettyProjectName } from "@/lib/format";
13
- import { OutcomePill, OUTCOME_STYLES } from "@/components/outcome-pill";
13
+ import { OutcomePill } from "@/components/outcome-pill";
14
+ import { AgentIcon } from "@/components/agent-icon";
14
15
 
15
16
  export type SessionEntrySummary = {
16
17
  outcome: DayOutcome | null;
@@ -643,21 +644,8 @@ export function GanttChart({
643
644
  flexShrink: 0,
644
645
  }}
645
646
  />
646
- {(() => {
647
- const sum = sessionEntries[session.id];
648
- if (sum?.outcome) {
649
- return (
650
- <span
651
- title={OUTCOME_STYLES[sum.outcome]?.label ?? sum.outcome}
652
- style={{ fontSize: 11, lineHeight: 1, flexShrink: 0 }}
653
- aria-hidden
654
- >
655
- {OUTCOME_STYLES[sum.outcome]?.icon ?? ""}
656
- </span>
657
- );
658
- }
659
- return null;
660
- })()}
647
+ <AgentIcon agent={session.agent} size={11} />
648
+
661
649
  <Link
662
650
  href={`/sessions/${session.id}`}
663
651
  style={{
@@ -841,7 +829,7 @@ export function GanttChart({
841
829
  if (sum.outcome) {
842
830
  return (
843
831
  <div style={{ marginBottom: 6 }}>
844
- <OutcomePill outcome={sum.outcome} size="sm" />
832
+ <OutcomePill outcome={sum.outcome} size="sm" agent={hover.session.agent} />
845
833
  </div>
846
834
  );
847
835
  }
@@ -854,6 +842,7 @@ export function GanttChart({
854
842
  sessionId={hover.session.id}
855
843
  localDay={sum.localDay}
856
844
  size="sm"
845
+ agent={hover.session.agent}
857
846
  />
858
847
  </div>
859
848
  );
@@ -1761,7 +1750,7 @@ function BurstDetailModal({
1761
1750
  {(() => {
1762
1751
  const sum = sessionEntries[s.id];
1763
1752
  if (sum?.outcome) {
1764
- return <OutcomePill outcome={sum.outcome} size="sm" label="text" />;
1753
+ return <OutcomePill outcome={sum.outcome} size="sm" label="text" agent={s.agent} />;
1765
1754
  }
1766
1755
  return null;
1767
1756
  })()}
@@ -8,6 +8,7 @@ import { formatDuration, formatRelative, formatTokens, prettyProjectName } from
8
8
  import { DataTable, type Column } from "@/components/data-table";
9
9
  import { useViewToggle } from "@/components/view-toggle";
10
10
  import { OutcomeMixRow } from "@/components/outcome-mix-row";
11
+ import { AgentMixChip } from "@/components/agent-mix-chip";
11
12
 
12
13
  export type ProjectRow = {
13
14
  project: ProjectRollup;
@@ -63,6 +64,7 @@ const projectTableColumns: Column<ProjectRow>[] = [
63
64
  >
64
65
  {prettyProjectName(r.project.projectName)}
65
66
  {r.project.worktreeCount > 0 && <WorktreeBadge count={r.project.worktreeCount} />}
67
+ <AgentMixChip perAgent={r.project.perAgent} />
66
68
  </div>
67
69
  <div
68
70
  style={{
@@ -203,6 +205,7 @@ function ProjectCard({ row }: { row: ProjectRow }) {
203
205
  {prettyProjectName(p.projectName)}
204
206
  </span>
205
207
  {p.worktreeCount > 0 && <WorktreeBadge count={p.worktreeCount} />}
208
+ <AgentMixChip perAgent={p.perAgent} />
206
209
  </div>
207
210
  <div
208
211
  style={{ fontSize: 11, color: "var(--af-text-tertiary)", fontFamily: "var(--font-mono)" }}