fleetlens 0.3.0 → 0.4.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 (210) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +9 -0
  3. package/app/apps/web/.next/build-manifest.json +6 -6
  4. package/app/apps/web/.next/prerender-manifest.json +3 -3
  5. package/app/apps/web/.next/routes-manifest.json +62 -0
  6. package/app/apps/web/.next/server/app/_global-error/page/build-manifest.json +3 -3
  7. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  8. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/app/apps/web/.next/server/app/_not-found/page/build-manifest.json +3 -3
  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 +3 -2
  18. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/api/events/route.js +1 -0
  20. package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
  21. package/app/apps/web/.next/server/app/api/insights/months-index/route/app-paths-manifest.json +3 -0
  22. package/app/apps/web/.next/server/app/api/insights/months-index/route/build-manifest.json +9 -0
  23. package/app/apps/web/.next/server/app/api/insights/months-index/route/server-reference-manifest.json +4 -0
  24. package/app/apps/web/.next/server/app/api/insights/months-index/route.js +7 -0
  25. package/app/apps/web/.next/server/app/api/insights/months-index/route.js.map +5 -0
  26. package/app/apps/web/.next/server/app/api/insights/months-index/route.js.nft.json +1 -0
  27. package/app/apps/web/.next/server/app/api/insights/months-index/route_client-reference-manifest.js +3 -0
  28. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route/app-paths-manifest.json +3 -0
  29. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route/build-manifest.json +9 -0
  30. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route/server-reference-manifest.json +4 -0
  31. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route.js +6 -0
  32. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route.js.map +5 -0
  33. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route.js.nft.json +1 -0
  34. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route_client-reference-manifest.js +3 -0
  35. package/app/apps/web/.next/server/app/api/insights/route/app-paths-manifest.json +3 -0
  36. package/app/apps/web/.next/server/app/api/insights/route/build-manifest.json +9 -0
  37. package/app/apps/web/.next/server/app/api/insights/route/server-reference-manifest.json +4 -0
  38. package/app/apps/web/.next/server/app/api/insights/route.js +8 -0
  39. package/app/apps/web/.next/server/app/api/insights/route.js.map +5 -0
  40. package/app/apps/web/.next/server/app/api/insights/route.js.nft.json +1 -0
  41. package/app/apps/web/.next/server/app/api/insights/route_client-reference-manifest.js +3 -0
  42. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route/app-paths-manifest.json +3 -0
  43. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route/build-manifest.json +9 -0
  44. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route/server-reference-manifest.json +4 -0
  45. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route.js +6 -0
  46. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route.js.map +5 -0
  47. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route.js.nft.json +1 -0
  48. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route_client-reference-manifest.js +3 -0
  49. package/app/apps/web/.next/server/app/api/insights/saved/route/app-paths-manifest.json +3 -0
  50. package/app/apps/web/.next/server/app/api/insights/saved/route/build-manifest.json +9 -0
  51. package/app/apps/web/.next/server/app/api/insights/saved/route/server-reference-manifest.json +4 -0
  52. package/app/apps/web/.next/server/app/api/insights/saved/route.js +6 -0
  53. package/app/apps/web/.next/server/app/api/insights/saved/route.js.map +5 -0
  54. package/app/apps/web/.next/server/app/api/insights/saved/route.js.nft.json +1 -0
  55. package/app/apps/web/.next/server/app/api/insights/saved/route_client-reference-manifest.js +3 -0
  56. package/app/apps/web/.next/server/app/api/insights/weeks-index/route/app-paths-manifest.json +3 -0
  57. package/app/apps/web/.next/server/app/api/insights/weeks-index/route/build-manifest.json +9 -0
  58. package/app/apps/web/.next/server/app/api/insights/weeks-index/route/server-reference-manifest.json +4 -0
  59. package/app/apps/web/.next/server/app/api/insights/weeks-index/route.js +7 -0
  60. package/app/apps/web/.next/server/app/api/insights/weeks-index/route.js.map +5 -0
  61. package/app/apps/web/.next/server/app/api/insights/weeks-index/route.js.nft.json +1 -0
  62. package/app/apps/web/.next/server/app/api/insights/weeks-index/route_client-reference-manifest.js +3 -0
  63. package/app/apps/web/.next/server/app/insights/[key]/page/app-paths-manifest.json +3 -0
  64. package/app/apps/web/.next/server/app/insights/[key]/page/build-manifest.json +17 -0
  65. package/app/apps/web/.next/server/app/insights/[key]/page/next-font-manifest.json +6 -0
  66. package/app/apps/web/.next/server/app/insights/[key]/page/react-loadable-manifest.json +1 -0
  67. package/app/apps/web/.next/server/app/insights/[key]/page/server-reference-manifest.json +4 -0
  68. package/app/apps/web/.next/server/app/insights/[key]/page.js +16 -0
  69. package/app/apps/web/.next/server/app/insights/[key]/page.js.map +5 -0
  70. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -0
  71. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +3 -0
  72. package/app/apps/web/.next/server/app/insights/page/app-paths-manifest.json +3 -0
  73. package/app/apps/web/.next/server/app/insights/page/build-manifest.json +17 -0
  74. package/app/apps/web/.next/server/app/insights/page/next-font-manifest.json +6 -0
  75. package/app/apps/web/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
  76. package/app/apps/web/.next/server/app/insights/page/server-reference-manifest.json +4 -0
  77. package/app/apps/web/.next/server/app/insights/page.js +16 -0
  78. package/app/apps/web/.next/server/app/insights/page.js.map +5 -0
  79. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -0
  80. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +3 -0
  81. package/app/apps/web/.next/server/app/insights/print/[key]/page/app-paths-manifest.json +3 -0
  82. package/app/apps/web/.next/server/app/insights/print/[key]/page/build-manifest.json +17 -0
  83. package/app/apps/web/.next/server/app/insights/print/[key]/page/next-font-manifest.json +6 -0
  84. package/app/apps/web/.next/server/app/insights/print/[key]/page/react-loadable-manifest.json +1 -0
  85. package/app/apps/web/.next/server/app/insights/print/[key]/page/server-reference-manifest.json +4 -0
  86. package/app/apps/web/.next/server/app/insights/print/[key]/page.js +16 -0
  87. package/app/apps/web/.next/server/app/insights/print/[key]/page.js.map +5 -0
  88. package/app/apps/web/.next/server/app/insights/print/[key]/page.js.nft.json +1 -0
  89. package/app/apps/web/.next/server/app/insights/print/[key]/page_client-reference-manifest.js +3 -0
  90. package/app/apps/web/.next/server/app/page/build-manifest.json +3 -3
  91. package/app/apps/web/.next/server/app/page.js +1 -1
  92. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  93. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  94. package/app/apps/web/.next/server/app/parallelism/page/build-manifest.json +3 -3
  95. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  96. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  97. package/app/apps/web/.next/server/app/projects/[slug]/page/build-manifest.json +3 -3
  98. package/app/apps/web/.next/server/app/projects/[slug]/page.js +1 -2
  99. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  100. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  101. package/app/apps/web/.next/server/app/projects/page/build-manifest.json +3 -3
  102. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  103. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  104. package/app/apps/web/.next/server/app/sessions/[id]/page/build-manifest.json +3 -3
  105. package/app/apps/web/.next/server/app/sessions/[id]/page.js +1 -2
  106. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  107. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  108. package/app/apps/web/.next/server/app/sessions/page/build-manifest.json +3 -3
  109. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  110. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  111. package/app/apps/web/.next/server/app/usage/page/build-manifest.json +3 -3
  112. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  113. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  114. package/app/apps/web/.next/server/app-paths-manifest.json +9 -0
  115. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_months-index_route_actions_0~h~zci.js +3 -0
  116. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_saved_[key]_route_actions_0a5j9yw.js +3 -0
  117. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_weeks-index_route_actions_0hh-1c7.js +3 -0
  118. package/app/apps/web/.next/server/chunks/{[externals]__0rv9ct5._.js → [externals]__0_xztrf._.js} +2 -2
  119. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0.hmj0z._.js +3 -0
  120. package/app/apps/web/.next/server/chunks/[root-of-the-server]__01h_g-p._.js +3 -0
  121. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0nh-z10._.js +3 -0
  122. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0op9af~._.js +1 -1
  123. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0ri7q~r._.js +3 -0
  124. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0rr1~~x._.js +3 -0
  125. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0s0gv.0._.js +3 -0
  126. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_pdf_[key]_route_actions_0lu-lnx.js +3 -0
  127. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_route_actions_0h8l5lz.js +3 -0
  128. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_saved_route_actions_13rlblw.js +3 -0
  129. package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_00t2xj6.js +68 -0
  130. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0sgyieh._.js → node_modules_next_dist_esm_build_templates_app-route_0ck.78s.js} +5 -5
  131. package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_0bc7ptm.js +3 -0
  132. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__00z7zlm._.js +1 -1
  133. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__08.d5ia._.js +12 -0
  134. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0b323~k._.js +8 -0
  135. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0euu8sa._.js +3 -0
  136. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gio_ck._.js +3 -0
  137. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gx-4qa._.js +3 -0
  138. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +3 -3
  139. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0z45d0g._.js +49 -0
  140. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__13itnvx._.js +3 -0
  141. package/app/apps/web/.next/server/chunks/ssr/_0r~__0v._.js +12 -0
  142. package/app/apps/web/.next/server/chunks/ssr/_0xies90._.js +1 -1
  143. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_insights_[key]_page_actions_0_z2~e_.js +3 -0
  144. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_insights_page_actions_0zjdm~n.js +3 -0
  145. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_insights_print_[key]_page_actions_0a853fw.js +3 -0
  146. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_06j3c.0._.js +1 -1
  147. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_insight-report_tsx_13q2a-c._.js +12 -0
  148. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_insights-view_tsx_11730ta._.js +6 -0
  149. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0-lmm4p._.js +3 -0
  150. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0nqz8dw._.js +3 -0
  151. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js +3 -0
  152. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0vz7_px.js +4 -0
  153. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10cdrh2.js +4 -0
  154. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12n1lw_.js +4 -0
  155. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0-jvt~a._.js +1 -1
  156. package/app/apps/web/.next/server/functions-config-manifest.json +7 -1
  157. package/app/apps/web/.next/server/middleware-build-manifest.js +6 -6
  158. package/app/apps/web/.next/server/pages/500.html +1 -1
  159. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  160. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  161. package/app/apps/web/.next/static/chunks/03_7xtpi9sv4g.js +4 -0
  162. package/app/apps/web/.next/static/chunks/08c1pcrocqq5s.js +6 -0
  163. package/app/apps/web/.next/static/chunks/0e-wrhqh4h3r5.js +2 -0
  164. package/app/apps/web/.next/static/chunks/0i7er7_bfab36.js +10 -0
  165. package/app/apps/web/.next/static/chunks/0ipytyi01h0ta.js +1 -0
  166. package/app/apps/web/.next/static/chunks/0u-n8fz-ms.ee.js +6 -0
  167. package/app/apps/web/.next/static/chunks/137uw2-qbro07.js +31 -0
  168. package/app/apps/web/.next/static/chunks/{0p1lpoh02zh8h.js → 15w5_bct86ut6.js} +3 -3
  169. package/app/apps/web/.next/static/chunks/{turbopack-17n9y8y0h4q9f.js → turbopack-169w-1._23ra_.js} +1 -1
  170. package/app/apps/web/app/api/insights/months-index/route.ts +80 -0
  171. package/app/apps/web/app/api/insights/pdf/[key]/route.ts +45 -0
  172. package/app/apps/web/app/api/insights/route.ts +508 -0
  173. package/app/apps/web/app/api/insights/saved/[key]/route.ts +11 -0
  174. package/app/apps/web/app/api/insights/saved/route.ts +9 -0
  175. package/app/apps/web/app/api/insights/weeks-index/route.ts +95 -0
  176. package/app/apps/web/app/insights/[key]/page.tsx +59 -0
  177. package/app/apps/web/app/insights/page.tsx +7 -0
  178. package/app/apps/web/app/insights/print/[key]/page.tsx +73 -0
  179. package/app/apps/web/app/sessions/[id]/session-view.tsx +450 -21
  180. package/app/apps/web/components/insight-report.tsx +1031 -0
  181. package/app/apps/web/components/insights-view.tsx +647 -0
  182. package/app/apps/web/components/live-refresher.tsx +11 -2
  183. package/app/apps/web/components/sidebar.tsx +8 -0
  184. package/app/apps/web/eslint.config.mjs +2 -0
  185. package/app/apps/web/lib/ai/chrome-pdf.ts +64 -0
  186. package/app/apps/web/lib/ai/insights-prompt.ts +71 -0
  187. package/app/apps/web/lib/ai/saved-reports.ts +83 -0
  188. package/app/apps/web/lib/date-range.ts +11 -2
  189. package/app/apps/web/lib/use-live-events.ts +7 -2
  190. package/app/apps/web/package.json +3 -2
  191. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  192. package/dist/daemon-worker.js +2852 -11
  193. package/dist/index.js +3091 -268
  194. package/package.json +5 -3
  195. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__05lbtny._.js +0 -12
  196. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ms7h0~._.js +0 -8
  197. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0p~g4m6._.js +0 -3
  198. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0wvzyl7._.js +0 -3
  199. package/app/apps/web/.next/server/chunks/ssr/_0ph19-k._.js +0 -12
  200. package/app/apps/web/.next/server/chunks/ssr/_0u29mdd._.js +0 -3
  201. package/app/apps/web/.next/server/chunks/ssr/node_modules_0i2xw~e._.js +0 -3
  202. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0.knjn.._.js +0 -3
  203. package/app/apps/web/.next/static/chunks/0257pdz1-imal.js +0 -2
  204. package/app/apps/web/.next/static/chunks/08983lz4~hffx.js +0 -6
  205. package/app/apps/web/.next/static/chunks/0qmh881w772ef.js +0 -31
  206. package/app/apps/web/.next/static/chunks/0wdga7zbwvg70.js +0 -1
  207. package/app/apps/web/.next/static/chunks/14q3xsfpkvuef.js +0 -6
  208. /package/app/apps/web/.next/static/{0fPDRTdMQ-Y62h6fHNJXL → 95-RytHk7ZQtfpZj5BLST}/_buildManifest.js +0 -0
  209. /package/app/apps/web/.next/static/{0fPDRTdMQ-Y62h6fHNJXL → 95-RytHk7ZQtfpZj5BLST}/_clientMiddlewareManifest.js +0 -0
  210. /package/app/apps/web/.next/static/{0fPDRTdMQ-Y62h6fHNJXL → 95-RytHk7ZQtfpZj5BLST}/_ssgManifest.js +0 -0
@@ -0,0 +1,11 @@
1
+ import { getSavedReport } from "@/lib/ai/saved-reports";
2
+
3
+ export const dynamic = "force-dynamic";
4
+ export const runtime = "nodejs";
5
+
6
+ export async function GET(_req: Request, ctx: { params: Promise<{ key: string }> }) {
7
+ const { key } = await ctx.params;
8
+ const report = await getSavedReport(key);
9
+ if (!report) return Response.json({ error: "not found" }, { status: 404 });
10
+ return Response.json({ report });
11
+ }
@@ -0,0 +1,9 @@
1
+ import { listSavedReports } from "@/lib/ai/saved-reports";
2
+
3
+ export const dynamic = "force-dynamic";
4
+ export const runtime = "nodejs";
5
+
6
+ export async function GET() {
7
+ const reports = await listSavedReports();
8
+ return Response.json({ reports });
9
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Weeks index — drives the week picker in /insights.
3
+ *
4
+ * Returns the last N calendar weeks (Mon-Sun, newest first) with:
5
+ * - isoweek + period label
6
+ * - session count observed in that window (raw SessionMeta filter)
7
+ * - in_progress flag for this week
8
+ * - saved_key when a report exists on disk
9
+ * - archetype_label + sessions_used from the saved report, for display
10
+ */
11
+ import { listSessions } from "@claude-lens/parser/fs";
12
+ import { calendarWeek, priorCalendarWeek } from "@claude-lens/parser";
13
+ import { listSavedReports, type SavedReportMeta } from "@/lib/ai/saved-reports";
14
+
15
+ export const dynamic = "force-dynamic";
16
+ export const runtime = "nodejs";
17
+
18
+ type WeekRow = {
19
+ iso_week: number;
20
+ start: string; // "2026-04-13"
21
+ end: string;
22
+ label: string; // "Apr 13 – Apr 19"
23
+ sessions: number;
24
+ in_progress: boolean;
25
+ saved_key: string | null;
26
+ archetype_label?: string;
27
+ sessions_used?: number;
28
+ prs?: number;
29
+ };
30
+
31
+ function isoDay(d: Date): string {
32
+ const y = d.getFullYear();
33
+ const m = String(d.getMonth() + 1).padStart(2, "0");
34
+ const day = String(d.getDate()).padStart(2, "0");
35
+ return `${y}-${m}-${day}`;
36
+ }
37
+
38
+ function isoWeekNo(d: Date): number {
39
+ const t = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
40
+ t.setUTCDate(t.getUTCDate() + 4 - (t.getUTCDay() || 7));
41
+ const yearStart = new Date(Date.UTC(t.getUTCFullYear(), 0, 1));
42
+ return Math.ceil((((t.getTime() - yearStart.getTime()) / 86_400_000) + 1) / 7);
43
+ }
44
+
45
+ function label(start: Date, end: Date): string {
46
+ const fmt = (d: Date) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
47
+ return `${fmt(start)} – ${fmt(end)}`;
48
+ }
49
+
50
+ export async function GET(req: Request) {
51
+ const url = new URL(req.url);
52
+ const count = Math.min(26, Math.max(1, parseInt(url.searchParams.get("count") ?? "12", 10)));
53
+
54
+ const [metas, saved] = await Promise.all([listSessions({ limit: 10000 }), listSavedReports()]);
55
+ const savedByKey = new Map<string, SavedReportMeta>(saved.map((s) => [s.key, s]));
56
+
57
+ const current = calendarWeek();
58
+ const prior = priorCalendarWeek();
59
+
60
+ const weeks: WeekRow[] = [];
61
+ for (let i = 0; i < count; i++) {
62
+ let start: Date, end: Date, in_progress: boolean;
63
+ if (i === 0) {
64
+ start = current.start; end = current.end; in_progress = true;
65
+ } else {
66
+ const offset = (i - 1) * 7;
67
+ start = new Date(prior.start); start.setDate(prior.start.getDate() - offset);
68
+ end = new Date(prior.end); end.setDate(prior.end.getDate() - offset);
69
+ in_progress = false;
70
+ }
71
+ const startMs = start.getTime();
72
+ const endMs = new Date(end).setHours(23, 59, 59, 999);
73
+ const sessions = metas.filter((m) => {
74
+ if (!m.firstTimestamp) return false;
75
+ const t = Date.parse(m.firstTimestamp);
76
+ return !Number.isNaN(t) && t >= startMs && t <= endMs;
77
+ }).length;
78
+ const startKey = isoDay(start);
79
+ const savedMeta = savedByKey.get(`week-${startKey}`);
80
+ weeks.push({
81
+ iso_week: isoWeekNo(start),
82
+ start: startKey,
83
+ end: isoDay(end),
84
+ label: label(start, end),
85
+ sessions,
86
+ in_progress,
87
+ saved_key: savedMeta ? savedMeta.key : null,
88
+ archetype_label: savedMeta?.archetype_label,
89
+ sessions_used: savedMeta?.sessions_used,
90
+ prs: savedMeta?.prs,
91
+ });
92
+ }
93
+
94
+ return Response.json({ weeks });
95
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Saved-report viewer. Deep-linkable, bookmarkable, server-rendered.
3
+ *
4
+ * /insights → history + picker (client-state machine)
5
+ * /insights/[key] → this page — reads the saved JSON off disk
6
+ * /insights/print/[key] → headless-Chrome target for PDF export
7
+ */
8
+ import Link from "next/link";
9
+ import { notFound } from "next/navigation";
10
+ import { ArrowLeft } from "lucide-react";
11
+ import { InsightReport } from "@/components/insight-report";
12
+ import { getSavedReport } from "@/lib/ai/saved-reports";
13
+
14
+ export const dynamic = "force-dynamic";
15
+
16
+ export default async function SavedInsightPage({
17
+ params,
18
+ }: { params: Promise<{ key: string }> }) {
19
+ const { key } = await params;
20
+ const report = await getSavedReport(key);
21
+ if (!report) notFound();
22
+
23
+ return (
24
+ <div>
25
+ <div className="no-print" style={topNavStyle}>
26
+ <Link href="/insights" style={backBtnStyle}>
27
+ <ArrowLeft size={12} /> Reports
28
+ </Link>
29
+ <span style={{ fontSize: 11, color: "var(--af-text-tertiary)", fontFamily: "var(--font-mono)" }}>
30
+ saved · key: {key}
31
+ </span>
32
+ </div>
33
+ <InsightReport data={report} savedKey={key} />
34
+ </div>
35
+ );
36
+ }
37
+
38
+ const topNavStyle: React.CSSProperties = {
39
+ maxWidth: 980,
40
+ margin: "0 auto",
41
+ padding: "16px 44px 0",
42
+ display: "flex",
43
+ alignItems: "center",
44
+ gap: 12,
45
+ };
46
+
47
+ const backBtnStyle: React.CSSProperties = {
48
+ display: "inline-flex",
49
+ alignItems: "center",
50
+ gap: 6,
51
+ padding: "7px 12px",
52
+ border: "1px solid var(--af-border)",
53
+ borderRadius: 8,
54
+ background: "var(--af-surface)",
55
+ color: "var(--af-text)",
56
+ fontSize: 12,
57
+ fontWeight: 500,
58
+ textDecoration: "none",
59
+ };
@@ -0,0 +1,7 @@
1
+ import { InsightsView } from "@/components/insights-view";
2
+
3
+ export const dynamic = "force-dynamic";
4
+
5
+ export default function InsightsPage() {
6
+ return <InsightsView />;
7
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Print-mode rendering target for `/api/insights/pdf/[key]`.
3
+ *
4
+ * Server-renders the saved report with the sidebar and floating widgets
5
+ * hidden, light theme forced, and print-optimised spacing. Chrome headless
6
+ * points at this URL when generating the PDF.
7
+ */
8
+ import { notFound } from "next/navigation";
9
+ import { InsightReport } from "@/components/insight-report";
10
+ import { getSavedReport } from "@/lib/ai/saved-reports";
11
+
12
+ export const dynamic = "force-dynamic";
13
+
14
+ export default async function PrintInsightPage({
15
+ params,
16
+ }: { params: Promise<{ key: string }> }) {
17
+ const { key } = await params;
18
+ const report = await getSavedReport(key);
19
+ if (!report) notFound();
20
+
21
+ return (
22
+ <div data-theme="light" data-print-mode="true" style={{ background: "white" }}>
23
+ <style>{`
24
+ /* Neutralise the root-layout viewport lock so content paginates freely. */
25
+ html, body {
26
+ height: auto !important;
27
+ min-height: 0 !important;
28
+ overflow: visible !important;
29
+ background: white !important;
30
+ margin: 0 !important;
31
+ padding: 0 !important;
32
+ }
33
+ body > div[style*="height: 100vh"],
34
+ body > div[style*="height:100vh"] {
35
+ display: block !important;
36
+ height: auto !important;
37
+ min-height: 0 !important;
38
+ }
39
+ main {
40
+ flex: none !important;
41
+ padding: 0 !important;
42
+ margin: 0 !important;
43
+ width: 100% !important;
44
+ min-height: 0 !important;
45
+ overflow: visible !important;
46
+ }
47
+
48
+ /* Hide everything that isn't the report itself. */
49
+ aside, [data-sidebar], .af-sidebar,
50
+ [data-live-refresher], .af-live-widget,
51
+ nav[aria-label="Main"], header[data-app-header] { display: none !important; }
52
+ .no-print { display: none !important; }
53
+
54
+ /* Report layout tuned for letter paper. */
55
+ .report-root {
56
+ max-width: none !important;
57
+ margin: 0 !important;
58
+ padding: 36px 48px 48px !important;
59
+ color: var(--af-text) !important;
60
+ }
61
+ .report-root section { page-break-inside: auto; }
62
+ .report-root section > header,
63
+ .report-root [role="heading"],
64
+ .report-root h1, .report-root h2, .report-root h3 {
65
+ page-break-after: avoid;
66
+ break-after: avoid;
67
+ }
68
+ @page { size: letter; margin: 0.4in; }
69
+ `}</style>
70
+ <InsightReport data={report} />
71
+ </div>
72
+ );
73
+ }