fleetlens 0.13.2 → 0.15.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 (230) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +4 -1
  3. package/app/apps/web/.next/build-manifest.json +3 -3
  4. package/app/apps/web/.next/prerender-manifest.json +3 -3
  5. package/app/apps/web/.next/routes-manifest.json +21 -3
  6. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  7. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  8. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/app/apps/web/.next/server/app/_not-found/page.js +1 -1
  14. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/app/apps/web/.next/server/app/api/ask/route.js +3 -3
  17. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  18. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +4 -4
  19. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  20. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +4 -4
  21. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/digest/month-index/route.js +2 -2
  23. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  24. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +4 -4
  25. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  26. package/app/apps/web/.next/server/app/api/digest/week-index/route.js +2 -2
  27. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js +4 -4
  29. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  31. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/api/settings/route.js +4 -3
  33. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  34. package/app/apps/web/.next/server/app/api/team/autostart/route/app-paths-manifest.json +3 -0
  35. package/app/apps/web/.next/server/app/api/team/autostart/route.js +7 -0
  36. package/app/apps/web/.next/server/app/api/team/autostart/route.js.nft.json +1 -0
  37. package/app/apps/web/.next/server/app/api/team/autostart/route_client-reference-manifest.js +3 -0
  38. package/app/apps/web/.next/server/app/api/team/onboarding/start/route/app-paths-manifest.json +3 -0
  39. package/app/apps/web/.next/server/app/api/team/onboarding/start/route/build-manifest.json +9 -0
  40. package/app/apps/web/.next/server/app/api/team/onboarding/start/route/server-reference-manifest.json +4 -0
  41. package/app/apps/web/.next/server/app/api/team/onboarding/start/route.js +8 -0
  42. package/app/apps/web/.next/server/app/api/team/onboarding/start/route.js.map +5 -0
  43. package/app/apps/web/.next/server/app/api/team/onboarding/start/route.js.nft.json +1 -0
  44. package/app/apps/web/.next/server/app/api/team/onboarding/start/route_client-reference-manifest.js +3 -0
  45. package/app/apps/web/.next/server/app/api/team/sync-projects/route/app-paths-manifest.json +3 -0
  46. package/app/apps/web/.next/server/app/api/team/sync-projects/route/build-manifest.json +9 -0
  47. package/app/apps/web/.next/server/app/api/team/sync-projects/route/server-reference-manifest.json +4 -0
  48. package/app/apps/web/.next/server/app/api/team/sync-projects/route.js +8 -0
  49. package/app/apps/web/.next/server/app/api/team/sync-projects/route.js.map +5 -0
  50. package/app/apps/web/.next/server/app/api/team/sync-projects/route.js.nft.json +1 -0
  51. package/app/apps/web/.next/server/app/api/team/sync-projects/route_client-reference-manifest.js +3 -0
  52. package/app/apps/web/.next/server/app/changelog/page.js +1 -1
  53. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  54. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  55. package/app/apps/web/.next/server/app/day/[date]/page.js +1 -1
  56. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  57. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  58. package/app/apps/web/.next/server/app/day/page.js +1 -1
  59. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  60. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  61. package/app/apps/web/.next/server/app/digest/[date]/page.js +1 -1
  62. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  63. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  64. package/app/apps/web/.next/server/app/digest/page.js +1 -1
  65. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  66. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  67. package/app/apps/web/.next/server/app/insights/[key]/page.js +1 -1
  68. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  69. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  70. package/app/apps/web/.next/server/app/insights/page.js +1 -1
  71. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  72. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  73. package/app/apps/web/.next/server/app/page.js +2 -2
  74. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  75. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  76. package/app/apps/web/.next/server/app/parallelism/page.js +1 -1
  77. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  78. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  79. package/app/apps/web/.next/server/app/print/[key]/page.js +1 -1
  80. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -1
  81. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
  82. package/app/apps/web/.next/server/app/projects/[slug]/page.js +2 -2
  83. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  84. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  85. package/app/apps/web/.next/server/app/projects/page.js +1 -1
  86. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  87. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  88. package/app/apps/web/.next/server/app/runs/page.js +1 -1
  89. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  90. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  91. package/app/apps/web/.next/server/app/sessions/[id]/page.js +3 -3
  92. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  93. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  94. package/app/apps/web/.next/server/app/sessions/page.js +1 -1
  95. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  96. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  97. package/app/apps/web/.next/server/app/settings/page.js +2 -2
  98. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  99. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  100. package/app/apps/web/.next/server/app/team/onboarding/page/app-paths-manifest.json +3 -0
  101. package/app/apps/web/.next/server/app/team/onboarding/page/build-manifest.json +17 -0
  102. package/app/apps/web/.next/server/app/team/onboarding/page/next-font-manifest.json +6 -0
  103. package/app/apps/web/.next/server/app/team/onboarding/page/react-loadable-manifest.json +1 -0
  104. package/app/apps/web/.next/server/app/team/onboarding/page/server-reference-manifest.json +4 -0
  105. package/app/apps/web/.next/server/app/team/onboarding/page.js +19 -0
  106. package/app/apps/web/.next/server/app/team/onboarding/page.js.map +5 -0
  107. package/app/apps/web/.next/server/app/team/onboarding/page.js.nft.json +1 -0
  108. package/app/apps/web/.next/server/app/team/onboarding/page_client-reference-manifest.js +3 -0
  109. package/app/apps/web/.next/server/app/team/page.js +3 -2
  110. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  111. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  112. package/app/apps/web/.next/server/app/usage/page.js +1 -1
  113. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  114. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  115. package/app/apps/web/.next/server/app-paths-manifest.json +4 -1
  116. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_team_onboarding_start_route_actions_0zeptl_.js +3 -0
  117. package/app/apps/web/.next/server/chunks/0fuv_zod_v4_classic_external_0.z.vap.js +39 -0
  118. package/app/apps/web/.next/server/chunks/[root-of-the-server]__038-.1r._.js +6 -0
  119. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0~utv~v._.js → [root-of-the-server]__03ewxxu._.js} +2 -2
  120. package/app/apps/web/.next/server/chunks/[root-of-the-server]__03rmbz6._.js +3 -0
  121. package/app/apps/web/.next/server/chunks/[root-of-the-server]__065lib8._.js +3 -0
  122. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0e.f-t.._.js → [root-of-the-server]__0a0~7d6._.js} +2 -2
  123. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0gril0u._.js → [root-of-the-server]__0acikq.._.js} +2 -2
  124. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0et2sqb._.js +3 -0
  125. package/app/apps/web/.next/server/chunks/{[externals]__09v47rg._.js → [root-of-the-server]__0jbc7tz._.js} +2 -2
  126. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0mq0or2._.js +3 -0
  127. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0mvl0qn._.js +3 -0
  128. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0n79hpm._.js → [root-of-the-server]__0ow1kn1._.js} +4 -4
  129. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0~xt99s._.js +3 -0
  130. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_team_autostart_route_actions_10-4s71.js +3 -0
  131. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_team_sync-projects_route_actions_0r_2f5n.js +3 -0
  132. package/app/apps/web/.next/server/chunks/node_modules_next_036my~r._.js +13 -0
  133. package/app/apps/web/.next/server/chunks/packages_09wmnv.._.js +3 -0
  134. package/app/apps/web/.next/server/chunks/packages_0o6.gpk._.js +3 -0
  135. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +1 -1
  136. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +1 -1
  137. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0z7mg0b._.js → [root-of-the-server]__08l86e-._.js} +2 -2
  138. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0a7n44-._.js +3 -0
  139. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0c00i76._.js +3 -0
  140. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0i.q-1h._.js +3 -0
  141. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +1 -1
  142. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0stu~~r._.js +3 -0
  143. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ufi3.w._.js +3 -0
  144. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0o03ymy._.js → [root-of-the-server]__10~b4bf._.js} +2 -2
  145. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  146. package/app/apps/web/.next/server/chunks/ssr/apps_web_0.97l5.._.js +3 -0
  147. package/app/apps/web/.next/server/chunks/ssr/{apps_web_app_settings_0u6z6rj._.js → apps_web_0q2x4a~._.js} +2 -2
  148. package/app/apps/web/.next/server/chunks/ssr/apps_web_114yo0v._.js +3 -0
  149. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_team_onboarding_page_actions_0pss~.k.js +3 -0
  150. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0c-tpft._.js +1 -1
  151. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0txtsv5._.js +1 -1
  152. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
  153. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
  154. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_team-config_ts_10egg08._.js +39 -0
  155. package/app/apps/web/.next/server/chunks/ssr/{node_modules_next_dist_0t-hj0x._.js → node_modules_0yrkyef._.js} +2 -2
  156. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_0w2y7fz._.js +2 -2
  157. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0jxvcfi.js +2 -2
  158. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0s5yhs4.js +4 -0
  159. package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +1 -1
  160. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0mx_509._.js +1 -1
  161. package/app/apps/web/.next/server/functions-config-manifest.json +3 -1
  162. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  163. package/app/apps/web/.next/server/middleware-manifest.json +5 -5
  164. package/app/apps/web/.next/server/pages/500.html +1 -1
  165. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  166. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  167. package/app/apps/web/.next/static/chunks/{0wwcx42ng8i2e.js → 0-3_u.90d79wi.js} +1 -1
  168. package/app/apps/web/.next/static/chunks/00a9oyw~h5i1p.js +1 -0
  169. package/app/apps/web/.next/static/chunks/040s42ypidk7s.css +1 -0
  170. package/app/apps/web/.next/static/chunks/06eiwghjkkbnh.js +1 -0
  171. package/app/apps/web/.next/static/chunks/06qeg4pt5jdqs.js +1 -0
  172. package/app/apps/web/.next/static/chunks/{0e_fzy0n8ij-o.js → 0u6gxpqhl0gc7.js} +1 -1
  173. package/app/apps/web/.next/static/chunks/18cj08-la37o-.js +1 -0
  174. package/app/apps/web/app/api/team/autostart/route.ts +41 -0
  175. package/app/apps/web/app/api/team/onboarding/start/route.ts +96 -0
  176. package/app/apps/web/app/api/team/sync-projects/route.ts +39 -0
  177. package/app/apps/web/app/globals.css +82 -0
  178. package/app/apps/web/app/settings/ai-features-form.tsx +1 -1
  179. package/app/apps/web/app/settings/page.tsx +21 -7
  180. package/app/apps/web/app/{settings → team}/force-sync-button.tsx +2 -4
  181. package/app/apps/web/app/team/onboarding/onboarding-wizard.tsx +503 -0
  182. package/app/apps/web/app/team/onboarding/page.tsx +28 -0
  183. package/app/apps/web/app/team/page.tsx +60 -81
  184. package/app/apps/web/app/{settings/team-connection-section.tsx → team/sync-activity-section.tsx} +6 -23
  185. package/app/apps/web/app/team/synced-projects-form.tsx +201 -0
  186. package/app/apps/web/app/team/synced-projects-section.tsx +37 -0
  187. package/app/apps/web/components/autostart-toggle.tsx +59 -0
  188. package/app/apps/web/components/previous-cycles-trend.tsx +4 -1
  189. package/app/apps/web/components/project-sync-picker.tsx +109 -0
  190. package/app/apps/web/components/team-chip.tsx +1 -1
  191. package/app/apps/web/components/team-welcome-banner.tsx +1 -1
  192. package/app/apps/web/lib/autostart-data.ts +31 -0
  193. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  194. package/app/apps/web/lib/sync-projects-data.ts +36 -0
  195. package/app/apps/web/lib/team-config.ts +21 -4
  196. package/app/apps/web/package.json +1 -1
  197. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  198. package/dist/daemon-worker.js +2089 -1622
  199. package/dist/index.js +1462 -230
  200. package/package.json +1 -1
  201. package/app/apps/web/.next/server/app/api/team-config/route/app-paths-manifest.json +0 -3
  202. package/app/apps/web/.next/server/app/api/team-config/route.js +0 -8
  203. package/app/apps/web/.next/server/app/api/team-config/route.js.nft.json +0 -1
  204. package/app/apps/web/.next/server/app/api/team-config/route_client-reference-manifest.js +0 -3
  205. package/app/apps/web/.next/server/chunks/[root-of-the-server]__08agijy._.js +0 -3
  206. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0atn.dt._.js +0 -3
  207. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0b.b7~1._.js +0 -3
  208. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0i06ito._.js +0 -3
  209. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0y5p73y._.js +0 -3
  210. package/app/apps/web/.next/server/chunks/_0euqdko._.js +0 -49
  211. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_team-config_route_actions_0ad2gak.js +0 -3
  212. package/app/apps/web/.next/server/chunks/packages_0c-sz9n._.js +0 -3
  213. package/app/apps/web/.next/server/chunks/packages_0wywuu.._.js +0 -3
  214. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__09yxy53._.js +0 -3
  215. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0exckd4._.js +0 -3
  216. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0n-ax-5._.js +0 -3
  217. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0q9qy0z._.js +0 -3
  218. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_team_team-sync-form_tsx_0choz0h._.js +0 -3
  219. package/app/apps/web/.next/static/chunks/083~hzkv577.5.css +0 -1
  220. package/app/apps/web/.next/static/chunks/0h.ua.-myj.6z.js +0 -1
  221. package/app/apps/web/.next/static/chunks/0uyctl-m8iydb.js +0 -1
  222. package/app/apps/web/.next/static/chunks/14joqbsr9ihhu.js +0 -1
  223. package/app/apps/web/app/api/team-config/route.ts +0 -39
  224. package/app/apps/web/app/team/team-sync-form.tsx +0 -144
  225. /package/app/apps/web/.next/server/app/api/{team-config → team/autostart}/route/build-manifest.json +0 -0
  226. /package/app/apps/web/.next/server/app/api/{team-config → team/autostart}/route/server-reference-manifest.json +0 -0
  227. /package/app/apps/web/.next/server/app/api/{team-config → team/autostart}/route.js.map +0 -0
  228. /package/app/apps/web/.next/static/{bZs5UyzsYBqC6MFY5n-M_ → C4y6rare_ZCcXXQLc8ysA}/_buildManifest.js +0 -0
  229. /package/app/apps/web/.next/static/{bZs5UyzsYBqC6MFY5n-M_ → C4y6rare_ZCcXXQLc8ysA}/_clientMiddlewareManifest.js +0 -0
  230. /package/app/apps/web/.next/static/{bZs5UyzsYBqC6MFY5n-M_ → C4y6rare_ZCcXXQLc8ysA}/_ssgManifest.js +0 -0
@@ -298,6 +298,88 @@ input::placeholder {
298
298
  border-color: var(--af-surface-elevated);
299
299
  }
300
300
 
301
+ /* Tailwind v4 preflight defaults `border` utilities to currentColor, which
302
+ reads as a harsh black/white line. Fall back to the theme token. */
303
+ @layer base {
304
+ *,
305
+ ::after,
306
+ ::before {
307
+ border-color: var(--af-border-subtle);
308
+ }
309
+ }
310
+
311
+ /* Buttons + panels for management surfaces (team, settings, wizard). */
312
+ .af-btn,
313
+ .af-btn-primary,
314
+ .af-btn-danger {
315
+ display: inline-block;
316
+ border-radius: 8px;
317
+ padding: 6px 14px;
318
+ font-size: 13px;
319
+ transition: background 0.12s, border-color 0.12s;
320
+ }
321
+ .af-btn {
322
+ border: 1px solid var(--af-border-subtle);
323
+ background: var(--af-surface);
324
+ color: var(--af-text);
325
+ }
326
+ .af-btn:hover:not(:disabled) {
327
+ border-color: var(--af-accent);
328
+ }
329
+ .af-btn-primary {
330
+ border: 1px solid transparent;
331
+ background: var(--af-accent);
332
+ color: var(--background);
333
+ font-weight: 500;
334
+ }
335
+ .af-btn-primary:hover:not(:disabled) {
336
+ background: var(--af-accent-hover);
337
+ }
338
+ .af-btn-danger {
339
+ border: 1px solid var(--af-danger);
340
+ background: transparent;
341
+ color: var(--af-danger);
342
+ }
343
+ .af-btn-danger:hover:not(:disabled) {
344
+ background: var(--af-danger-subtle);
345
+ }
346
+ .af-btn:disabled,
347
+ .af-btn-primary:disabled,
348
+ .af-btn-danger:disabled {
349
+ opacity: 0.55;
350
+ cursor: default;
351
+ }
352
+ .af-panel {
353
+ background: var(--af-surface-elevated);
354
+ border: 1px solid var(--af-border-subtle);
355
+ border-radius: 8px;
356
+ }
357
+ .af-panel-danger {
358
+ background: var(--af-danger-subtle);
359
+ border: 1px solid var(--af-danger);
360
+ border-radius: 8px;
361
+ color: var(--af-danger);
362
+ }
363
+ .af-step-active {
364
+ background: var(--af-accent);
365
+ color: var(--background);
366
+ }
367
+ .af-chip {
368
+ display: inline-block;
369
+ border: 1px solid var(--af-border-subtle);
370
+ border-radius: 9999px;
371
+ padding: 2px 10px;
372
+ font-family: var(--font-mono);
373
+ font-size: 12px;
374
+ }
375
+ a.af-chip:hover {
376
+ border-color: var(--af-accent);
377
+ text-decoration: underline;
378
+ }
379
+ .af-row:hover {
380
+ background: var(--af-surface-hover);
381
+ }
382
+
301
383
  /* =============================================
302
384
  Markdown prose (sessions drawer)
303
385
  ============================================= */
@@ -72,7 +72,7 @@ export function AiFeaturesForm({ initial }: { initial: Initial }) {
72
72
  <button
73
73
  type="submit"
74
74
  disabled={saving}
75
- className="px-3 py-1 border rounded bg-black text-white disabled:opacity-60"
75
+ className="af-btn-primary"
76
76
  >
77
77
  {saving ? "Saving…" : "Save"}
78
78
  </button>
@@ -1,18 +1,32 @@
1
1
  import { readSettings } from "@claude-lens/entries/node";
2
2
  import { AiFeaturesForm } from "./ai-features-form";
3
- import { TeamConnectionSection } from "./team-connection-section";
3
+ import { readAutostartState } from "@/lib/autostart-data";
4
+ import { AutostartToggle } from "@/components/autostart-toggle";
4
5
 
6
+ // Layout mirrors /team: max-w-3xl, header + subtitle, card-style sections.
5
7
  export default function SettingsPage() {
6
8
  const s = readSettings();
7
9
  return (
8
- <main className="mx-auto max-w-2xl p-6 space-y-8">
9
- <h1 className="text-2xl font-semibold">Fleetlens Settings</h1>
10
+ <main className="mx-auto max-w-3xl p-6 space-y-8">
11
+ <header>
12
+ <h1 className="text-2xl font-semibold">Settings</h1>
13
+ <p className="text-sm text-gray-500 mt-1">
14
+ Local machine preferences. Team-sync management lives on the Team page.
15
+ </p>
16
+ </header>
10
17
 
11
- <TeamConnectionSection />
18
+ <section className="af-card space-y-3">
19
+ <h2 className="text-lg font-medium">Daemon auto-start</h2>
20
+ <p className="text-sm text-gray-500">
21
+ Brings the dashboard, plan-usage polling, and team sync back after a
22
+ reboot. Team pairing turns this on by default.
23
+ </p>
24
+ <AutostartToggle initial={readAutostartState()} />
25
+ </section>
12
26
 
13
- <section>
14
- <h2 className="text-lg font-medium mb-2">AI Features</h2>
15
- <p className="text-sm text-gray-500 mb-4">
27
+ <section className="af-card space-y-3">
28
+ <h2 className="text-lg font-medium">AI Features</h2>
29
+ <p className="text-sm text-gray-500">
16
30
  When enabled, Fleetlens synthesizes daily digests and per-entry
17
31
  narratives by spawning your local <code>claude</code> CLI (uses your
18
32
  existing Claude Code auth — no API key required).
@@ -49,7 +49,7 @@ export function ForceSyncButton({ cliAvailable }: { cliAvailable: boolean }) {
49
49
  ? "Force sync is only available when running via the fleetlens CLI"
50
50
  : undefined
51
51
  }
52
- className="rounded border border-gray-300 px-3 py-1.5 text-sm hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
52
+ className="af-btn disabled:cursor-not-allowed"
53
53
  >
54
54
  {state === "syncing" ? "Syncing…" : "Sync now"}
55
55
  </button>
@@ -60,9 +60,7 @@ export function ForceSyncButton({ cliAvailable }: { cliAvailable: boolean }) {
60
60
 
61
61
  {result && (
62
62
  <pre
63
- className={`rounded border p-3 text-xs font-mono whitespace-pre-wrap ${
64
- result.ok ? "border-gray-200 bg-gray-50" : "border-red-300 bg-red-50 text-red-700"
65
- }`}
63
+ className={`p-3 text-xs font-mono whitespace-pre-wrap ${result.ok ? "af-panel" : "af-panel-danger"}`}
66
64
  >
67
65
  {result.lines.length > 0 ? result.lines.join("\n") : ""}
68
66
  {result.error ? (result.lines.length > 0 ? "\n" : "") + result.error : ""}
@@ -0,0 +1,503 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { ProjectSyncPicker } from "@/components/project-sync-picker";
5
+ import type { SyncProjectRow } from "@/lib/sync-projects-data";
6
+ import type { SyncProjects } from "@/lib/team-config";
7
+
8
+ // Mirrors packages/cli/src/team/sync.ts's SyncProgressEvent. Arrives as JSON
9
+ // over SSE `event: progress` frames — kept as a local type rather than an
10
+ // import to avoid apps/web depending on the cli package for a wire shape.
11
+ type SyncProgressEvent =
12
+ | { type: "phase"; phase: "usage-backfill" | "activity"; totalDays?: number }
13
+ | { type: "usage"; inserted: number; alreadyKnown: number }
14
+ | { type: "day"; day: string; index: number; total: number; outcome: "pushed" | "queued" | "dropped" }
15
+ | { type: "done"; pushed: number; queued: number; pushedDays: string[] }
16
+ | { type: "error"; message: string }
17
+ // Route fallback when a stdout line isn't valid JSON (shouldn't happen in
18
+ // practice, but the route emits it rather than dropping the line silently).
19
+ | { type: "log"; line: string };
20
+
21
+ type LogRow = { key: number; text: string; tone?: "warn" | "error" | "dim" };
22
+
23
+ function selectedProjectNames(projects: SyncProjectRow[], selection: SyncProjects): string[] {
24
+ return projects
25
+ .filter((p) => {
26
+ if (selection.excluded.includes(p.name)) return false;
27
+ if (selection.included.includes(p.name)) return true;
28
+ return selection.autoIncludeNew;
29
+ })
30
+ .map((p) => p.name);
31
+ }
32
+
33
+ function selectionCount(projects: SyncProjectRow[], selection: SyncProjects): number {
34
+ return selectedProjectNames(projects, selection).length;
35
+ }
36
+
37
+ // Client-side clock, not server time — matches "generated when the event
38
+ // arrives" rather than any timestamp the CLI might embed in the payload.
39
+ function logTimestamp(): string {
40
+ return new Date().toTimeString().slice(0, 8);
41
+ }
42
+
43
+ export function OnboardingWizard({
44
+ teamName,
45
+ teamUrl,
46
+ serverHost,
47
+ projects,
48
+ initial,
49
+ setupPending,
50
+ }: {
51
+ teamName: string;
52
+ teamUrl: string;
53
+ serverHost: string;
54
+ projects: SyncProjectRow[];
55
+ initial: SyncProjects;
56
+ setupPending: boolean;
57
+ }) {
58
+ const [step, setStep] = useState<1 | 2 | 3>(1);
59
+ const [selection, setSelection] = useState<SyncProjects>(initial);
60
+ const [streaming, setStreaming] = useState(false);
61
+ const [rows, setRows] = useState<LogRow[]>([]);
62
+ const [pushed, setPushed] = useState<number | null>(null);
63
+ const [failure, setFailure] = useState<string | null>(null);
64
+ const [finished, setFinished] = useState(false);
65
+
66
+ async function startSync() {
67
+ setStreaming(true);
68
+ setFinished(false);
69
+ setFailure(null);
70
+ setRows([]);
71
+ setPushed(null);
72
+ let seq = 0;
73
+ const log = (text: string, tone?: LogRow["tone"]) =>
74
+ setRows((r) => [...r, { key: seq++, text: `${logTimestamp()} ${text}`, tone }]);
75
+
76
+ let res: Response;
77
+ try {
78
+ res = await fetch("/api/team/onboarding/start", {
79
+ method: "POST",
80
+ headers: { "Content-Type": "application/json" },
81
+ body: JSON.stringify(selection),
82
+ });
83
+ } catch (err) {
84
+ setFailure(`Request failed: ${(err as Error).message}`);
85
+ setStreaming(false);
86
+ return;
87
+ }
88
+
89
+ if (!res.ok || !res.body) {
90
+ const body = await res.json().catch(() => null);
91
+ setFailure(body?.error ?? `Error ${res.status}`);
92
+ setStreaming(false);
93
+ return;
94
+ }
95
+
96
+ const reader = res.body.getReader();
97
+ const decoder = new TextDecoder();
98
+ let buf = "";
99
+ while (true) {
100
+ const { done, value } = await reader.read();
101
+ if (done) break;
102
+ buf += decoder.decode(value, { stream: true });
103
+ const frames = buf.split("\n\n");
104
+ buf = frames.pop() ?? "";
105
+ for (const frame of frames) {
106
+ const lines = frame.split("\n");
107
+ const eventLine = lines.find((l) => l.startsWith("event: "));
108
+ const dataLine = lines.find((l) => l.startsWith("data: "));
109
+ if (!dataLine) continue;
110
+ let data: unknown;
111
+ try {
112
+ data = JSON.parse(dataLine.slice("data: ".length));
113
+ } catch {
114
+ continue;
115
+ }
116
+ if (eventLine?.slice("event: ".length) === "done") {
117
+ const exitCode = (data as { exitCode: number | null }).exitCode;
118
+ if (exitCode !== 0) {
119
+ setFailure(`fleetlens team sync exited with code ${exitCode ?? "unknown"}`);
120
+ log(`done — exit ${exitCode ?? "unknown"}`, "error");
121
+ }
122
+ continue;
123
+ }
124
+ const ev = data as SyncProgressEvent;
125
+ switch (ev.type) {
126
+ case "phase":
127
+ log(ev.phase === "usage-backfill" ? "checking plan-usage history…" : `pushing ${ev.totalDays ?? "?"} day(s), newest first…`);
128
+ break;
129
+ case "usage":
130
+ log(
131
+ ev.inserted === 0 && ev.alreadyKnown === 0
132
+ ? "no plan-usage snapshots yet — the daemon starts collecting them automatically"
133
+ : `usage: +${ev.inserted} snapshot(s) (${ev.alreadyKnown} already on server)`,
134
+ );
135
+ break;
136
+ case "day": {
137
+ const text =
138
+ ev.outcome === "pushed"
139
+ ? `✓ ${ev.day} pushed (${ev.index}/${ev.total})`
140
+ : ev.outcome === "queued"
141
+ ? `⚠ ${ev.day} queued for retry (${ev.index}/${ev.total})`
142
+ : `✗ ${ev.day} rejected by server (${ev.index}/${ev.total})`;
143
+ log(text, ev.outcome === "dropped" ? "error" : ev.outcome === "queued" ? "warn" : undefined);
144
+ break;
145
+ }
146
+ case "done":
147
+ setPushed(ev.pushed);
148
+ break;
149
+ case "error":
150
+ log(ev.message, "error");
151
+ setFailure(ev.message);
152
+ break;
153
+ case "log":
154
+ log(ev.line, "dim");
155
+ break;
156
+ }
157
+ }
158
+ }
159
+ setStreaming(false);
160
+ setFinished(true);
161
+ }
162
+
163
+ return (
164
+ <main className="mx-auto max-w-2xl space-y-6 p-6">
165
+ <StepDots step={step} />
166
+ {step === 1 && (
167
+ <Step1
168
+ teamName={teamName}
169
+ serverHost={serverHost}
170
+ setupPending={setupPending}
171
+ onContinue={() => setStep(2)}
172
+ />
173
+ )}
174
+ {step === 2 && (
175
+ <Step2
176
+ projects={projects}
177
+ selection={selection}
178
+ onChange={setSelection}
179
+ onBack={() => setStep(1)}
180
+ onContinue={() => setStep(3)}
181
+ />
182
+ )}
183
+ {step === 3 && (
184
+ <Step3
185
+ projects={projects}
186
+ selection={selection}
187
+ teamName={teamName}
188
+ serverHost={serverHost}
189
+ rows={rows}
190
+ streaming={streaming}
191
+ finished={finished}
192
+ pushed={pushed}
193
+ failure={failure}
194
+ teamUrl={teamUrl}
195
+ onBack={() => setStep(2)}
196
+ onStart={startSync}
197
+ />
198
+ )}
199
+ </main>
200
+ );
201
+ }
202
+
203
+ function StepDots({ step }: { step: 1 | 2 | 3 }) {
204
+ const labels: Array<[1 | 2 | 3, string]> = [
205
+ [1, "What happens"],
206
+ [2, "Choose projects"],
207
+ [3, "Sync"],
208
+ ];
209
+ return (
210
+ <div className="flex items-center gap-2 text-xs text-gray-500">
211
+ {labels.map(([n, label], i) => (
212
+ <span key={n} className="flex items-center gap-2">
213
+ <span
214
+ className={`flex h-5 w-5 items-center justify-center rounded-full ${
215
+ n === step ? "af-step-active" : "border"
216
+ }`}
217
+ >
218
+ {n}
219
+ </span>
220
+ <span className={n === step ? "font-medium text-gray-900 dark:text-gray-100" : ""}>{label}</span>
221
+ {i < labels.length - 1 && <span className="text-gray-300 dark:text-gray-700">—</span>}
222
+ </span>
223
+ ))}
224
+ </div>
225
+ );
226
+ }
227
+
228
+ function Step1({
229
+ teamName,
230
+ serverHost,
231
+ setupPending,
232
+ onContinue,
233
+ }: {
234
+ teamName: string;
235
+ serverHost: string;
236
+ setupPending: boolean;
237
+ onContinue: () => void;
238
+ }) {
239
+ return (
240
+ <section className="space-y-4">
241
+ <h1 className="text-2xl font-semibold">You&rsquo;re pairing with &ldquo;{teamName}&rdquo;</h1>
242
+ {setupPending && <p className="text-sm text-gray-500">Nothing syncs until you finish this wizard.</p>}
243
+
244
+ <div className="af-panel p-4 text-sm">
245
+ <p className="mb-2 font-medium">Shared with {serverHost} every 5 minutes:</p>
246
+ <ul className="list-inside list-disc space-y-1 text-gray-600 dark:text-gray-400">
247
+ <li>Daily aggregate metrics (agent time, sessions, tool calls, turns, tokens)</li>
248
+ <li>Per-project totals — project name, agent time, session count, and GitHub repo name when one is detected</li>
249
+ <li>Daily working style — working-shape mix, concurrency peak and parallel minutes, long-autonomous runs, plan-mode and brainstorm usage, tool-error count</li>
250
+ <li>Daily tooling and output counts — skills and sub-agents used (names + counts), PRs, commits, pushes</li>
251
+ <li>Session outcome mixes from AI enrichment (shipped / partial / blocked …)</li>
252
+ <li>Plan-utilization percentages and sync health logs</li>
253
+ </ul>
254
+ </div>
255
+
256
+ <div className="af-panel p-4 text-sm">
257
+ <p className="mb-2 font-medium">Never leaves this machine:</p>
258
+ <ul className="list-inside list-disc space-y-1 text-gray-600 dark:text-gray-400">
259
+ <li>Transcripts, prompts, and code</li>
260
+ <li>File contents and absolute paths</li>
261
+ <li>Anything from projects you exclude in the next step</li>
262
+ </ul>
263
+ </div>
264
+
265
+ <p className="text-xs text-gray-500">Plan utilization is account-level and isn&rsquo;t affected by project selection.</p>
266
+
267
+ <button
268
+ type="button"
269
+ onClick={onContinue}
270
+ className="af-btn-primary"
271
+ >
272
+ Continue
273
+ </button>
274
+ </section>
275
+ );
276
+ }
277
+
278
+ function Step2({
279
+ projects,
280
+ selection,
281
+ onChange,
282
+ onBack,
283
+ onContinue,
284
+ }: {
285
+ projects: SyncProjectRow[];
286
+ selection: SyncProjects;
287
+ onChange: (v: SyncProjects) => void;
288
+ onBack: () => void;
289
+ onContinue: () => void;
290
+ }) {
291
+ return (
292
+ <section className="space-y-4">
293
+ <h1 className="text-xl font-semibold">Choose which projects sync</h1>
294
+ <p className="text-sm text-gray-500">
295
+ Syncing {selectionCount(projects, selection)} of {projects.length} project{projects.length === 1 ? "" : "s"}
296
+ </p>
297
+ <ProjectSyncPicker projects={projects} value={selection} onChange={onChange} />
298
+ <div className="flex gap-3">
299
+ <button
300
+ type="button"
301
+ onClick={onBack}
302
+ className="af-btn"
303
+ >
304
+ Back
305
+ </button>
306
+ <button
307
+ type="button"
308
+ onClick={onContinue}
309
+ className="af-btn-primary"
310
+ >
311
+ Continue
312
+ </button>
313
+ </div>
314
+ </section>
315
+ );
316
+ }
317
+
318
+ function Step3({
319
+ projects,
320
+ selection,
321
+ teamName,
322
+ serverHost,
323
+ rows,
324
+ streaming,
325
+ finished,
326
+ pushed,
327
+ failure,
328
+ teamUrl,
329
+ onBack,
330
+ onStart,
331
+ }: {
332
+ projects: SyncProjectRow[];
333
+ selection: SyncProjects;
334
+ teamName: string;
335
+ serverHost: string;
336
+ rows: LogRow[];
337
+ streaming: boolean;
338
+ finished: boolean;
339
+ pushed: number | null;
340
+ failure: string | null;
341
+ teamUrl: string;
342
+ onBack: () => void;
343
+ onStart: () => void;
344
+ }) {
345
+ const succeeded = finished && !failure;
346
+ // Nothing has happened yet (not even a failed attempt) — show the summary,
347
+ // not the log/outcome panels below.
348
+ const notStarted = !streaming && !finished && !failure;
349
+ const logRef = useRef<HTMLDivElement>(null);
350
+
351
+ useEffect(() => {
352
+ if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
353
+ }, [rows]);
354
+
355
+ if (notStarted) {
356
+ const selected = selectedProjectNames(projects, selection);
357
+ const excludedCount = projects.length - selected.length;
358
+ const shown = selected.slice(0, 6);
359
+ const more = selected.length - shown.length;
360
+ return (
361
+ <section className="space-y-4">
362
+ <h1 className="text-xl font-semibold">
363
+ Syncing {selected.length} of {projects.length} project{projects.length === 1 ? "" : "s"} to &ldquo;{teamName}&rdquo; (
364
+ {serverHost})
365
+ </h1>
366
+
367
+ {shown.length > 0 && (
368
+ <div className="flex flex-wrap gap-2">
369
+ {shown.map((name) => (
370
+ <span
371
+ key={name}
372
+ className="rounded-full border border-gray-300 px-2 py-0.5 font-mono text-xs text-gray-600 dark:border-gray-700 dark:text-gray-400"
373
+ >
374
+ {name}
375
+ </span>
376
+ ))}
377
+ {more > 0 && <span className="self-center text-xs text-gray-500">+{more} more</span>}
378
+ </div>
379
+ )}
380
+
381
+ <div className="space-y-1 text-sm text-gray-600 dark:text-gray-400">
382
+ {excludedCount > 0 && (
383
+ <p>
384
+ {excludedCount} project{excludedCount === 1 ? " stays" : "s stay"} private on this machine.
385
+ </p>
386
+ )}
387
+ <p>
388
+ {selection.autoIncludeNew ? "New projects will sync automatically." : "New projects stay private until you add them."}
389
+ </p>
390
+ </div>
391
+
392
+ <ul className="list-inside list-disc space-y-1 text-xs text-gray-500">
393
+ <li>Aggregate metrics only — never transcripts, prompts, or file contents</li>
394
+ <li>Pushes run every 5 minutes from now on</li>
395
+ <li>You can change the selection anytime on the Team page</li>
396
+ </ul>
397
+
398
+ <div className="flex gap-3">
399
+ <button
400
+ type="button"
401
+ onClick={onBack}
402
+ className="af-btn"
403
+ >
404
+ Back
405
+ </button>
406
+ <button
407
+ type="button"
408
+ onClick={onStart}
409
+ className="af-btn-primary"
410
+ >
411
+ Start syncing
412
+ </button>
413
+ </div>
414
+ </section>
415
+ );
416
+ }
417
+
418
+ return (
419
+ <section className="space-y-4">
420
+ <h1 className="text-xl font-semibold">Sync your history</h1>
421
+
422
+ {rows.length > 0 && (
423
+ <div
424
+ ref={logRef}
425
+ className="max-h-80 space-y-0.5 overflow-y-auto rounded-lg bg-gray-950 p-3 font-mono text-xs text-gray-200"
426
+ >
427
+ {rows.map((r) => (
428
+ <div
429
+ key={r.key}
430
+ className={r.tone === "error" ? "text-red-400" : r.tone === "warn" ? "text-amber-400" : r.tone === "dim" ? "text-gray-500" : undefined}
431
+ >
432
+ {r.text}
433
+ </div>
434
+ ))}
435
+ </div>
436
+ )}
437
+
438
+ {succeeded && (
439
+ <div className="space-y-3 rounded-lg border border-green-300 bg-green-50 p-4 text-sm dark:border-green-800 dark:bg-green-950">
440
+ <p className="font-medium text-green-800 dark:text-green-300">
441
+ All synced — {pushed ?? 0} day{pushed === 1 ? "" : "s"} pushed
442
+ </p>
443
+ <div className="flex flex-wrap items-center gap-3">
444
+ {/* globals.css's un-layered `a { color: inherit }` beats layered
445
+ utilities — button-styled anchors need the ! variants. */}
446
+ <a
447
+ href="/team"
448
+ className="af-btn-primary"
449
+ >
450
+ View your team sync page
451
+ </a>
452
+ <a
453
+ href={teamUrl}
454
+ target="_blank"
455
+ rel="noreferrer"
456
+ className="af-btn"
457
+ >
458
+ Open the team dashboard ↗
459
+ </a>
460
+ </div>
461
+ <a href="/" className="block text-xs text-gray-500! underline">
462
+ Back to overview
463
+ </a>
464
+ </div>
465
+ )}
466
+
467
+ {failure && (
468
+ <div className="space-y-2 rounded-lg border border-red-300 bg-red-50 p-4 text-sm text-red-700 dark:border-red-800 dark:bg-red-950 dark:text-red-300">
469
+ <p>{failure}</p>
470
+ <button
471
+ type="button"
472
+ onClick={onStart}
473
+ disabled={streaming}
474
+ className="rounded border border-red-400 px-3 py-1 text-xs disabled:opacity-50"
475
+ >
476
+ Retry
477
+ </button>
478
+ </div>
479
+ )}
480
+
481
+ <div className="flex gap-3">
482
+ <button
483
+ type="button"
484
+ onClick={onBack}
485
+ disabled={streaming}
486
+ className="rounded border border-gray-300 px-4 py-2 text-sm disabled:opacity-50 dark:border-gray-700"
487
+ >
488
+ Back
489
+ </button>
490
+ {!succeeded && (
491
+ <button
492
+ type="button"
493
+ onClick={onStart}
494
+ disabled={streaming}
495
+ className="af-btn-primary"
496
+ >
497
+ {streaming ? "Syncing…" : "Start syncing"}
498
+ </button>
499
+ )}
500
+ </div>
501
+ </section>
502
+ );
503
+ }
@@ -0,0 +1,28 @@
1
+ import { redirect } from "next/navigation";
2
+ import { readTeamConfig } from "@/lib/team-config";
3
+ import { listSyncProjectRows } from "@/lib/sync-projects-data";
4
+ import { OnboardingWizard } from "./onboarding-wizard";
5
+
6
+ export const dynamic = "force-dynamic";
7
+
8
+ export default async function TeamOnboardingPage() {
9
+ const config = readTeamConfig();
10
+ if (!config) redirect("/team");
11
+ const projects = await listSyncProjectRows();
12
+ return (
13
+ <OnboardingWizard
14
+ teamName={config.teamName ?? config.teamSlug}
15
+ teamUrl={`${config.serverUrl.replace(/\/$/, "")}/team/${config.teamSlug}`}
16
+ serverHost={new URL(config.serverUrl).host}
17
+ projects={projects}
18
+ initial={
19
+ config.syncProjects ?? {
20
+ autoIncludeNew: true,
21
+ included: projects.map((p) => p.name),
22
+ excluded: [],
23
+ }
24
+ }
25
+ setupPending={config.setupPending ?? false}
26
+ />
27
+ );
28
+ }