fleetlens 0.4.0 → 0.6.0

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 (440) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +16 -7
  3. package/app/apps/web/.next/build-manifest.json +7 -7
  4. package/app/apps/web/.next/prerender-manifest.json +3 -3
  5. package/app/apps/web/.next/required-server-files.json +2 -1
  6. package/app/apps/web/.next/routes-manifest.json +86 -24
  7. package/app/apps/web/.next/server/app/_global-error/page/build-manifest.json +4 -4
  8. package/app/apps/web/.next/server/app/_global-error/page.js +1 -1
  9. package/app/apps/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  10. package/app/apps/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  12. package/app/apps/web/.next/server/app/_global-error.rsc +7 -7
  13. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  14. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  15. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  16. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  17. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/app/apps/web/.next/server/app/_not-found/page/build-manifest.json +4 -4
  19. package/app/apps/web/.next/server/app/_not-found/page.js +5 -4
  20. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/app/apps/web/.next/server/app/api/digest/day/[date]/route/app-paths-manifest.json +3 -0
  23. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +9 -0
  24. package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/day/[date]}/route.js.nft.json +1 -1
  25. package/app/apps/web/.next/server/app/api/digest/day/[date]/route_client-reference-manifest.js +3 -0
  26. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route/app-paths-manifest.json +3 -0
  27. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +9 -0
  28. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -0
  29. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route_client-reference-manifest.js +3 -0
  30. package/app/apps/web/.next/server/app/api/digest/month-index/route/app-paths-manifest.json +3 -0
  31. package/app/apps/web/.next/server/app/api/digest/month-index/route.js +7 -0
  32. package/app/apps/web/.next/server/app/api/{insights/months-index → digest/month-index}/route.js.nft.json +1 -1
  33. package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route_client-reference-manifest.js +1 -1
  34. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route/app-paths-manifest.json +3 -0
  35. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +9 -0
  36. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -0
  37. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route_client-reference-manifest.js +3 -0
  38. package/app/apps/web/.next/server/app/api/digest/week-index/route/app-paths-manifest.json +3 -0
  39. package/app/apps/web/.next/server/app/api/digest/week-index/route.js +7 -0
  40. package/app/apps/web/.next/server/app/api/{insights/weeks-index → digest/week-index}/route.js.nft.json +1 -1
  41. package/app/apps/web/.next/server/app/api/digest/week-index/route_client-reference-manifest.js +3 -0
  42. package/app/apps/web/.next/server/app/api/jobs/route/app-paths-manifest.json +3 -0
  43. package/app/apps/web/.next/server/app/api/jobs/route.js +6 -0
  44. package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -0
  45. package/app/apps/web/.next/server/app/api/jobs/route_client-reference-manifest.js +3 -0
  46. package/app/apps/web/.next/server/app/api/runs/[runId]/route/app-paths-manifest.json +3 -0
  47. package/app/apps/web/.next/server/app/api/runs/[runId]/route/build-manifest.json +9 -0
  48. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js +6 -0
  49. package/app/apps/web/.next/server/app/api/{insights/saved → runs/[runId]}/route.js.nft.json +1 -1
  50. package/app/apps/web/.next/server/app/api/runs/[runId]/route_client-reference-manifest.js +3 -0
  51. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route/app-paths-manifest.json +3 -0
  52. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route/build-manifest.json +9 -0
  53. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route/server-reference-manifest.json +4 -0
  54. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js +6 -0
  55. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.map +5 -0
  56. package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → runs/[runId]/stream}/route.js.nft.json +1 -1
  57. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route_client-reference-manifest.js +3 -0
  58. package/app/apps/web/.next/server/app/api/runs/route/app-paths-manifest.json +3 -0
  59. package/app/apps/web/.next/server/app/api/runs/route/build-manifest.json +9 -0
  60. package/app/apps/web/.next/server/app/api/runs/route/server-reference-manifest.json +4 -0
  61. package/app/apps/web/.next/server/app/api/runs/route.js +6 -0
  62. package/app/apps/web/.next/server/app/api/runs/route.js.map +5 -0
  63. package/app/apps/web/.next/server/app/api/{insights → runs}/route.js.nft.json +1 -1
  64. package/app/apps/web/.next/server/app/api/runs/route_client-reference-manifest.js +3 -0
  65. package/app/apps/web/.next/server/app/api/settings/route/app-paths-manifest.json +3 -0
  66. package/app/apps/web/.next/server/app/api/settings/route/build-manifest.json +9 -0
  67. package/app/apps/web/.next/server/app/api/settings/route/server-reference-manifest.json +4 -0
  68. package/app/apps/web/.next/server/app/api/settings/route.js +10 -0
  69. package/app/apps/web/.next/server/app/api/settings/route.js.map +5 -0
  70. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -0
  71. package/app/apps/web/.next/server/app/api/{insights → settings}/route_client-reference-manifest.js +1 -1
  72. package/app/apps/web/.next/server/app/day/[date]/page/app-paths-manifest.json +3 -0
  73. package/app/apps/web/.next/server/app/{insights/print/[key] → day/[date]}/page/build-manifest.json +4 -4
  74. package/app/apps/web/.next/server/app/day/[date]/page/server-reference-manifest.json +4 -0
  75. package/app/apps/web/.next/server/app/day/[date]/page.js +18 -0
  76. package/app/apps/web/.next/server/app/day/[date]/page.js.map +5 -0
  77. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -0
  78. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +3 -0
  79. package/app/apps/web/.next/server/app/day/page/app-paths-manifest.json +3 -0
  80. package/app/apps/web/.next/server/app/day/page/build-manifest.json +17 -0
  81. package/app/apps/web/.next/server/app/day/page/next-font-manifest.json +6 -0
  82. package/app/apps/web/.next/server/app/day/page/react-loadable-manifest.json +1 -0
  83. package/app/apps/web/.next/server/app/day/page/server-reference-manifest.json +4 -0
  84. package/app/apps/web/.next/server/app/{insights/print/[key] → day}/page.js +11 -10
  85. package/app/apps/web/.next/server/app/day/page.js.map +5 -0
  86. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -0
  87. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +3 -0
  88. package/app/apps/web/.next/server/app/digest/[date]/page/app-paths-manifest.json +3 -0
  89. package/app/apps/web/.next/server/app/digest/[date]/page/build-manifest.json +17 -0
  90. package/app/apps/web/.next/server/app/digest/[date]/page/next-font-manifest.json +6 -0
  91. package/app/apps/web/.next/server/app/digest/[date]/page/react-loadable-manifest.json +1 -0
  92. package/app/apps/web/.next/server/app/digest/[date]/page/server-reference-manifest.json +4 -0
  93. package/app/apps/web/.next/server/app/digest/[date]/page.js +17 -0
  94. package/app/apps/web/.next/server/app/digest/[date]/page.js.map +5 -0
  95. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -0
  96. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +3 -0
  97. package/app/apps/web/.next/server/app/digest/page/app-paths-manifest.json +3 -0
  98. package/app/apps/web/.next/server/app/digest/page/build-manifest.json +17 -0
  99. package/app/apps/web/.next/server/app/digest/page/next-font-manifest.json +6 -0
  100. package/app/apps/web/.next/server/app/digest/page/react-loadable-manifest.json +1 -0
  101. package/app/apps/web/.next/server/app/digest/page/server-reference-manifest.json +4 -0
  102. package/app/apps/web/.next/server/app/digest/page.js +17 -0
  103. package/app/apps/web/.next/server/app/digest/page.js.map +5 -0
  104. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -0
  105. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +3 -0
  106. package/app/apps/web/.next/server/app/insights/[key]/page/build-manifest.json +4 -4
  107. package/app/apps/web/.next/server/app/insights/[key]/page.js +7 -5
  108. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  109. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  110. package/app/apps/web/.next/server/app/insights/page/build-manifest.json +4 -4
  111. package/app/apps/web/.next/server/app/insights/page.js +7 -5
  112. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  113. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  114. package/app/apps/web/.next/server/app/page/build-manifest.json +4 -4
  115. package/app/apps/web/.next/server/app/page.js +7 -6
  116. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  117. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  118. package/app/apps/web/.next/server/app/parallelism/page/build-manifest.json +4 -4
  119. package/app/apps/web/.next/server/app/parallelism/page.js +6 -5
  120. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  121. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  122. package/app/apps/web/.next/server/app/projects/[slug]/page/build-manifest.json +4 -4
  123. package/app/apps/web/.next/server/app/projects/[slug]/page.js +6 -5
  124. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  125. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  126. package/app/apps/web/.next/server/app/projects/page/build-manifest.json +4 -4
  127. package/app/apps/web/.next/server/app/projects/page.js +5 -4
  128. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  129. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  130. package/app/apps/web/.next/server/app/runs/page/app-paths-manifest.json +3 -0
  131. package/app/apps/web/.next/server/app/runs/page/build-manifest.json +17 -0
  132. package/app/apps/web/.next/server/app/runs/page/next-font-manifest.json +6 -0
  133. package/app/apps/web/.next/server/app/runs/page/react-loadable-manifest.json +1 -0
  134. package/app/apps/web/.next/server/app/runs/page/server-reference-manifest.json +4 -0
  135. package/app/apps/web/.next/server/app/runs/page.js +17 -0
  136. package/app/apps/web/.next/server/app/runs/page.js.map +5 -0
  137. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -0
  138. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +3 -0
  139. package/app/apps/web/.next/server/app/sessions/[id]/page/build-manifest.json +4 -4
  140. package/app/apps/web/.next/server/app/sessions/[id]/page.js +5 -4
  141. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  142. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  143. package/app/apps/web/.next/server/app/sessions/page/build-manifest.json +4 -4
  144. package/app/apps/web/.next/server/app/sessions/page.js +5 -4
  145. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  146. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  147. package/app/apps/web/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  148. package/app/apps/web/.next/server/app/settings/page/build-manifest.json +17 -0
  149. package/app/apps/web/.next/server/app/settings/page/next-font-manifest.json +6 -0
  150. package/app/apps/web/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  151. package/app/apps/web/.next/server/app/settings/page/server-reference-manifest.json +4 -0
  152. package/app/apps/web/.next/server/app/settings/page.js +18 -0
  153. package/app/apps/web/.next/server/app/settings/page.js.map +5 -0
  154. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -0
  155. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  156. package/app/apps/web/.next/server/app/usage/page/build-manifest.json +4 -4
  157. package/app/apps/web/.next/server/app/usage/page.js +6 -5
  158. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  159. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  160. package/app/apps/web/.next/server/app-paths-manifest.json +16 -7
  161. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_digest_week_[startDate]_route_actions_0klqqsh.js +3 -0
  162. package/app/apps/web/.next/server/chunks/09og__next-internal_server_app_api_digest_month_[yearMonth]_route_actions_0i4ielu.js +3 -0
  163. package/app/apps/web/.next/server/chunks/[externals]__0o43ejh._.js +3 -0
  164. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0-vgrh1._.js +3 -0
  165. package/app/apps/web/.next/server/chunks/[root-of-the-server]__00n3f9y._.js +3 -0
  166. package/app/apps/web/.next/server/chunks/[root-of-the-server]__02zukjw._.js +3 -0
  167. package/app/apps/web/.next/server/chunks/[root-of-the-server]__067~im1._.js +6 -0
  168. package/app/apps/web/.next/server/chunks/[root-of-the-server]__06b4cj-._.js +3 -0
  169. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0_8zh-i._.js +9 -0
  170. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0e8n_x4._.js +3 -0
  171. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0ej_p3s._.js +9 -0
  172. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0jprdks._.js +9 -0
  173. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_digest_day_[date]_route_actions_09sxie5.js +3 -0
  174. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_digest_month-index_route_actions_0wldpbu.js +3 -0
  175. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_digest_week-index_route_actions_12c2wj2.js +3 -0
  176. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_jobs_route_actions_08kx~8-.js +3 -0
  177. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_runs_[runId]_route_actions_0dfcghc.js +3 -0
  178. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_runs_[runId]_stream_route_actions_0.8e8-k.js +3 -0
  179. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_runs_route_actions_0xyx82f.js +3 -0
  180. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_settings_route_actions_0.xv7sx.js +3 -0
  181. package/app/apps/web/.next/server/chunks/node_modules_next_036my~r._.js +49 -0
  182. package/app/apps/web/.next/server/chunks/packages_0e7q9u_._.js +3 -0
  183. package/app/apps/web/.next/server/chunks/packages_0n6p2ot._.js +3 -0
  184. package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +379 -0
  185. package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_0bc7ptm.js +1 -1
  186. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0-1_njm._.js +3 -0
  187. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0-94ji~._.js +3 -0
  188. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__13xpdx0._.js → [root-of-the-server]__03uoeiw._.js} +2 -2
  189. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0_6.inc._.js +1 -1
  190. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0d~2~le._.js +8 -0
  191. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gio_ck._.js +1 -1
  192. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__08.d5ia._.js → [root-of-the-server]__0jdyefm._.js} +10 -10
  193. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ln9jsw._.js +3 -0
  194. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0z45d0g._.js → [root-of-the-server]__0lz4a~g._.js} +2 -48
  195. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0o1_g.~._.js +3 -0
  196. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +3 -0
  197. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0rvzdnx._.js +3 -0
  198. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0euu8sa._.js → [root-of-the-server]__0u39afl._.js} +2 -2
  199. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0u5d7de._.js +12 -0
  200. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +3 -3
  201. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0wwa6gh._.js +3 -0
  202. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0xy1qim._.js +3 -0
  203. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~_8vff._.js +3 -0
  204. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__10srpu0._.js +3 -0
  205. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__11v.eqw._.js +1 -1
  206. package/app/apps/web/.next/server/chunks/ssr/_02s1n-x._.js +8 -0
  207. package/app/apps/web/.next/server/chunks/ssr/_0fjbf--._.js +3 -0
  208. package/app/apps/web/.next/server/chunks/ssr/_0jw2sm7._.js +3 -0
  209. package/app/apps/web/.next/server/chunks/ssr/_0wj750k._.js +3 -0
  210. package/app/apps/web/.next/server/chunks/ssr/_0woap-3._.js +1 -1
  211. package/app/apps/web/.next/server/chunks/ssr/{_0xies90._.js → _0xu2pvc._.js} +2 -2
  212. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_day_[date]_page_actions_0u2kxb..js +3 -0
  213. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_day_page_actions_1042maj.js +3 -0
  214. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_digest_[date]_page_actions_0olu967.js +3 -0
  215. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_digest_page_actions_0bl.eil.js +3 -0
  216. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_runs_page_actions_0485qy7.js +3 -0
  217. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_settings_page_actions_0f6epye.js +3 -0
  218. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_day_[date]_day-view_tsx_0wjoe1u._.js +3 -0
  219. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_settings_ai-features-form_tsx_01p699p._.js +3 -0
  220. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0b-4-4j._.js +1 -1
  221. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0ly1xes._.js +6 -0
  222. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0txtsv5._.js +16 -0
  223. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0xs658s._.js +10 -0
  224. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_runs-live-board_tsx_0r6dkdq._.js +3 -0
  225. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_usage-charts-dashboard_tsx_0bgr_uv._.js +1 -1
  226. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_usage-data_ts_0xtv99n._.js +3 -0
  227. package/app/apps/web/.next/server/chunks/ssr/node_modules_0i2xw~e._.js +3 -0
  228. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js +1 -1
  229. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0d3d4wn.js +4 -0
  230. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0edz1ko.js +4 -0
  231. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0eq.n-n.js +4 -0
  232. package/app/apps/web/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0vz7_px.js → node_modules_next_dist_esm_build_templates_app-page_0hcvt-s.js} +3 -3
  233. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0nd5zu0.js +4 -0
  234. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11j1qy0.js +4 -0
  235. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12n1lw_.js +1 -1
  236. package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +3 -0
  237. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0-jvt~a._.js +1 -1
  238. package/app/apps/web/.next/server/functions-config-manifest.json +11 -6
  239. package/app/apps/web/.next/server/middleware-build-manifest.js +7 -7
  240. package/app/apps/web/.next/server/pages/500.html +1 -1
  241. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  242. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  243. package/app/apps/web/.next/static/chunks/0-yc2_pjxwwuq.js +1 -0
  244. package/app/apps/web/.next/static/chunks/0257pdz1-imal.js +2 -0
  245. package/app/apps/web/.next/static/chunks/05m.oz3kmf1p7.js +1 -0
  246. package/app/apps/web/.next/static/chunks/{0pqt~8bl3ukh4.js → 073081qv4uyn8.js} +1 -1
  247. package/app/apps/web/.next/static/chunks/{0018dy-m-kusj.js → 07lbm-sdh9c2j.js} +1 -1
  248. package/app/apps/web/.next/static/chunks/0858bgw2i4vob.js +1 -0
  249. package/app/apps/web/.next/static/chunks/0_7303jr0sf0w.js +10 -0
  250. package/app/apps/web/.next/static/chunks/0byz8fqw.exef.js +1 -0
  251. package/app/apps/web/.next/static/chunks/0coa1800xqgfj.js +1 -0
  252. package/app/apps/web/.next/static/chunks/0fs3gxea5h0s3.css +1 -0
  253. package/app/apps/web/.next/static/chunks/0k1psab.bybh9.js +14 -0
  254. package/app/apps/web/.next/static/chunks/0k9pksi_i.odf.js +1 -0
  255. package/app/apps/web/.next/static/chunks/0m62vx92~0_0d.js +1 -0
  256. package/app/apps/web/.next/static/chunks/0mc8aa8z.0-5l.js +8 -0
  257. package/app/apps/web/.next/static/chunks/0mykrrv810ra-.js +31 -0
  258. package/app/apps/web/.next/static/chunks/0o9ayt8sknubd.js +1 -0
  259. package/app/apps/web/.next/static/chunks/0osdgl2.9cl1q.js +6 -0
  260. package/app/apps/web/.next/static/chunks/0xfu09fn_358k.js +4 -0
  261. package/app/apps/web/.next/static/chunks/171za22fv684..js +6 -0
  262. package/app/apps/web/.next/static/chunks/17u2ww8ya5dv1.js +6 -0
  263. package/app/apps/web/.next/static/chunks/{turbopack-169w-1._23ra_.js → turbopack-0_p36yduv.waj.js} +1 -1
  264. package/app/apps/web/app/api/digest/day/[date]/route.ts +152 -0
  265. package/app/apps/web/app/api/digest/month/[yearMonth]/route.ts +147 -0
  266. package/app/apps/web/app/api/digest/month-index/route.ts +103 -0
  267. package/app/apps/web/app/api/digest/week/[startDate]/route.ts +149 -0
  268. package/app/apps/web/app/api/{insights/weeks-index → digest/week-index}/route.ts +45 -33
  269. package/app/apps/web/app/api/jobs/route.ts +8 -0
  270. package/app/apps/web/app/api/runs/[runId]/route.ts +64 -0
  271. package/app/apps/web/app/api/runs/[runId]/stream/route.ts +154 -0
  272. package/app/apps/web/app/api/runs/route.ts +266 -0
  273. package/app/apps/web/app/api/settings/route.ts +35 -0
  274. package/app/apps/web/app/day/[date]/day-view.tsx +193 -0
  275. package/app/apps/web/app/day/[date]/page.tsx +175 -0
  276. package/app/apps/web/app/day/page.tsx +8 -0
  277. package/app/apps/web/app/digest/[date]/page.tsx +15 -0
  278. package/app/apps/web/app/digest/page.tsx +7 -0
  279. package/app/apps/web/app/insights/[key]/page.tsx +106 -48
  280. package/app/apps/web/app/insights/page.tsx +133 -3
  281. package/app/apps/web/app/layout.tsx +23 -3
  282. package/app/apps/web/app/page.tsx +33 -4
  283. package/app/apps/web/app/parallelism/gantt-chart.tsx +67 -1
  284. package/app/apps/web/app/parallelism/page.tsx +8 -278
  285. package/app/apps/web/app/projects/[slug]/page.tsx +153 -0
  286. package/app/apps/web/app/projects/page.tsx +49 -4
  287. package/app/apps/web/app/projects/projects-view.tsx +79 -68
  288. package/app/apps/web/app/runs/page.tsx +21 -0
  289. package/app/apps/web/app/sessions/[id]/page.tsx +12 -1
  290. package/app/apps/web/app/sessions/[id]/session-view.tsx +569 -21
  291. package/app/apps/web/app/sessions/page.tsx +19 -3
  292. package/app/apps/web/app/sessions/sessions-grid.tsx +172 -131
  293. package/app/apps/web/app/settings/ai-features-form.tsx +45 -0
  294. package/app/apps/web/app/settings/page.tsx +20 -0
  295. package/app/apps/web/app/usage/page.tsx +45 -3
  296. package/app/apps/web/components/auto-generate-yesterday.tsx +96 -0
  297. package/app/apps/web/components/backfill-drawer.tsx +309 -0
  298. package/app/apps/web/components/dashboard-view.tsx +4 -2
  299. package/app/apps/web/components/date-nav.tsx +385 -0
  300. package/app/apps/web/components/day-digest-view.tsx +180 -0
  301. package/app/apps/web/components/day-digest.tsx +489 -0
  302. package/app/apps/web/components/flag-chip.tsx +54 -0
  303. package/app/apps/web/components/goal-bar.tsx +63 -0
  304. package/app/apps/web/components/heatmap.tsx +78 -1
  305. package/app/apps/web/components/helpfulness-sparkline.tsx +82 -0
  306. package/app/apps/web/components/insights-history.tsx +211 -0
  307. package/app/apps/web/components/insights-top-bar.tsx +216 -0
  308. package/app/apps/web/components/job-queue-widget.tsx +274 -0
  309. package/app/apps/web/components/live-sessions-widget.tsx +38 -3
  310. package/app/apps/web/components/month-digest-view.tsx +138 -0
  311. package/app/apps/web/components/month-digest.tsx +216 -0
  312. package/app/apps/web/components/outcome-mix-row.tsx +37 -0
  313. package/app/apps/web/components/outcome-pill.tsx +101 -0
  314. package/app/apps/web/components/previous-cycles-trend.tsx +155 -0
  315. package/app/apps/web/components/recent-days-panel.tsx +83 -0
  316. package/app/apps/web/components/runs-live-board.tsx +513 -0
  317. package/app/apps/web/components/sidebar.tsx +38 -4
  318. package/app/apps/web/components/usage-chart-range.tsx +58 -6
  319. package/app/apps/web/components/usage-chart.tsx +94 -7
  320. package/app/apps/web/components/usage-charts-dashboard.tsx +20 -1
  321. package/app/apps/web/components/week-digest-view.tsx +226 -0
  322. package/app/apps/web/components/week-digest.tsx +2128 -0
  323. package/app/apps/web/components/yesterday-hero.tsx +110 -0
  324. package/app/apps/web/lib/auto-week-fire.ts +37 -0
  325. package/app/apps/web/lib/calibration-data.ts +171 -0
  326. package/app/apps/web/lib/entries-index.ts +174 -0
  327. package/app/apps/web/lib/entries.ts +72 -0
  328. package/app/apps/web/lib/inflight-coalesce.test.ts +43 -0
  329. package/app/apps/web/lib/inflight-coalesce.ts +19 -0
  330. package/app/apps/web/lib/jobs.ts +170 -0
  331. package/app/apps/web/lib/usage-data.ts +37 -0
  332. package/app/apps/web/lib/validate-settings.test.ts +25 -0
  333. package/app/apps/web/lib/validate-settings.ts +9 -0
  334. package/app/apps/web/next.config.ts +1 -1
  335. package/app/apps/web/package.json +4 -2
  336. package/app/apps/web/server.js +1 -1
  337. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  338. package/app/apps/web/vitest.config.ts +9 -0
  339. package/dist/daemon-worker.js +1758 -713
  340. package/dist/index.js +11308 -1888
  341. package/package.json +4 -1
  342. package/app/apps/web/.next/server/app/api/insights/months-index/route/app-paths-manifest.json +0 -3
  343. package/app/apps/web/.next/server/app/api/insights/months-index/route.js +0 -7
  344. package/app/apps/web/.next/server/app/api/insights/months-index/route_client-reference-manifest.js +0 -3
  345. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route/app-paths-manifest.json +0 -3
  346. package/app/apps/web/.next/server/app/api/insights/pdf/[key]/route.js +0 -6
  347. package/app/apps/web/.next/server/app/api/insights/route/app-paths-manifest.json +0 -3
  348. package/app/apps/web/.next/server/app/api/insights/route.js +0 -8
  349. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route/app-paths-manifest.json +0 -3
  350. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route.js +0 -6
  351. package/app/apps/web/.next/server/app/api/insights/saved/[key]/route_client-reference-manifest.js +0 -3
  352. package/app/apps/web/.next/server/app/api/insights/saved/route/app-paths-manifest.json +0 -3
  353. package/app/apps/web/.next/server/app/api/insights/saved/route.js +0 -6
  354. package/app/apps/web/.next/server/app/api/insights/saved/route_client-reference-manifest.js +0 -3
  355. package/app/apps/web/.next/server/app/api/insights/weeks-index/route/app-paths-manifest.json +0 -3
  356. package/app/apps/web/.next/server/app/api/insights/weeks-index/route.js +0 -7
  357. package/app/apps/web/.next/server/app/api/insights/weeks-index/route_client-reference-manifest.js +0 -3
  358. package/app/apps/web/.next/server/app/insights/print/[key]/page/app-paths-manifest.json +0 -3
  359. package/app/apps/web/.next/server/app/insights/print/[key]/page.js.nft.json +0 -1
  360. package/app/apps/web/.next/server/app/insights/print/[key]/page_client-reference-manifest.js +0 -3
  361. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_months-index_route_actions_0~h~zci.js +0 -3
  362. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_saved_[key]_route_actions_0a5j9yw.js +0 -3
  363. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_insights_weeks-index_route_actions_0hh-1c7.js +0 -3
  364. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0.hmj0z._.js +0 -3
  365. package/app/apps/web/.next/server/chunks/[root-of-the-server]__01h_g-p._.js +0 -3
  366. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0nh-z10._.js +0 -3
  367. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0ri7q~r._.js +0 -3
  368. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0rr1~~x._.js +0 -3
  369. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0s0gv.0._.js +0 -3
  370. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_pdf_[key]_route_actions_0lu-lnx.js +0 -3
  371. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_route_actions_0h8l5lz.js +0 -3
  372. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_insights_saved_route_actions_13rlblw.js +0 -3
  373. package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_00t2xj6.js +0 -68
  374. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0.tsxpj._.js +0 -3
  375. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__00z7zlm._.js +0 -3
  376. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__08pen0k._.js +0 -3
  377. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0b323~k._.js +0 -8
  378. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0gx-4qa._.js +0 -3
  379. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0wv27wt._.js +0 -3
  380. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__13itnvx._.js +0 -3
  381. package/app/apps/web/.next/server/chunks/ssr/_09n75_5._.js +0 -8
  382. package/app/apps/web/.next/server/chunks/ssr/_0r~__0v._.js +0 -12
  383. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_insights_print_[key]_page_actions_0a853fw.js +0 -3
  384. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_parallelism_08vub.0._.js +0 -3
  385. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_06j3c.0._.js +0 -8
  386. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0bbo_pd._.js +0 -8
  387. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_insight-report_tsx_13q2a-c._.js +0 -12
  388. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_insights-view_tsx_11730ta._.js +0 -6
  389. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0nqz8dw._.js +0 -3
  390. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js +0 -3
  391. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_analytics_0k4dgst.js +0 -3
  392. package/app/apps/web/.next/static/chunks/028_pmk40b69_.js +0 -6
  393. package/app/apps/web/.next/static/chunks/03.mv4y4.w-vb.js +0 -6
  394. package/app/apps/web/.next/static/chunks/03_7xtpi9sv4g.js +0 -4
  395. package/app/apps/web/.next/static/chunks/03g5dw5eskotd.js +0 -6
  396. package/app/apps/web/.next/static/chunks/063oimt30jeo9.js +0 -10
  397. package/app/apps/web/.next/static/chunks/08c1pcrocqq5s.js +0 -6
  398. package/app/apps/web/.next/static/chunks/0e-wrhqh4h3r5.js +0 -2
  399. package/app/apps/web/.next/static/chunks/0fc6dk2qtokwh.js +0 -1
  400. package/app/apps/web/.next/static/chunks/0i7er7_bfab36.js +0 -10
  401. package/app/apps/web/.next/static/chunks/0ipytyi01h0ta.js +0 -1
  402. package/app/apps/web/.next/static/chunks/0lsznd4_avzhv.js +0 -6
  403. package/app/apps/web/.next/static/chunks/0lty3v_i9mde7.js +0 -1
  404. package/app/apps/web/.next/static/chunks/0vekjjj4pidlz.css +0 -1
  405. package/app/apps/web/.next/static/chunks/137uw2-qbro07.js +0 -31
  406. package/app/apps/web/app/api/insights/months-index/route.ts +0 -80
  407. package/app/apps/web/app/api/insights/pdf/[key]/route.ts +0 -45
  408. package/app/apps/web/app/api/insights/route.ts +0 -508
  409. package/app/apps/web/app/api/insights/saved/[key]/route.ts +0 -11
  410. package/app/apps/web/app/api/insights/saved/route.ts +0 -9
  411. package/app/apps/web/app/insights/print/[key]/page.tsx +0 -73
  412. package/app/apps/web/components/insight-report.tsx +0 -1031
  413. package/app/apps/web/components/insights-view.tsx +0 -647
  414. package/app/apps/web/lib/ai/insights-prompt.ts +0 -71
  415. package/app/apps/web/lib/ai/saved-reports.ts +0 -83
  416. /package/app/apps/web/.next/server/app/api/{insights/months-index → digest/day/[date]}/route/build-manifest.json +0 -0
  417. /package/app/apps/web/.next/server/app/api/{insights/months-index → digest/day/[date]}/route/server-reference-manifest.json +0 -0
  418. /package/app/apps/web/.next/server/app/api/{insights/months-index → digest/day/[date]}/route.js.map +0 -0
  419. /package/app/apps/web/.next/server/app/api/{insights → digest/month/[yearMonth]}/route/build-manifest.json +0 -0
  420. /package/app/apps/web/.next/server/app/api/{insights → digest/month/[yearMonth]}/route/server-reference-manifest.json +0 -0
  421. /package/app/apps/web/.next/server/app/api/{insights → digest/month/[yearMonth]}/route.js.map +0 -0
  422. /package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route/build-manifest.json +0 -0
  423. /package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route/server-reference-manifest.json +0 -0
  424. /package/app/apps/web/.next/server/app/api/{insights/pdf/[key] → digest/month-index}/route.js.map +0 -0
  425. /package/app/apps/web/.next/server/app/api/{insights/saved → digest/week/[startDate]}/route/build-manifest.json +0 -0
  426. /package/app/apps/web/.next/server/app/api/{insights/saved → digest/week/[startDate]}/route/server-reference-manifest.json +0 -0
  427. /package/app/apps/web/.next/server/app/api/{insights/saved → digest/week/[startDate]}/route.js.map +0 -0
  428. /package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/week-index}/route/build-manifest.json +0 -0
  429. /package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/week-index}/route/server-reference-manifest.json +0 -0
  430. /package/app/apps/web/.next/server/app/api/{insights/saved/[key] → digest/week-index}/route.js.map +0 -0
  431. /package/app/apps/web/.next/server/app/api/{insights/weeks-index → jobs}/route/build-manifest.json +0 -0
  432. /package/app/apps/web/.next/server/app/api/{insights/weeks-index → jobs}/route/server-reference-manifest.json +0 -0
  433. /package/app/apps/web/.next/server/app/api/{insights/weeks-index → jobs}/route.js.map +0 -0
  434. /package/app/apps/web/.next/server/app/{insights/print/[key]/page → api/runs/[runId]/route}/server-reference-manifest.json +0 -0
  435. /package/app/apps/web/.next/server/app/{insights/print/[key]/page.js.map → api/runs/[runId]/route.js.map} +0 -0
  436. /package/app/apps/web/.next/server/app/{insights/print/[key] → day/[date]}/page/next-font-manifest.json +0 -0
  437. /package/app/apps/web/.next/server/app/{insights/print/[key] → day/[date]}/page/react-loadable-manifest.json +0 -0
  438. /package/app/apps/web/.next/static/{G_4ofKI9v9ARC_lb9JILZ → 8tTWPvUhtatZEoocIhamh}/_buildManifest.js +0 -0
  439. /package/app/apps/web/.next/static/{G_4ofKI9v9ARC_lb9JILZ → 8tTWPvUhtatZEoocIhamh}/_clientMiddlewareManifest.js +0 -0
  440. /package/app/apps/web/.next/static/{G_4ofKI9v9ARC_lb9JILZ → 8tTWPvUhtatZEoocIhamh}/_ssgManifest.js +0 -0
@@ -0,0 +1,266 @@
1
+ import { execSync } from "node:child_process";
2
+ import { existsSync, readFileSync, readdirSync, statSync, openSync, readSync, closeSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+
6
+ export const runtime = "nodejs";
7
+ export const dynamic = "force-dynamic";
8
+
9
+ /**
10
+ * GET /api/runs?since=24h
11
+ *
12
+ * Mirrors `fleetlens runs --json`. Returns a snapshot of currently-running
13
+ * LLM subprocesses (week_digest / top_session / day_digest / entry_enrich)
14
+ * plus aggregated token spend in the requested window.
15
+ */
16
+
17
+ const KIND_MARKERS: Array<{ kind: string; marker: RegExp }> = [
18
+ { kind: "week_digest", marker: /weekly retrospective writer/i },
19
+ { kind: "top_session", marker: /editorial perception layer for ONE session/i },
20
+ { kind: "day_digest", marker: /single local day into a short, honest narrative/i },
21
+ { kind: "entry_enrich", marker: /per[- ]entry|enrich.{0,40}entry|brief_summary/i },
22
+ ];
23
+
24
+ function detectKind(cmdline: string): string {
25
+ for (const { kind, marker } of KIND_MARKERS) {
26
+ if (marker.test(cmdline)) return kind;
27
+ }
28
+ return "unknown";
29
+ }
30
+
31
+ function parseModel(cmdline: string): string {
32
+ const m = cmdline.match(/--model\s+(\S+)/);
33
+ return m ? m[1]! : "?";
34
+ }
35
+
36
+ type ActiveRun = {
37
+ pid: number;
38
+ kind: string;
39
+ model: string;
40
+ elapsed_s: number;
41
+ cpu_time: string;
42
+ };
43
+
44
+ function etimeToSec(s: string): number {
45
+ const m = s.match(/^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)$/);
46
+ if (!m) return 0;
47
+ const [, dStr, hStr, mStr, secStr] = m;
48
+ return Number(dStr ?? 0) * 86400 + Number(hStr ?? 0) * 3600 + Number(mStr ?? 0) * 60 + Number(secStr ?? 0);
49
+ }
50
+
51
+ function listActiveRuns(): ActiveRun[] {
52
+ let out: string;
53
+ try {
54
+ out = execSync("ps -axww -o pid,etime,time,command", { encoding: "utf-8" });
55
+ } catch {
56
+ return [];
57
+ }
58
+ const runs: ActiveRun[] = [];
59
+ for (const line of out.split("\n")) {
60
+ if (!line.includes("claude -p")) continue;
61
+ if (!line.includes("--append-system-prompt")) continue;
62
+ if (line.includes("grep")) continue;
63
+ const m = line.trim().match(/^(\d+)\s+(\S+)\s+([\d:.]+)\s+(.+)$/);
64
+ if (!m) continue;
65
+ const [, pidStr, etimeStr, cputime, command] = m;
66
+ runs.push({
67
+ pid: Number(pidStr),
68
+ kind: detectKind(command!),
69
+ model: parseModel(command!),
70
+ elapsed_s: etimeToSec(etimeStr!),
71
+ cpu_time: cputime!,
72
+ });
73
+ }
74
+ return runs.sort((a, b) => a.elapsed_s - b.elapsed_s);
75
+ }
76
+
77
+ const SPEND_PATH = join(homedir(), ".cclens", "llm-spend.jsonl");
78
+
79
+ type CompletedRun = {
80
+ ts: string;
81
+ kind: string;
82
+ ref: string;
83
+ model: string;
84
+ input_tokens: number;
85
+ output_tokens: number;
86
+ cost_usd: number;
87
+ };
88
+
89
+ function readSpend(sinceMs: number): CompletedRun[] {
90
+ if (!existsSync(SPEND_PATH)) return [];
91
+ const lines = readFileSync(SPEND_PATH, "utf-8").split("\n").filter(l => l.trim());
92
+ const out: CompletedRun[] = [];
93
+ for (const line of lines) {
94
+ try {
95
+ const r = JSON.parse(line);
96
+ const ts = Date.parse(r.ts);
97
+ if (Number.isNaN(ts) || ts < sinceMs) continue;
98
+ out.push({
99
+ ts: r.ts,
100
+ kind: r.kind ?? "?",
101
+ ref: r.ref ?? "",
102
+ model: r.model ?? "?",
103
+ input_tokens: r.input_tokens ?? 0,
104
+ output_tokens: r.output_tokens ?? 0,
105
+ cost_usd: r.cost_usd ?? 0,
106
+ });
107
+ } catch { /* skip */ }
108
+ }
109
+ return out;
110
+ }
111
+
112
+ function parseSince(s: string | null): number {
113
+ if (!s) return Date.now() - 24 * 3_600_000;
114
+ const m = s.match(/^(\d+)([smhd])$/);
115
+ if (m) {
116
+ const n = Number(m[1]);
117
+ const unit = m[2];
118
+ const mult = unit === "s" ? 1000 : unit === "m" ? 60_000 : unit === "h" ? 3_600_000 : 86_400_000;
119
+ return Date.now() - n * mult;
120
+ }
121
+ const t = Date.parse(s);
122
+ if (!Number.isNaN(t)) return t;
123
+ return Date.now() - 24 * 3_600_000;
124
+ }
125
+
126
+ const RUNS_DIR = join(homedir(), ".cclens", "llm-runs");
127
+
128
+ type TraceSummary = {
129
+ run_id: string;
130
+ kind: string;
131
+ model: string;
132
+ pid: number | null;
133
+ started_at: string;
134
+ ended_at: string | null;
135
+ elapsed_ms: number | null;
136
+ exit_code: number | null;
137
+ status: "running" | "ok" | "error" | "unknown";
138
+ content_chars: number | null;
139
+ output_tokens: number | null;
140
+ };
141
+
142
+ function listRecentTraces(limit: number): TraceSummary[] {
143
+ if (!existsSync(RUNS_DIR)) return [];
144
+ const files = readdirSync(RUNS_DIR)
145
+ .filter(f => f.endsWith(".jsonl"))
146
+ .map(f => ({ id: f.replace(/\.jsonl$/, ""), path: join(RUNS_DIR, f), mtime: statSync(join(RUNS_DIR, f)).mtimeMs }))
147
+ .sort((a, b) => b.mtime - a.mtime)
148
+ .slice(0, limit);
149
+
150
+ const out: TraceSummary[] = [];
151
+ for (const f of files) {
152
+ let start: { ts?: string; kind?: string; model?: string } | null = null;
153
+ let spawned: { pid?: number } | null = null;
154
+ let end: { ts?: string; elapsed_ms?: number; exit_code?: number; content_chars?: number; output_tokens?: number } | null = null;
155
+ let spawnError: { ts?: string } | null = null;
156
+
157
+ try {
158
+ // Read first ~16KB (start + spawned + maybe payload) and last ~4KB (end record)
159
+ const stat = statSync(f.path);
160
+ const headSize = Math.min(16_384, stat.size);
161
+ const tailSize = Math.min(4_096, stat.size);
162
+ const buf = Buffer.alloc(headSize);
163
+ const fd = openSync(f.path, "r");
164
+ try {
165
+ readSync(fd, buf, 0, headSize, 0);
166
+ } finally {
167
+ closeSync(fd);
168
+ }
169
+ const head = buf.toString("utf-8");
170
+ // Parse every _meta record visible in head — start, spawned, AND end /
171
+ // spawn_error. Previously end/spawn_error were only checked in the tail
172
+ // block, which got skipped when the file fit entirely in headSize. That
173
+ // left small completed traces (~10-15KB entry-enrich files) stuck at
174
+ // status="running" forever, even though their end record was already in
175
+ // the head buffer.
176
+ for (const line of head.split("\n")) {
177
+ if (!line.trim()) continue;
178
+ try {
179
+ const obj = JSON.parse(line) as { _meta?: { type?: string; ts?: string; kind?: string; model?: string; pid?: number; elapsed_ms?: number; exit_code?: number; content_chars?: number; output_tokens?: number } };
180
+ const t = obj._meta?.type;
181
+ if (t === "start") start = obj._meta!;
182
+ else if (t === "spawned") spawned = obj._meta!;
183
+ else if (t === "end") end = obj._meta!;
184
+ else if (t === "spawn_error") spawnError = obj._meta!;
185
+ } catch { /* skip */ }
186
+ }
187
+
188
+ if (!end && !spawnError && stat.size > headSize) {
189
+ const tailBuf = Buffer.alloc(tailSize);
190
+ const fd2 = openSync(f.path, "r");
191
+ try {
192
+ readSync(fd2, tailBuf, 0, tailSize, stat.size - tailSize);
193
+ } finally {
194
+ closeSync(fd2);
195
+ }
196
+ const tail = tailBuf.toString("utf-8");
197
+ for (const line of tail.split("\n").reverse()) {
198
+ if (!line.trim()) continue;
199
+ try {
200
+ const obj = JSON.parse(line) as { _meta?: { type?: string; ts?: string; elapsed_ms?: number; exit_code?: number; content_chars?: number; output_tokens?: number } };
201
+ if (obj._meta?.type === "end") { end = obj._meta; break; }
202
+ if (obj._meta?.type === "spawn_error") { spawnError = obj._meta; break; }
203
+ } catch { /* skip */ }
204
+ }
205
+ }
206
+ } catch { /* skip */ }
207
+
208
+ const status: TraceSummary["status"] =
209
+ end ? (end.exit_code === 0 ? "ok" : "error")
210
+ : spawnError ? "error"
211
+ : start ? "running"
212
+ : "unknown";
213
+
214
+ out.push({
215
+ run_id: f.id,
216
+ kind: start?.kind ?? "?",
217
+ model: start?.model ?? "?",
218
+ pid: spawned?.pid ?? null,
219
+ started_at: start?.ts ?? "",
220
+ ended_at: end?.ts ?? null,
221
+ elapsed_ms: end?.elapsed_ms ?? null,
222
+ exit_code: end?.exit_code ?? null,
223
+ status,
224
+ content_chars: end?.content_chars ?? null,
225
+ output_tokens: end?.output_tokens ?? null,
226
+ });
227
+ }
228
+ return out;
229
+ }
230
+
231
+ export async function GET(req: Request): Promise<Response> {
232
+ const url = new URL(req.url);
233
+ const sinceMs = parseSince(url.searchParams.get("since"));
234
+ const traceLimit = Number(url.searchParams.get("trace_limit") ?? "30");
235
+ const active = listActiveRuns();
236
+ const completed = readSpend(sinceMs);
237
+ const traces = listRecentTraces(traceLimit);
238
+
239
+ type Totals = { ops: number; input_tokens: number; output_tokens: number; cost_usd: number };
240
+ const totals: Totals = { ops: completed.length, input_tokens: 0, output_tokens: 0, cost_usd: 0 };
241
+ const byKind: Record<string, Totals> = {};
242
+ for (const r of completed) {
243
+ totals.input_tokens += r.input_tokens;
244
+ totals.output_tokens += r.output_tokens;
245
+ totals.cost_usd += r.cost_usd;
246
+ const k = byKind[r.kind] ?? { ops: 0, input_tokens: 0, output_tokens: 0, cost_usd: 0 };
247
+ k.ops += 1;
248
+ k.input_tokens += r.input_tokens;
249
+ k.output_tokens += r.output_tokens;
250
+ k.cost_usd += r.cost_usd;
251
+ byKind[r.kind] = k;
252
+ }
253
+
254
+ return new Response(JSON.stringify({
255
+ generated_at: new Date().toISOString(),
256
+ active,
257
+ completed_since_ms: sinceMs,
258
+ totals,
259
+ by_kind: byKind,
260
+ completed,
261
+ traces,
262
+ }, null, 2), {
263
+ status: 200,
264
+ headers: { "content-type": "application/json" },
265
+ });
266
+ }
@@ -0,0 +1,35 @@
1
+ import { NextResponse } from "next/server";
2
+ import { readSettings, writeSettings, monthToDateSpend } from "@claude-lens/entries/node";
3
+ import { SettingsUpdateSchema } from "@/lib/validate-settings";
4
+
5
+ export const runtime = "nodejs";
6
+
7
+ export async function GET() {
8
+ return NextResponse.json({
9
+ settings: readSettings(),
10
+ month_to_date_spend_usd: monthToDateSpend(),
11
+ });
12
+ }
13
+
14
+ export async function PUT(req: Request) {
15
+ let raw: unknown;
16
+ try {
17
+ raw = await req.json();
18
+ } catch {
19
+ return NextResponse.json({ error: "invalid JSON body" }, { status: 400 });
20
+ }
21
+ const parsed = SettingsUpdateSchema.safeParse(raw);
22
+ if (!parsed.success) {
23
+ return NextResponse.json(
24
+ { error: "schema validation failed", issues: parsed.error.issues },
25
+ { status: 400 },
26
+ );
27
+ }
28
+ // Preserve other on-disk fields (model, monthlyBudgetUsd) — UI no longer edits
29
+ // them, but the settings module and queue still read them. Only enabled flips.
30
+ const current = readSettings();
31
+ writeSettings({
32
+ ai_features: { ...current.ai_features, enabled: parsed.data.ai_features.enabled },
33
+ });
34
+ return NextResponse.json({ ok: true });
35
+ }
@@ -0,0 +1,193 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { ChevronDown, ChevronRight, Layers } from "lucide-react";
5
+ import type { DayDigest, Entry } from "@claude-lens/entries";
6
+ import type { GanttDay, ParallelismBurst } from "@claude-lens/parser";
7
+ import { DayDigestView } from "@/components/day-digest-view";
8
+ import { GanttChart, type SessionEntrySummary } from "../../parallelism/gantt-chart";
9
+ import { BackfillDrawer, type BackfillRow } from "@/components/backfill-drawer";
10
+ import { DateNav, type DayInfo } from "@/components/date-nav";
11
+
12
+ export function DayView({
13
+ date,
14
+ today,
15
+ prev,
16
+ next,
17
+ initial,
18
+ entries,
19
+ aiEnabled,
20
+ gantt,
21
+ bursts,
22
+ sessionEntries,
23
+ backfillRows,
24
+ dayStats,
25
+ }: {
26
+ date: string;
27
+ today: string;
28
+ prev: string;
29
+ next: string | null;
30
+ initial: DayDigest | null;
31
+ entries: Entry[];
32
+ aiEnabled: boolean;
33
+ gantt: GanttDay;
34
+ bursts: ParallelismBurst[];
35
+ sessionEntries: Record<string, SessionEntrySummary>;
36
+ backfillRows: BackfillRow[];
37
+ dayStats: DayInfo[];
38
+ }) {
39
+ const [drawerOpen, setDrawerOpen] = useState(false);
40
+ // Narrative section is suppressed when every entry is `skipped_trivial` —
41
+ // that's a "warm-up only" day with nothing to summarize, so the section
42
+ // would just be a header above an empty placeholder. Keep the timeline
43
+ // accessible via its own collapsible.
44
+ const allTrivial = entries.length > 0
45
+ && entries.every((e) => e.enrichment.status === "skipped_trivial");
46
+ const hasNarrative = entries.length > 0 && !allTrivial;
47
+ const hasTimeline = gantt.sessions.length > 0;
48
+
49
+ const fmtDate = new Date(`${date}T12:00:00`).toLocaleDateString("en-US", {
50
+ weekday: "long", month: "long", day: "numeric", year: "numeric",
51
+ });
52
+
53
+ const pendingCount = backfillRows.filter((r) => r.status === "pending").length;
54
+
55
+ return (
56
+ <>
57
+ <nav
58
+ style={{
59
+ padding: "14px 40px",
60
+ display: "flex",
61
+ gap: 12,
62
+ fontSize: 12,
63
+ borderBottom: "1px solid var(--af-border-subtle)",
64
+ alignItems: "center",
65
+ flexWrap: "wrap",
66
+ }}
67
+ >
68
+ <DateNav
69
+ date={date}
70
+ today={today}
71
+ prevDay={prev}
72
+ nextDay={next ?? undefined}
73
+ dayStats={dayStats}
74
+ />
75
+
76
+ <button
77
+ type="button"
78
+ onClick={() => setDrawerOpen(true)}
79
+ style={{
80
+ marginLeft: "auto",
81
+ display: "inline-flex",
82
+ alignItems: "center",
83
+ gap: 5,
84
+ padding: "5px 10px",
85
+ background: "transparent",
86
+ border: "1px solid var(--af-border-subtle)",
87
+ borderRadius: 6,
88
+ fontSize: 11,
89
+ color: "var(--af-text-secondary)",
90
+ cursor: "pointer",
91
+ }}
92
+ title="Open the backfill multi-select drawer"
93
+ >
94
+ <Layers size={12} />
95
+ Backfill digests
96
+ {pendingCount > 0 && (
97
+ <span
98
+ style={{
99
+ fontSize: 10,
100
+ color: "#ed8936",
101
+ fontWeight: 700,
102
+ }}
103
+ >
104
+ {pendingCount}
105
+ </span>
106
+ )}
107
+ </button>
108
+ </nav>
109
+
110
+ {!hasNarrative && !hasTimeline ? (
111
+ <div
112
+ style={{
113
+ padding: "60px 40px",
114
+ textAlign: "center",
115
+ color: "var(--af-text-secondary)",
116
+ }}
117
+ >
118
+ <div style={{ fontSize: 14, marginBottom: 6 }}>{fmtDate}</div>
119
+ <div style={{ fontSize: 13, color: "var(--af-text-tertiary)" }}>
120
+ No Claude Code activity on this day.
121
+ </div>
122
+ </div>
123
+ ) : (
124
+ <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
125
+ {hasNarrative && (
126
+ <Section label="Narrative" defaultOpen>
127
+ <DayDigestView
128
+ initial={initial}
129
+ entries={entries}
130
+ date={date}
131
+ aiEnabled={aiEnabled}
132
+ />
133
+ </Section>
134
+ )}
135
+ {hasTimeline && (
136
+ <Section label="Timeline & concurrency" defaultOpen>
137
+ <div style={{ padding: "8px 40px 40px" }}>
138
+ <GanttChart gantt={gantt} bursts={bursts} sessionEntries={sessionEntries} />
139
+ </div>
140
+ </Section>
141
+ )}
142
+ </div>
143
+ )}
144
+
145
+ <BackfillDrawer
146
+ open={drawerOpen}
147
+ onClose={() => setDrawerOpen(false)}
148
+ rows={backfillRows}
149
+ aiEnabled={aiEnabled}
150
+ />
151
+ </>
152
+ );
153
+ }
154
+
155
+ function Section({
156
+ label,
157
+ defaultOpen = true,
158
+ children,
159
+ }: {
160
+ label: string;
161
+ defaultOpen?: boolean;
162
+ children: React.ReactNode;
163
+ }) {
164
+ const [open, setOpen] = useState(defaultOpen);
165
+ return (
166
+ <div style={{ borderBottom: "1px solid var(--af-border-subtle)" }}>
167
+ <button
168
+ type="button"
169
+ onClick={() => setOpen((v) => !v)}
170
+ style={{
171
+ width: "100%",
172
+ padding: "12px 40px",
173
+ background: "transparent",
174
+ border: "none",
175
+ textAlign: "left",
176
+ display: "flex",
177
+ alignItems: "center",
178
+ gap: 8,
179
+ cursor: "pointer",
180
+ fontSize: 11,
181
+ fontWeight: 700,
182
+ color: "var(--af-text-tertiary)",
183
+ textTransform: "uppercase",
184
+ letterSpacing: "0.08em",
185
+ }}
186
+ >
187
+ {open ? <ChevronDown size={13} /> : <ChevronRight size={13} />}
188
+ {label}
189
+ </button>
190
+ {open && <div>{children}</div>}
191
+ </div>
192
+ );
193
+ }
@@ -0,0 +1,175 @@
1
+ import { listSessions, getSession } from "@/lib/data";
2
+ import {
3
+ buildGanttDay,
4
+ computeParallelismBursts,
5
+ computeBurstsFromSessions,
6
+ dailyActivity,
7
+ type GanttDay,
8
+ type ParallelismBurst,
9
+ } from "@claude-lens/parser";
10
+ import { toLocalDay as toLocalDayParser } from "@claude-lens/parser";
11
+ import { readDayDigest, listEntriesForDay } from "@claude-lens/entries/fs";
12
+ import { readSettings, buildDeterministicDigest, getTodayDigestFromCache } from "@claude-lens/entries/node";
13
+ import type { DayDigest } from "@claude-lens/entries";
14
+ import { isValidDate, todayLocal, toLocalDay } from "@/lib/entries";
15
+ import { buildEntriesIndex } from "@/lib/entries-index";
16
+ import type { SessionEntrySummary } from "../../parallelism/gantt-chart";
17
+ import type { BackfillRow } from "@/components/backfill-drawer";
18
+ import type { DayInfo } from "@/components/date-nav";
19
+ import { DayView } from "./day-view";
20
+ import Link from "next/link";
21
+ import { notFound } from "next/navigation";
22
+
23
+ export const dynamic = "force-dynamic";
24
+
25
+ const BACKFILL_DAYS = 30;
26
+
27
+ function addDays(date: string, n: number): string {
28
+ const [y, m, d] = date.split("-").map(Number);
29
+ const dt = new Date(y!, (m ?? 1) - 1, d, 12);
30
+ dt.setDate(dt.getDate() + n);
31
+ return `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, "0")}-${String(dt.getDate()).padStart(2, "0")}`;
32
+ }
33
+
34
+ function buildBackfillRows(): BackfillRow[] {
35
+ const out: BackfillRow[] = [];
36
+ const now = Date.now();
37
+ for (let i = 0; i < BACKFILL_DAYS; i++) {
38
+ const d = toLocalDay(now - i * 86_400_000);
39
+ const entries = listEntriesForDay(d);
40
+ const digest = readDayDigest(d);
41
+ const status: BackfillRow["status"] = entries.length === 0 ? "empty"
42
+ : digest && digest.headline ? "generated"
43
+ : "pending";
44
+ const label = i === 0 ? "Today"
45
+ : i === 1 ? "Yesterday"
46
+ : new Date(`${d}T12:00:00`).toLocaleDateString("en-US", {
47
+ weekday: "short", month: "short", day: "numeric",
48
+ });
49
+ out.push({
50
+ date: d,
51
+ day_label: label,
52
+ entry_count: entries.length,
53
+ pr_count: entries.reduce((s, e) => s + e.pr_titles.length, 0),
54
+ status,
55
+ });
56
+ }
57
+ return out;
58
+ }
59
+
60
+ export default async function DayPage({
61
+ params,
62
+ }: {
63
+ params: Promise<{ date: string }>;
64
+ }) {
65
+ const { date } = await params;
66
+ if (!isValidDate(date)) return notFound();
67
+
68
+ const today = todayLocal();
69
+ if (date > today) {
70
+ return (
71
+ <div style={{ padding: "40px" }}>
72
+ <h1>Future date</h1>
73
+ <p>Day views only exist for past and current days.</p>
74
+ <Link href={`/day/${today}`}>Go to today →</Link>
75
+ </div>
76
+ );
77
+ }
78
+
79
+ // ---- Narrative side (digest + entries) ----
80
+ const settings = readSettings();
81
+ const aiEnabled = settings.ai_features.enabled;
82
+ const entries = listEntriesForDay(date);
83
+ // Today's digest lives only in the 10-min in-memory TTL cache — never on disk.
84
+ // Falling back to deterministic-only would erase the LLM narrative the user
85
+ // just generated; the today branch reads the cache instead of disk.
86
+ let initial: DayDigest | null = date === today
87
+ ? getTodayDigestFromCache(date, Date.now())
88
+ : readDayDigest(date);
89
+ if (!initial && entries.length > 0) initial = buildDeterministicDigest(date, entries);
90
+
91
+ // ---- Timeline side (Gantt) ----
92
+ const [y, m, d] = date.split("-").map(Number) as [number, number, number];
93
+ const dayStartMs = new Date(y, m - 1, d).getTime();
94
+ const dayEndMs = new Date(y, m - 1, d + 1).getTime();
95
+ const filterStartMs = dayStartMs - 24 * 60 * 60 * 1000;
96
+ const filterEndMs = dayEndMs + 24 * 60 * 60 * 1000;
97
+ const allSessions = await listSessions();
98
+ const candidates = allSessions.filter((s) => {
99
+ if (!s.firstTimestamp) return false;
100
+ const startMs = Date.parse(s.firstTimestamp);
101
+ if (Number.isNaN(startMs)) return false;
102
+ const endMs = s.lastTimestamp ? Date.parse(s.lastTimestamp) : startMs;
103
+ return endMs >= filterStartMs && startMs <= filterEndMs;
104
+ });
105
+ const details = (
106
+ await Promise.all(candidates.slice(0, 80).map((s) => getSession(s.id)))
107
+ ).filter((d): d is NonNullable<typeof d> => !!d);
108
+ const gantt: GanttDay = buildGanttDay(details, date);
109
+ const bursts: ParallelismBurst[] = computeParallelismBursts(gantt);
110
+
111
+ const entriesIndex = await buildEntriesIndex();
112
+ const sessionEntries: Record<string, SessionEntrySummary> = {};
113
+ for (const s of gantt.sessions) {
114
+ const list = entriesIndex.bySession.get(s.id) ?? [];
115
+ const e = list.find((e) => e.local_day === date);
116
+ if (!e) continue;
117
+ sessionEntries[s.id] = {
118
+ outcome: e.enrichment.outcome ?? null,
119
+ briefSummary: e.enrichment.brief_summary ?? null,
120
+ enrichmentStatus: e.enrichment.status,
121
+ localDay: e.local_day,
122
+ };
123
+ }
124
+
125
+ const prev = addDays(date, -1);
126
+ const next = addDays(date, 1);
127
+ const backfillRows = buildBackfillRows();
128
+
129
+ // Calendar popover stats: per-day activity + parallelism stats so the
130
+ // calendar tints by airtime and dots days with concurrency bursts.
131
+ const buckets = dailyActivity(allSessions);
132
+ const allBursts = computeBurstsFromSessions(allSessions);
133
+ type DayBurstAgg = { totalMs: number; count: number; peak: number };
134
+ const burstsByDay = new Map<string, DayBurstAgg>();
135
+ for (const b of allBursts) {
136
+ const day = toLocalDayParser(b.startMs);
137
+ const e = burstsByDay.get(day) ?? { totalMs: 0, count: 0, peak: 0 };
138
+ e.totalMs += b.endMs - b.startMs;
139
+ e.count += 1;
140
+ if (b.peak > e.peak) e.peak = b.peak;
141
+ burstsByDay.set(day, e);
142
+ }
143
+ const dayKeys = new Set<string>();
144
+ for (const b of buckets) if (b.sessions > 0) dayKeys.add(b.date);
145
+ for (const d of burstsByDay.keys()) dayKeys.add(d);
146
+ const dayStats: DayInfo[] = Array.from(dayKeys).map((dt) => {
147
+ const a = buckets.find((b) => b.date === dt);
148
+ const burst = burstsByDay.get(dt);
149
+ return {
150
+ date: dt,
151
+ sessions: a?.sessions ?? 0,
152
+ airTimeMs: a?.airTimeMs ?? 0,
153
+ parallelMs: burst?.totalMs ?? 0,
154
+ burstCount: burst?.count ?? 0,
155
+ peakConcurrency: burst?.peak ?? 0,
156
+ };
157
+ });
158
+
159
+ return (
160
+ <DayView
161
+ date={date}
162
+ today={today}
163
+ prev={prev}
164
+ next={next <= today ? next : null}
165
+ initial={initial}
166
+ entries={entries}
167
+ aiEnabled={aiEnabled}
168
+ gantt={gantt}
169
+ bursts={bursts}
170
+ sessionEntries={sessionEntries}
171
+ backfillRows={backfillRows}
172
+ dayStats={dayStats}
173
+ />
174
+ );
175
+ }
@@ -0,0 +1,8 @@
1
+ import { redirect } from "next/navigation";
2
+ import { todayLocal } from "@/lib/entries";
3
+
4
+ export const dynamic = "force-dynamic";
5
+
6
+ export default function DayIndexRedirect() {
7
+ redirect(`/day/${todayLocal()}`);
8
+ }
@@ -0,0 +1,15 @@
1
+ import { redirect } from "next/navigation";
2
+ import { isValidDate } from "@/lib/entries";
3
+ import { notFound } from "next/navigation";
4
+
5
+ export const dynamic = "force-dynamic";
6
+
7
+ export default async function LegacyDigestRedirect({
8
+ params,
9
+ }: {
10
+ params: Promise<{ date: string }>;
11
+ }) {
12
+ const { date } = await params;
13
+ if (!isValidDate(date)) return notFound();
14
+ redirect(`/day/${date}`);
15
+ }