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
@@ -1 +1 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/0qmh881w772ef.js","static/chunks/0pqt~8bl3ukh4.js","static/chunks/0l4e3as18eexy.js","static/chunks/0257pdz1-imal.js"],runtimeModuleIds:[94553]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=function(){if(null!=self.TURBOPACK_ASSET_SUFFIX)return self.TURBOPACK_ASSET_SUFFIX;let e=document?.currentScript?.getAttribute?.("src")??"",t=e.indexOf("?");return t>=0?e.slice(t):""}(),n=["NEXT_DEPLOYMENT_ID","NEXT_CLIENT_ASSET_SUFFIX"];var o,l=((o=l||{})[o.Runtime=0]="Runtime",o[o.Parent=1]="Parent",o[o.Update=2]="Update",o);let i=new WeakMap;function s(e,t){this.m=e,this.e=t}let u=s.prototype,a=Object.prototype.hasOwnProperty,c="u">typeof Symbol&&Symbol.toStringTag;function f(e,t,r){a.call(e,t)||Object.defineProperty(e,t,r)}function p(e,t){let r=e[t];return r||(r=h(t),e[t]=r),r}function h(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function d(e,t){f(e,"__esModule",{value:!0}),c&&f(e,c,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)f(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?f(e,n,{get:o,set:t[r++],enumerable:!0}):f(e,n,{get:o,enumerable:!0})}Object.seal(e)}function m(e,t){(null!=t?p(this.c,t):this.m).exports=e}u.s=function(e,t){let r,n;null!=t?n=(r=p(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,d(n,e)},u.j=function(e,t){var r,n;let o,l,s;null!=t?l=(o=p(this.c,t)).exports:(o=this.m,l=this.e);let u=(r=o,n=l,(s=i.get(r))||(i.set(r,s=[]),r.exports=r.namespaceObject=new Proxy(n,{get(e,t){if(a.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of s){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of s)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),s);"object"==typeof e&&null!==e&&u.push(e)},u.v=m,u.n=function(e,t){let r;(r=null!=t?p(this.c,t):this.m).exports=r.namespaceObject=e};let b=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,y=[null,b({}),b([]),b(b)];function g(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!y.includes(t);t=b(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),d(t,n),t}function O(e){let t=B(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=g(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function w(e){let t=e.indexOf("#");-1!==t&&(e=e.substring(0,t));let r=e.indexOf("?");return -1!==r&&(e=e.substring(0,r)),e}function k(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}u.i=O,u.A=function(e){return this.r(e)(O.bind(this))},u.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},u.r=function(e){return B(e,this.m).exports},u.f=function(e){function t(t){if(t=w(t),a.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(t=w(t),a.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let j=Symbol("turbopack queues"),U=Symbol("turbopack exports"),C=Symbol("turbopack error");function P(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}u.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:l,reject:i,promise:s}=k(),u=Object.assign(s,{[U]:r.exports,[j]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[U]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(j in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[U]:{},[j]:e=>e(t)};return e.then(e=>{r[U]=e,P(t)},e=>{r[C]=e,P(t)}),r}}return{[U]:e,[j]:()=>{}}}),r=()=>t.map(e=>{if(e[C])throw e[C];return e[U]}),{promise:l,resolve:i}=k(),s=Object.assign(()=>i(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[j](u)),s.queueCount?l:r()},function(e){e?i(u[C]=e):l(u[U]),P(n)}),n&&-1===n.status&&(n.status=0)};let v=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function R(e,t){throw Error(`Invariant: ${t(e)}`)}v.prototype=URL.prototype,u.U=v,u.z=function(e){throw Error("dynamic usage of require is not supported")},u.g=globalThis;let S=s.prototype,$=new Map;u.M=$;let E=new Map,_=new Map;async function T(e,t,r){let n;if("string"==typeof r)return M(e,t,q(r));let o=r.included||[],l=o.map(e=>!!$.has(e)||E.get(e));if(l.length>0&&l.every(e=>e))return void await Promise.all(l);let i=r.moduleChunks||[],s=i.map(e=>_.get(e)).filter(e=>e);if(s.length>0){if(s.length===i.length)return void await Promise.all(s);let r=new Set;for(let e of i)_.has(e)||r.add(e);for(let n of r){let r=M(e,t,q(n));_.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=M(e,t,q(r.path)),i))_.has(o)||_.set(o,n)}for(let e of o)E.has(e)||E.set(e,n);await n}S.l=function(e){return T(l.Parent,this.m.id,e)};let A=Promise.resolve(void 0),x=new WeakMap;function M(t,r,n){let o=e.loadChunkCached(t,n),i=x.get(o);if(void 0===i){let e=x.set.bind(x,o,A);i=o.then(e).catch(e=>{let o;switch(t){case l.Runtime:o=`as a runtime dependency of chunk ${r}`;break;case l.Parent:o=`from module ${r}`;break;case l.Update:o="from an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}let i=Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0);throw i.name="ChunkLoadError",i}),x.set(o,i)}return i}function q(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}${r}`}S.L=function(e){return M(l.Parent,this.m.id,e)},S.R=function(e){let t=this.r(e);return t?.default??t},S.P=function(e){return`/ROOT/${e??""}`},S.q=function(e,t){m.call(this,`${e}${r}`,t)},S.b=function(e,t,o,l){let i="SharedWorker"===e.name,s=[o.map(e=>q(e)).reverse(),r];for(let e of n)s.push(globalThis[e]);let u=new URL(q(t),location.origin),a=JSON.stringify(s);return i?u.searchParams.set("params",a):u.hash="#params="+encodeURIComponent(a),new e(u,l?{...l,type:void 0}:void 0)};let N=/\.js(?:\?[^#]*)?(?:#.*)?$/,K=/\.css(?:\?[^#]*)?(?:#.*)?$/;function L(e){return K.test(e)}u.w=function(t,r,n){return e.loadWebAssembly(l.Parent,this.m.id,t,r,n)},u.u=function(t,r){return e.loadWebAssemblyModule(l.Parent,this.m.id,t,r)};let I={};u.c=I;let B=(e,t)=>{let r=I[e];if(r){if(r.error)throw r.error;return r}return W(e,l.Parent,t.id)};function W(e,t,r){let n=$.get(e);if("function"!=typeof n)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let o=h(e),l=o.exports;I[e]=o;let i=new s(o,l);try{n(i,o,l)}catch(e){throw o.error=e,e}return o.namespaceObject&&o.exports!==o.namespaceObject&&g(o.exports,o.namespaceObject),o}function F(t){let r,n=function(e){if("string"==typeof e)return e;if(e)return{src:e.getAttribute("src")};if("u">typeof TURBOPACK_NEXT_CHUNK_URLS)return{src:TURBOPACK_NEXT_CHUNK_URLS.pop()};throw Error("chunk path empty but not in a worker")}(t[0]);return 2===t.length?r=t[1]:(r=void 0,!function(e,t){let r=1;for(;r<e.length;){let n,o=r+1;for(;o<e.length&&"function"!=typeof e[o];)o++;if(o===e.length)throw Error("malformed chunk format, expected a factory function");let l=e[o];for(let l=r;l<o;l++){let r=e[l],o=t.get(r);if(o){n=o;break}}let i=n??l,s=!1;for(let n=r;n<o;n++){let r=e[n];t.has(r)||(s||(i===l&&Object.defineProperty(l,"name",{value:"module evaluation"}),s=!0),t.set(r,i))}r=o+1}}(t,$)),e.registerChunk(n,r)}let X=new Map;function D(e){let t=X.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},X.set(e,t)}return t}e={async registerChunk(e,r){let n=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(e.src.replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(e);if(D("string"==typeof e?q(e):e.src).resolve(),null!=r){for(let e of r.otherChunks)D(q("string"==typeof e?e:e.path));if(await Promise.all(r.otherChunks.map(e=>T(l.Runtime,n,e))),r.runtimeModuleIds.length>0)for(let e of r.runtimeModuleIds)!function(e,t){let r=I[t];if(r){if(r.error)throw r.error;return}W(t,l.Runtime,e)}(n,e)}},loadChunkCached:(e,t)=>(function(e,t){let r=D(t);if(r.loadingStarted)return r.promise;if(e===l.Runtime)return r.loadingStarted=!0,L(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(L(t));else if(N.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(L(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(N.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let l=fetch(q(r)),{instance:i}=await WebAssembly.instantiateStreaming(l,o);return i.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(q(r));return await WebAssembly.compileStreaming(o)}};let H=globalThis.TURBOPACK;globalThis.TURBOPACK={push:F},H.forEach(F)})();
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/137uw2-qbro07.js","static/chunks/0pqt~8bl3ukh4.js","static/chunks/0l4e3as18eexy.js","static/chunks/0e-wrhqh4h3r5.js"],runtimeModuleIds:[94553]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=function(){if(null!=self.TURBOPACK_ASSET_SUFFIX)return self.TURBOPACK_ASSET_SUFFIX;let e=document?.currentScript?.getAttribute?.("src")??"",t=e.indexOf("?");return t>=0?e.slice(t):""}(),n=["NEXT_DEPLOYMENT_ID","NEXT_CLIENT_ASSET_SUFFIX"];var o,l=((o=l||{})[o.Runtime=0]="Runtime",o[o.Parent=1]="Parent",o[o.Update=2]="Update",o);let i=new WeakMap;function s(e,t){this.m=e,this.e=t}let u=s.prototype,a=Object.prototype.hasOwnProperty,c="u">typeof Symbol&&Symbol.toStringTag;function f(e,t,r){a.call(e,t)||Object.defineProperty(e,t,r)}function p(e,t){let r=e[t];return r||(r=h(t),e[t]=r),r}function h(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function d(e,t){f(e,"__esModule",{value:!0}),c&&f(e,c,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)f(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?f(e,n,{get:o,set:t[r++],enumerable:!0}):f(e,n,{get:o,enumerable:!0})}Object.seal(e)}function m(e,t){(null!=t?p(this.c,t):this.m).exports=e}u.s=function(e,t){let r,n;null!=t?n=(r=p(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,d(n,e)},u.j=function(e,t){var r,n;let o,l,s;null!=t?l=(o=p(this.c,t)).exports:(o=this.m,l=this.e);let u=(r=o,n=l,(s=i.get(r))||(i.set(r,s=[]),r.exports=r.namespaceObject=new Proxy(n,{get(e,t){if(a.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of s){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of s)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),s);"object"==typeof e&&null!==e&&u.push(e)},u.v=m,u.n=function(e,t){let r;(r=null!=t?p(this.c,t):this.m).exports=r.namespaceObject=e};let b=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,y=[null,b({}),b([]),b(b)];function g(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!y.includes(t);t=b(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),d(t,n),t}function w(e){let t=B(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=g(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function O(e){let t=e.indexOf("#");-1!==t&&(e=e.substring(0,t));let r=e.indexOf("?");return -1!==r&&(e=e.substring(0,r)),e}function k(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}u.i=w,u.A=function(e){return this.r(e)(w.bind(this))},u.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},u.r=function(e){return B(e,this.m).exports},u.f=function(e){function t(t){if(t=O(t),a.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(t=O(t),a.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let j=Symbol("turbopack queues"),U=Symbol("turbopack exports"),C=Symbol("turbopack error");function P(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}u.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:l,reject:i,promise:s}=k(),u=Object.assign(s,{[U]:r.exports,[j]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[U]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(j in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[U]:{},[j]:e=>e(t)};return e.then(e=>{r[U]=e,P(t)},e=>{r[C]=e,P(t)}),r}}return{[U]:e,[j]:()=>{}}}),r=()=>t.map(e=>{if(e[C])throw e[C];return e[U]}),{promise:l,resolve:i}=k(),s=Object.assign(()=>i(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[j](u)),s.queueCount?l:r()},function(e){e?i(u[C]=e):l(u[U]),P(n)}),n&&-1===n.status&&(n.status=0)};let v=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function R(e,t){throw Error(`Invariant: ${t(e)}`)}v.prototype=URL.prototype,u.U=v,u.z=function(e){throw Error("dynamic usage of require is not supported")},u.g=globalThis;let S=s.prototype,$=new Map;u.M=$;let E=new Map,_=new Map;async function T(e,t,r){let n;if("string"==typeof r)return M(e,t,q(r));let o=r.included||[],l=o.map(e=>!!$.has(e)||E.get(e));if(l.length>0&&l.every(e=>e))return void await Promise.all(l);let i=r.moduleChunks||[],s=i.map(e=>_.get(e)).filter(e=>e);if(s.length>0){if(s.length===i.length)return void await Promise.all(s);let r=new Set;for(let e of i)_.has(e)||r.add(e);for(let n of r){let r=M(e,t,q(n));_.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=M(e,t,q(r.path)),i))_.has(o)||_.set(o,n)}for(let e of o)E.has(e)||E.set(e,n);await n}S.l=function(e){return T(l.Parent,this.m.id,e)};let A=Promise.resolve(void 0),x=new WeakMap;function M(t,r,n){let o=e.loadChunkCached(t,n),i=x.get(o);if(void 0===i){let e=x.set.bind(x,o,A);i=o.then(e).catch(e=>{let o;switch(t){case l.Runtime:o=`as a runtime dependency of chunk ${r}`;break;case l.Parent:o=`from module ${r}`;break;case l.Update:o="from an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}let i=Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0);throw i.name="ChunkLoadError",i}),x.set(o,i)}return i}function q(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}${r}`}S.L=function(e){return M(l.Parent,this.m.id,e)},S.R=function(e){let t=this.r(e);return t?.default??t},S.P=function(e){return`/ROOT/${e??""}`},S.q=function(e,t){m.call(this,`${e}${r}`,t)},S.b=function(e,t,o,l){let i="SharedWorker"===e.name,s=[o.map(e=>q(e)).reverse(),r];for(let e of n)s.push(globalThis[e]);let u=new URL(q(t),location.origin),a=JSON.stringify(s);return i?u.searchParams.set("params",a):u.hash="#params="+encodeURIComponent(a),new e(u,l?{...l,type:void 0}:void 0)};let N=/\.js(?:\?[^#]*)?(?:#.*)?$/,K=/\.css(?:\?[^#]*)?(?:#.*)?$/;function L(e){return K.test(e)}u.w=function(t,r,n){return e.loadWebAssembly(l.Parent,this.m.id,t,r,n)},u.u=function(t,r){return e.loadWebAssemblyModule(l.Parent,this.m.id,t,r)};let I={};u.c=I;let B=(e,t)=>{let r=I[e];if(r){if(r.error)throw r.error;return r}return W(e,l.Parent,t.id)};function W(e,t,r){let n=$.get(e);if("function"!=typeof n)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:R(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let o=h(e),l=o.exports;I[e]=o;let i=new s(o,l);try{n(i,o,l)}catch(e){throw o.error=e,e}return o.namespaceObject&&o.exports!==o.namespaceObject&&g(o.exports,o.namespaceObject),o}function F(t){let r,n=function(e){if("string"==typeof e)return e;if(e)return{src:e.getAttribute("src")};if("u">typeof TURBOPACK_NEXT_CHUNK_URLS)return{src:TURBOPACK_NEXT_CHUNK_URLS.pop()};throw Error("chunk path empty but not in a worker")}(t[0]);return 2===t.length?r=t[1]:(r=void 0,!function(e,t){let r=1;for(;r<e.length;){let n,o=r+1;for(;o<e.length&&"function"!=typeof e[o];)o++;if(o===e.length)throw Error("malformed chunk format, expected a factory function");let l=e[o];for(let l=r;l<o;l++){let r=e[l],o=t.get(r);if(o){n=o;break}}let i=n??l,s=!1;for(let n=r;n<o;n++){let r=e[n];t.has(r)||(s||(i===l&&Object.defineProperty(l,"name",{value:"module evaluation"}),s=!0),t.set(r,i))}r=o+1}}(t,$)),e.registerChunk(n,r)}let X=new Map;function D(e){let t=X.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},X.set(e,t)}return t}e={async registerChunk(e,r){let n=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(e.src.replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(e);if(D("string"==typeof e?q(e):e.src).resolve(),null!=r){for(let e of r.otherChunks)D(q("string"==typeof e?e:e.path));if(await Promise.all(r.otherChunks.map(e=>T(l.Runtime,n,e))),r.runtimeModuleIds.length>0)for(let e of r.runtimeModuleIds)!function(e,t){let r=I[t];if(r){if(r.error)throw r.error;return}W(t,l.Runtime,e)}(n,e)}},loadChunkCached:(e,t)=>(function(e,t){let r=D(t);if(r.loadingStarted)return r.promise;if(e===l.Runtime)return r.loadingStarted=!0,L(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(L(t));else if(N.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(L(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(N.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let l=fetch(q(r)),{instance:i}=await WebAssembly.instantiateStreaming(l,o);return i.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(q(r));return await WebAssembly.compileStreaming(o)}};let H=globalThis.TURBOPACK;globalThis.TURBOPACK={push:F},H.forEach(F)})();
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Months index — drives the month picker in /insights.
3
+ *
4
+ * Returns the last N calendar months (newest first), with session count
5
+ * observed in that window, in_progress flag for the current month, and
6
+ * saved_key lookup (`month-YYYY-MM-01` convention).
7
+ */
8
+ import { listSessions } from "@claude-lens/parser/fs";
9
+ import { calendarMonth } from "@claude-lens/parser";
10
+ import { listSavedReports, type SavedReportMeta } from "@/lib/ai/saved-reports";
11
+
12
+ export const dynamic = "force-dynamic";
13
+ export const runtime = "nodejs";
14
+
15
+ type MonthRow = {
16
+ year: number;
17
+ month: number; // 1-12
18
+ start: string; // "2026-03-01"
19
+ end: string; // "2026-03-31"
20
+ label: string; // "March 2026"
21
+ sessions: number;
22
+ in_progress: boolean;
23
+ saved_key: string | null;
24
+ archetype_label?: string;
25
+ sessions_used?: number;
26
+ prs?: number;
27
+ };
28
+
29
+ function isoDay(d: Date): string {
30
+ const y = d.getFullYear();
31
+ const m = String(d.getMonth() + 1).padStart(2, "0");
32
+ const day = String(d.getDate()).padStart(2, "0");
33
+ return `${y}-${m}-${day}`;
34
+ }
35
+
36
+ export async function GET(req: Request) {
37
+ const url = new URL(req.url);
38
+ const count = Math.min(24, Math.max(1, parseInt(url.searchParams.get("count") ?? "6", 10)));
39
+
40
+ const [metas, saved] = await Promise.all([listSessions({ limit: 10000 }), listSavedReports()]);
41
+ const savedByKey = new Map<string, SavedReportMeta>(saved.map((s) => [s.key, s]));
42
+
43
+ const now = new Date();
44
+ const currentMonth = calendarMonth(now);
45
+
46
+ const months: MonthRow[] = [];
47
+ for (let i = 0; i < count; i++) {
48
+ const anchor = new Date(now.getFullYear(), now.getMonth() - i, 15);
49
+ const { start, end } = calendarMonth(anchor);
50
+ const in_progress =
51
+ start.getFullYear() === currentMonth.start.getFullYear()
52
+ && start.getMonth() === currentMonth.start.getMonth();
53
+
54
+ const startMs = start.getTime();
55
+ const endMs = new Date(end).setHours(23, 59, 59, 999);
56
+ const sessions = metas.filter((m) => {
57
+ if (!m.firstTimestamp) return false;
58
+ const t = Date.parse(m.firstTimestamp);
59
+ return !Number.isNaN(t) && t >= startMs && t <= endMs;
60
+ }).length;
61
+
62
+ const startKey = isoDay(start);
63
+ const savedMeta = savedByKey.get(`month-${startKey}`);
64
+ months.push({
65
+ year: start.getFullYear(),
66
+ month: start.getMonth() + 1,
67
+ start: startKey,
68
+ end: isoDay(end),
69
+ label: start.toLocaleDateString("en-US", { month: "long", year: "numeric" }),
70
+ sessions,
71
+ in_progress,
72
+ saved_key: savedMeta ? savedMeta.key : null,
73
+ archetype_label: savedMeta?.archetype_label,
74
+ sessions_used: savedMeta?.sessions_used,
75
+ prs: savedMeta?.prs,
76
+ });
77
+ }
78
+
79
+ return Response.json({ months });
80
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Renders a saved insight report to PDF via headless Chrome and streams
3
+ * the bytes back. The actual HTML is served by
4
+ * `/insights/print/[key]/page.tsx`; this route just drives the browser.
5
+ */
6
+ import { getSavedReport } from "@/lib/ai/saved-reports";
7
+ import { renderPdf, findChrome } from "@/lib/ai/chrome-pdf";
8
+
9
+ export const dynamic = "force-dynamic";
10
+ export const runtime = "nodejs";
11
+
12
+ export async function GET(
13
+ req: Request,
14
+ ctx: { params: Promise<{ key: string }> },
15
+ ) {
16
+ const { key } = await ctx.params;
17
+ if (!/^[a-z0-9-]+$/i.test(key)) {
18
+ return new Response("invalid key", { status: 400 });
19
+ }
20
+ const report = await getSavedReport(key);
21
+ if (!report) return new Response("report not found", { status: 404 });
22
+
23
+ if (!findChrome()) {
24
+ return new Response(
25
+ "No Chrome/Chromium binary found. Install Chrome or set the CHROME_BIN env var.",
26
+ { status: 503 },
27
+ );
28
+ }
29
+
30
+ const origin = new URL(req.url).origin;
31
+ const printUrl = `${origin}/insights/print/${encodeURIComponent(key)}`;
32
+
33
+ try {
34
+ const bytes = await renderPdf(printUrl, key);
35
+ return new Response(new Uint8Array(bytes), {
36
+ headers: {
37
+ "Content-Type": "application/pdf",
38
+ "Content-Disposition": `attachment; filename="${key}.pdf"`,
39
+ "Cache-Control": "no-store",
40
+ },
41
+ });
42
+ } catch (err) {
43
+ return new Response(`PDF render failed: ${(err as Error).message}`, { status: 500 });
44
+ }
45
+ }
@@ -0,0 +1,508 @@
1
+ /**
2
+ * Insights agent — structured ReportData pipeline with persistence.
3
+ *
4
+ * POST /api/insights
5
+ * { range_type: "prior_week" | "week" | "4weeks_completed" | "4weeks" | "custom",
6
+ * since?: "YYYY-MM-DD", until?: "YYYY-MM-DD" }
7
+ *
8
+ * Streams SSE:
9
+ * { type: "status", phase: "data"|"analyst"|"compose", text }
10
+ * { type: "report", report }
11
+ * { type: "saved", key, saved_at }
12
+ * { type: "done" }
13
+ * { type: "error", message }
14
+ */
15
+ import { listSessions, getSession, loadUsageByDay } from "@claude-lens/parser/fs";
16
+ import {
17
+ buildCapsule,
18
+ buildPeriodBundle,
19
+ aggregateConcurrency,
20
+ calendarWeek,
21
+ priorCalendarWeek,
22
+ last4CompletedWeeks,
23
+ calendarMonth,
24
+ priorCalendarMonth,
25
+ computeBurstsFromSessions,
26
+ type SessionCapsule,
27
+ type PeriodBundle,
28
+ } from "@claude-lens/parser";
29
+ import { INSIGHTS_SYSTEM_PROMPT } from "@/lib/ai/insights-prompt";
30
+ import { saveReport, keyForRange, listSavedReports, getSavedReport } from "@/lib/ai/saved-reports";
31
+ import { spawn } from "node:child_process";
32
+ import type { ReportData, IconKey } from "@/components/insight-report";
33
+
34
+ export const dynamic = "force-dynamic";
35
+ export const runtime = "nodejs";
36
+
37
+ type Narrative = {
38
+ archetype: { label: string; icon: string; tagline: string; why: string; vs_usual?: string };
39
+ theme_headline: string;
40
+ shipped_summaries: Record<string, string>;
41
+ patterns: { icon: string; title: string; stat: string; note: string }[];
42
+ concurrency_insight: string;
43
+ concurrency_suggestion: string;
44
+ outlier_notes: {
45
+ longest_run?: string;
46
+ fastest_ship?: string;
47
+ most_errors?: string;
48
+ wandered?: string;
49
+ };
50
+ suggestion_headline: string;
51
+ suggestion_body: string;
52
+ };
53
+
54
+ const VALID_ICONS: IconKey[] = [
55
+ "BrainCircuit", "ClipboardList", "Compass", "GitCommit", "Layers3",
56
+ "Network", "Repeat", "Rocket", "Sparkles", "TrendingDown", "TrendingUp",
57
+ "Users", "Zap",
58
+ ];
59
+
60
+ function safeIcon(v: string): IconKey {
61
+ return VALID_ICONS.includes(v as IconKey) ? (v as IconKey) : "Sparkles";
62
+ }
63
+
64
+ function resolveRange(body: { range_type?: string; since?: string; until?: string }): {
65
+ start: Date; end: Date; range_type: ReportData["range_type"]; in_progress: boolean;
66
+ } {
67
+ switch (body.range_type) {
68
+ case "prior_week": {
69
+ const r = priorCalendarWeek();
70
+ return { ...r, range_type: "week", in_progress: false };
71
+ }
72
+ case "4weeks_completed": {
73
+ const r = last4CompletedWeeks();
74
+ return { ...r, range_type: "4weeks", in_progress: false };
75
+ }
76
+ case "4weeks": {
77
+ const end = calendarWeek().end;
78
+ const start = new Date(end);
79
+ start.setDate(end.getDate() - 27);
80
+ return { start, end, range_type: "4weeks", in_progress: true };
81
+ }
82
+ case "prior_month": {
83
+ const r = priorCalendarMonth();
84
+ return { ...r, range_type: "month", in_progress: false };
85
+ }
86
+ case "month": {
87
+ const r = calendarMonth();
88
+ return { ...r, range_type: "month", in_progress: true };
89
+ }
90
+ case "custom": {
91
+ if (!body.since || !body.until) throw new Error("custom range requires since + until");
92
+ const start = new Date(body.since);
93
+ const end = new Date(body.until);
94
+ // Normalise: pin Mon-Sun 7-day windows to `week`, and full-calendar-month
95
+ // windows to `month`, so they participate in baselines and pickers with
96
+ // the right key instead of living off in custom-* land.
97
+ const days = Math.round((end.getTime() - start.getTime()) / 86_400_000) + 1;
98
+ const isCalendarWeek = days === 7 && start.getDay() === 1;
99
+ const monthEnd = new Date(start.getFullYear(), start.getMonth() + 1, 0);
100
+ const isCalendarMonth = start.getDate() === 1
101
+ && end.getFullYear() === monthEnd.getFullYear()
102
+ && end.getMonth() === monthEnd.getMonth()
103
+ && end.getDate() === monthEnd.getDate();
104
+ const normalised: "week" | "month" | "custom" =
105
+ isCalendarWeek ? "week" : isCalendarMonth ? "month" : "custom";
106
+ return {
107
+ start, end,
108
+ range_type: normalised,
109
+ in_progress: false,
110
+ };
111
+ }
112
+ case "week":
113
+ default: {
114
+ const r = calendarWeek();
115
+ return { ...r, range_type: "week", in_progress: true };
116
+ }
117
+ }
118
+ }
119
+
120
+ export async function POST(request: Request) {
121
+ let body: { range_type?: string; since?: string; until?: string };
122
+ try {
123
+ body = await request.json();
124
+ } catch {
125
+ return Response.json({ error: "invalid JSON" }, { status: 400 });
126
+ }
127
+
128
+ const encoder = new TextEncoder();
129
+ const stream = new ReadableStream({
130
+ async start(controller) {
131
+ let closed = false;
132
+ function send(data: Record<string, unknown>) {
133
+ if (closed) return;
134
+ try { controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)); }
135
+ catch { closed = true; }
136
+ }
137
+ const status = (phase: "data" | "analyst" | "compose", text: string) =>
138
+ send({ type: "status", phase, text });
139
+ function finish() {
140
+ if (!closed) {
141
+ try { controller.close(); } catch { /* already closed */ }
142
+ closed = true;
143
+ }
144
+ }
145
+
146
+ const t0 = Date.now();
147
+
148
+ try {
149
+ const range = resolveRange(body);
150
+ const rangeLabel = range.range_type === "week"
151
+ ? (range.in_progress ? "this week (in progress)" : "last week")
152
+ : range.range_type === "4weeks"
153
+ ? (range.in_progress ? "last 4 weeks (incl. current)" : "last 4 completed weeks")
154
+ : range.range_type === "month"
155
+ ? (range.in_progress ? "this month (in progress)" : "last month")
156
+ : "custom range";
157
+ status("data", `Window: ${rangeLabel}`);
158
+
159
+ // Phase 1 · Data
160
+ const metas = await listSessions({ limit: 10000 });
161
+ const inRange = metas.filter((m) => {
162
+ if (!m.firstTimestamp) return false;
163
+ const t = new Date(m.firstTimestamp).getTime();
164
+ return t >= range.start.getTime() && t <= range.end.getTime();
165
+ });
166
+ status("data", `${inRange.length} sessions found in range`);
167
+
168
+ const caps: SessionCapsule[] = [];
169
+ let trivial = 0;
170
+ const CONCURRENCY = 8;
171
+ for (let i = 0; i < inRange.length; i += CONCURRENCY) {
172
+ const slice = inRange.slice(i, i + CONCURRENCY);
173
+ const results = await Promise.all(slice.map(async (m) => {
174
+ try {
175
+ const d = await getSession(m.id);
176
+ if (!d) return null;
177
+ return buildCapsule(d, { compact: true });
178
+ } catch { return null; }
179
+ }));
180
+ for (const cap of results) {
181
+ if (!cap) continue;
182
+ if (cap.outcome === "trivial") trivial++;
183
+ else caps.push(cap);
184
+ }
185
+ status("data", `Built ${caps.length}/${inRange.length} capsules (${trivial} trivial)`);
186
+ }
187
+
188
+ status("data", `Aggregating ${caps.length} sessions over ${Math.round((range.end.getTime() - range.start.getTime()) / 86400000) + 1} days`);
189
+ const bundle: PeriodBundle = buildPeriodBundle(caps, {
190
+ period: range,
191
+ trivial_dropped: trivial,
192
+ sessions_total: inRange.length,
193
+ });
194
+
195
+ status("data", "Computing concurrency bursts");
196
+ bundle.concurrency = aggregateConcurrency(computeBurstsFromSessions(inRange), range);
197
+
198
+ status("data", "Loading license utilization");
199
+ try { bundle.usage = await loadUsageByDay(range.start, range.end); }
200
+ catch { /* optional */ }
201
+
202
+ status("data", "Loading prior reports for baseline comparison");
203
+ const priorBaseline = await loadPriorWeeks(4);
204
+
205
+ // Phase 2 · Analyst — stringify the payload once; reuse for status, prompt, and context_kb.
206
+ const payloadJson = JSON.stringify({
207
+ period: bundle.period,
208
+ aggregates: bundle,
209
+ capsules: caps,
210
+ prior: priorBaseline,
211
+ });
212
+ const payloadKb = Math.round(payloadJson.length / 1024);
213
+ status("analyst", `Sending ${payloadKb} KB to Claude (sonnet)`);
214
+
215
+ const narrative = await callAnalyst(payloadJson, status);
216
+ if (!narrative) {
217
+ send({ type: "error", message: "Analyst returned no parseable JSON." });
218
+ finish();
219
+ return;
220
+ }
221
+
222
+ // Phase 3 · Compose
223
+ status("compose", "Merging aggregates + narrative");
224
+ const report = mergeReport(bundle, narrative, range, payloadKb, priorBaseline);
225
+ report.meta.pipeline_ms = Date.now() - t0;
226
+
227
+ send({ type: "report", report });
228
+
229
+ // Persistence
230
+ if (!range.in_progress) {
231
+ status("compose", "Saving report to disk");
232
+ const key = keyForRange(range.range_type, bundle.period.start);
233
+ try {
234
+ await saveReport(key, report);
235
+ send({ type: "saved", key, saved_at: new Date().toISOString() });
236
+ } catch (e) {
237
+ send({ type: "status", phase: "compose", text: `(save failed: ${(e as Error).message})` });
238
+ }
239
+ }
240
+
241
+ send({ type: "done" });
242
+ finish();
243
+ } catch (err) {
244
+ send({ type: "error", message: (err as Error).message });
245
+ finish();
246
+ }
247
+ },
248
+ });
249
+
250
+ return new Response(stream, {
251
+ headers: {
252
+ "Content-Type": "text/event-stream",
253
+ "Cache-Control": "no-cache, no-transform",
254
+ Connection: "keep-alive",
255
+ "X-Accel-Buffering": "no",
256
+ },
257
+ });
258
+ }
259
+
260
+ // ──────────────────────────────────────────────────────────────────
261
+ // Spawn claude -p, parse JSON
262
+ // ──────────────────────────────────────────────────────────────────
263
+
264
+ async function callAnalyst(
265
+ payloadJson: string,
266
+ status: (phase: "data" | "analyst" | "compose", text: string) => void,
267
+ ): Promise<Narrative | null> {
268
+ const userPrompt = `Period payload:\n\n${payloadJson}\n\n---\n\nReturn the JSON per your system instructions.`;
269
+
270
+ return new Promise((resolve) => {
271
+ const args = [
272
+ "-p",
273
+ "--output-format", "stream-json",
274
+ "--verbose",
275
+ "--model", "sonnet",
276
+ "--tools", "",
277
+ "--disable-slash-commands",
278
+ "--no-session-persistence",
279
+ "--setting-sources", "",
280
+ "--append-system-prompt", INSIGHTS_SYSTEM_PROMPT,
281
+ ];
282
+ const proc = spawn("claude", args, { stdio: ["pipe", "pipe", "pipe"], env: { ...process.env } });
283
+ proc.stdin.write(userPrompt);
284
+ proc.stdin.end();
285
+
286
+ let buffer = "";
287
+ let lastReportedKb = -1;
288
+ const phaseStart = Date.now();
289
+ proc.stdout.on("data", (chunk: Buffer) => {
290
+ const text = chunk.toString("utf8");
291
+ for (const line of text.split("\n")) {
292
+ const trimmed = line.trim();
293
+ if (!trimmed) continue;
294
+ try {
295
+ const obj = JSON.parse(trimmed) as Record<string, unknown>;
296
+ if (obj.type === "assistant") {
297
+ const msg = obj.message as Record<string, unknown> | undefined;
298
+ const content = msg?.content as Array<Record<string, unknown>> | undefined;
299
+ if (Array.isArray(content)) {
300
+ for (const block of content) {
301
+ if (block.type === "text" && typeof block.text === "string") {
302
+ buffer += block.text;
303
+ const kb = Math.floor(buffer.length / 1024);
304
+ if (kb > lastReportedKb) {
305
+ lastReportedKb = kb;
306
+ const secs = Math.round((Date.now() - phaseStart) / 1000);
307
+ status("analyst", `Claude composing… ${buffer.length.toLocaleString()} chars (${secs}s)`);
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+ } catch { /* skip non-JSON framing */ }
314
+ }
315
+ });
316
+ proc.on("close", () => {
317
+ const json = extractJsonBlock(buffer);
318
+ if (!json) { resolve(null); return; }
319
+ try { resolve(JSON.parse(json) as Narrative); }
320
+ catch { resolve(null); }
321
+ });
322
+ proc.on("error", () => resolve(null));
323
+ });
324
+ }
325
+
326
+ function extractJsonBlock(s: string): string | null {
327
+ const fence = /```json\s*([\s\S]*?)```/m.exec(s);
328
+ if (fence) return fence[1]!.trim();
329
+ const first = s.indexOf("{");
330
+ const last = s.lastIndexOf("}");
331
+ if (first !== -1 && last > first) return s.slice(first, last + 1);
332
+ return null;
333
+ }
334
+
335
+ // ──────────────────────────────────────────────────────────────────
336
+ // Merge → ReportData
337
+ // ──────────────────────────────────────────────────────────────────
338
+
339
+ type PriorWeek = {
340
+ period_label: string;
341
+ archetype: string;
342
+ sessions: number;
343
+ prs: number;
344
+ subagents: number;
345
+ agent_minutes: number;
346
+ };
347
+
348
+ async function loadPriorWeeks(limit: number): Promise<PriorWeek[]> {
349
+ const all = await listSavedReports();
350
+ const weeks = all.filter((r) => r.key.startsWith("week-")).slice(0, limit);
351
+ const out: PriorWeek[] = [];
352
+ for (const meta of weeks) {
353
+ const r = await getSavedReport(meta.key);
354
+ if (!r) continue;
355
+ out.push({
356
+ period_label: r.period_label,
357
+ archetype: r.archetype.label,
358
+ sessions: r.meta.sessions_used,
359
+ prs: r.shipped.length,
360
+ subagents: r.concurrency.peak, // rough proxy for ambition
361
+ agent_minutes: r.days.reduce((a, d) => a + d.agent_minutes, 0),
362
+ });
363
+ }
364
+ return out;
365
+ }
366
+
367
+ function mergeReport(
368
+ bundle: PeriodBundle,
369
+ n: Narrative,
370
+ range: { in_progress: boolean },
371
+ contextKb: number,
372
+ priorWeeks: PriorWeek[],
373
+ ): ReportData {
374
+ const skillEntries = Object.entries(bundle.skills_total).sort((a, b) => b[1] - a[1]);
375
+ const top_skills = skillEntries.slice(0, 6).map(([name, count]) => ({ name, count }));
376
+
377
+ const days = bundle.by_day.map((d, i) => {
378
+ const concOfDay = bundle.concurrency?.by_day[i];
379
+ const useOfDay = bundle.usage?.by_day.find((u) => u.date === d.date);
380
+ return {
381
+ day_name: d.day_name,
382
+ date_label: new Date(d.date).toLocaleDateString("en-US", { month: "short", day: "numeric" }),
383
+ agent_minutes: Math.round(d.agent_min),
384
+ sessions: d.sessions,
385
+ concurrency_peak: concOfDay?.peak ?? 0,
386
+ has_cross_project: Boolean(concOfDay?.has_cross_project),
387
+ plan_util_pct: useOfDay?.peak_util_pct ?? 0,
388
+ is_partial: new Date(d.date).getTime() > Date.now(),
389
+ };
390
+ });
391
+
392
+ const projects = bundle.project_shares.map((p) => ({
393
+ name: p.name,
394
+ display_name: p.display_name,
395
+ agent_minutes: Math.round(p.agent_min),
396
+ share_pct: p.share_pct,
397
+ prs: p.prs,
398
+ commits: p.commits,
399
+ }));
400
+
401
+ const shipped = bundle.shipped_prs.map((s) => ({
402
+ title: s.title,
403
+ project: s.project,
404
+ duration_label: fmtDuration(s.active_min),
405
+ commits: s.commits,
406
+ subagents: s.subagents,
407
+ flags: s.flags,
408
+ summary: n.shipped_summaries[s.session_id] ?? "",
409
+ }));
410
+
411
+ const outliers: ReportData["outliers"] = [];
412
+ if (bundle.outliers.longest_run) {
413
+ outliers.push({
414
+ label: "Longest run",
415
+ detail: fmtDuration(bundle.outliers.longest_run.active_min),
416
+ note: n.outlier_notes.longest_run ?? bundle.outliers.longest_run.project,
417
+ });
418
+ }
419
+ if (bundle.outliers.fastest_ship) {
420
+ outliers.push({
421
+ label: "Fastest ship",
422
+ detail: fmtDuration(bundle.outliers.fastest_ship.active_min),
423
+ note: n.outlier_notes.fastest_ship ?? bundle.outliers.fastest_ship.pr_title,
424
+ });
425
+ }
426
+ if (bundle.outliers.most_errors) {
427
+ outliers.push({
428
+ label: "Most errors",
429
+ detail: String(bundle.outliers.most_errors.tool_errors),
430
+ note: n.outlier_notes.most_errors ?? bundle.outliers.most_errors.project,
431
+ });
432
+ }
433
+ if (bundle.outliers.wandered) {
434
+ outliers.push({
435
+ label: "Wandered",
436
+ detail: fmtDuration(bundle.outliers.wandered.active_min),
437
+ note: n.outlier_notes.wandered ?? bundle.outliers.wandered.project,
438
+ });
439
+ }
440
+
441
+ const in_progress_suffix = range.in_progress ? " · in progress" : "";
442
+ const periodPrefix =
443
+ bundle.period.range_type === "4weeks" ? "Last 4 weeks ·"
444
+ : bundle.period.range_type === "month" ? "Month of"
445
+ : "Week of";
446
+ const sublabel =
447
+ bundle.period.range_type === "4weeks" ? "Calendar 4-week rollup"
448
+ : bundle.period.range_type === "month" ? "Calendar month"
449
+ : "Calendar week · Mon–Sun";
450
+
451
+ return {
452
+ period_label: `${periodPrefix} ${bundle.period.label}`,
453
+ period_sublabel: `${sublabel}${in_progress_suffix}`,
454
+ range_type: bundle.period.range_type,
455
+ archetype: {
456
+ label: n.archetype.label,
457
+ icon: safeIcon(n.archetype.icon),
458
+ tagline: n.archetype.tagline,
459
+ why: n.archetype.why,
460
+ vs_usual: n.archetype.vs_usual,
461
+ },
462
+ top_skills,
463
+ days,
464
+ theme_headline: n.theme_headline,
465
+ projects,
466
+ shipped,
467
+ patterns: n.patterns.map((p) => ({
468
+ icon: safeIcon(p.icon), title: p.title, stat: p.stat, note: p.note,
469
+ })),
470
+ concurrency: {
471
+ multi_agent_days: bundle.concurrency?.multi_agent_days ?? 0,
472
+ peak: bundle.concurrency?.peak ?? 0,
473
+ peak_day: bundle.concurrency?.peak_day
474
+ ? new Date(bundle.concurrency.peak_day).toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" })
475
+ : "—",
476
+ cross_project_days: bundle.concurrency?.cross_project_days ?? 0,
477
+ insight: n.concurrency_insight,
478
+ suggestion: n.concurrency_suggestion,
479
+ },
480
+ outliers,
481
+ suggestion_headline: n.suggestion_headline,
482
+ suggestion_body: n.suggestion_body,
483
+ prior_weeks: priorWeeks,
484
+ saved_reports: [],
485
+ meta: {
486
+ generated_at: new Date().toISOString().replace("T", " ").slice(0, 16),
487
+ sessions_total: bundle.counts.sessions_total,
488
+ sessions_used: bundle.counts.substantive,
489
+ trivial_dropped: bundle.counts.trivial_dropped,
490
+ model: "claude-sonnet-4-6",
491
+ pipeline_ms: 0,
492
+ context_kb: contextKb,
493
+ },
494
+ };
495
+ }
496
+
497
+ function fmtDuration(minutes: number): string {
498
+ if (minutes < 60) {
499
+ const whole = Math.floor(minutes);
500
+ const secs = Math.round((minutes - whole) * 60);
501
+ if (whole === 0 && secs > 0) return `${secs}s`;
502
+ if (secs === 0) return `${whole}m`;
503
+ return `${whole}m ${secs}s`;
504
+ }
505
+ const h = Math.floor(minutes / 60);
506
+ const m = Math.round(minutes - h * 60);
507
+ return `${h}h ${m}m`;
508
+ }