@leanspec/ui 0.2.5-dev.20251120072524 → 0.2.5-dev.20251120093243

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 (338) hide show
  1. package/.next/standalone/packages/ui/.next/BUILD_ID +1 -1
  2. package/.next/standalone/packages/ui/.next/app-path-routes-manifest.json +9 -0
  3. package/.next/standalone/packages/ui/.next/build-manifest.json +7 -6
  4. package/.next/standalone/packages/ui/.next/prerender-manifest.json +28 -3
  5. package/.next/standalone/packages/ui/.next/routes-manifest.json +71 -0
  6. package/.next/standalone/packages/ui/.next/server/app/_global-error/page/build-manifest.json +5 -4
  7. package/.next/standalone/packages/ui/.next/server/app/_global-error/page.js +1 -1
  8. package/.next/standalone/packages/ui/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/standalone/packages/ui/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/packages/ui/.next/server/app/_global-error.html +2 -2
  11. package/.next/standalone/packages/ui/.next/server/app/_global-error.rsc +1 -1
  12. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  13. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/packages/ui/.next/server/app/_not-found/page/build-manifest.json +5 -4
  17. package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js +2 -2
  18. package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/packages/ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/packages/ui/.next/server/app/_not-found.html +2 -2
  21. package/.next/standalone/packages/ui/.next/server/app/_not-found.rsc +20 -19
  22. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_full.segment.rsc +20 -19
  23. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_index.segment.rsc +26 -25
  24. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
  25. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  26. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_tree.segment.rsc +5 -5
  27. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js +2 -3
  28. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.nft.json +1 -1
  29. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js +2 -3
  30. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.nft.json +1 -1
  31. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route/app-paths-manifest.json +3 -0
  32. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route/build-manifest.json +11 -0
  33. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route/server-reference-manifest.json +4 -0
  34. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js +6 -0
  35. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.map +5 -0
  36. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.nft.json +1 -0
  37. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route_client-reference-manifest.js +2 -0
  38. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js +2 -3
  39. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.nft.json +1 -1
  40. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route/app-paths-manifest.json +3 -0
  41. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route/build-manifest.json +11 -0
  42. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route/server-reference-manifest.json +4 -0
  43. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js +8 -0
  44. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.map +5 -0
  45. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.nft.json +1 -0
  46. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +2 -0
  47. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route/app-paths-manifest.json +3 -0
  48. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route/build-manifest.json +11 -0
  49. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route/server-reference-manifest.json +4 -0
  50. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js +9 -0
  51. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.map +5 -0
  52. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.nft.json +1 -0
  53. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route_client-reference-manifest.js +2 -0
  54. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route/app-paths-manifest.json +3 -0
  55. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route/build-manifest.json +11 -0
  56. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route/server-reference-manifest.json +4 -0
  57. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js +8 -0
  58. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.map +5 -0
  59. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.nft.json +1 -0
  60. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route_client-reference-manifest.js +2 -0
  61. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js +4 -3
  62. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
  63. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route/app-paths-manifest.json +3 -0
  64. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route/build-manifest.json +11 -0
  65. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route/server-reference-manifest.json +4 -0
  66. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js +8 -0
  67. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.map +5 -0
  68. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.nft.json +1 -0
  69. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route_client-reference-manifest.js +2 -0
  70. package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js +2 -2
  71. package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js.nft.json +1 -1
  72. package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js +3 -4
  73. package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js.nft.json +1 -1
  74. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js +3 -4
  75. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
  76. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js +3 -4
  77. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
  78. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js +3 -4
  79. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js.nft.json +1 -1
  80. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js +3 -4
  81. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
  82. package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js +3 -4
  83. package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js.nft.json +1 -1
  84. package/.next/standalone/packages/ui/.next/server/app/page/build-manifest.json +5 -4
  85. package/.next/standalone/packages/ui/.next/server/app/page.js +2 -2
  86. package/.next/standalone/packages/ui/.next/server/app/page.js.nft.json +1 -1
  87. package/.next/standalone/packages/ui/.next/server/app/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/app-paths-manifest.json +3 -0
  89. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/build-manifest.json +18 -0
  90. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/next-font-manifest.json +6 -0
  91. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/react-loadable-manifest.json +1 -0
  92. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/server-reference-manifest.json +4 -0
  93. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js +21 -0
  94. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.map +5 -0
  95. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.nft.json +1 -0
  96. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +2 -0
  97. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/app-paths-manifest.json +3 -0
  98. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/build-manifest.json +18 -0
  99. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/next-font-manifest.json +6 -0
  100. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/react-loadable-manifest.json +1 -0
  101. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/server-reference-manifest.json +4 -0
  102. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js +21 -0
  103. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.map +5 -0
  104. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.nft.json +1 -0
  105. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page_client-reference-manifest.js +2 -0
  106. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/app-paths-manifest.json +3 -0
  107. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/build-manifest.json +18 -0
  108. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/next-font-manifest.json +6 -0
  109. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/react-loadable-manifest.json +1 -0
  110. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/server-reference-manifest.json +4 -0
  111. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js +20 -0
  112. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.map +5 -0
  113. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.nft.json +1 -0
  114. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page_client-reference-manifest.js +2 -0
  115. package/.next/standalone/packages/ui/.next/server/app/projects/page/app-paths-manifest.json +3 -0
  116. package/.next/standalone/packages/ui/.next/server/app/projects/page/build-manifest.json +18 -0
  117. package/.next/standalone/packages/ui/.next/server/app/projects/page/next-font-manifest.json +6 -0
  118. package/.next/standalone/packages/ui/.next/server/app/projects/page/react-loadable-manifest.json +1 -0
  119. package/.next/standalone/packages/ui/.next/server/app/projects/page/server-reference-manifest.json +4 -0
  120. package/.next/standalone/packages/ui/.next/server/app/projects/page.js +19 -0
  121. package/.next/standalone/packages/ui/.next/server/app/projects/page.js.map +5 -0
  122. package/.next/standalone/packages/ui/.next/server/app/projects/page.js.nft.json +1 -0
  123. package/.next/standalone/packages/ui/.next/server/app/projects/page_client-reference-manifest.js +2 -0
  124. package/.next/standalone/packages/ui/.next/server/app/projects.html +2 -0
  125. package/.next/standalone/packages/ui/.next/server/app/projects.meta +14 -0
  126. package/.next/standalone/packages/ui/.next/server/app/projects.rsc +34 -0
  127. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_full.segment.rsc +34 -0
  128. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_index.segment.rsc +27 -0
  129. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_tree.segment.rsc +9 -0
  130. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +9 -0
  131. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects.segment.rsc +4 -0
  132. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page/build-manifest.json +5 -4
  133. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js +4 -4
  134. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js.nft.json +1 -1
  135. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
  136. package/.next/standalone/packages/ui/.next/server/app/specs/page/build-manifest.json +5 -4
  137. package/.next/standalone/packages/ui/.next/server/app/specs/page.js +2 -2
  138. package/.next/standalone/packages/ui/.next/server/app/specs/page.js.nft.json +1 -1
  139. package/.next/standalone/packages/ui/.next/server/app/specs/page_client-reference-manifest.js +1 -1
  140. package/.next/standalone/packages/ui/.next/server/app/stats/page/build-manifest.json +5 -4
  141. package/.next/standalone/packages/ui/.next/server/app/stats/page.js +2 -2
  142. package/.next/standalone/packages/ui/.next/server/app/stats/page.js.nft.json +1 -1
  143. package/.next/standalone/packages/ui/.next/server/app/stats/page_client-reference-manifest.js +1 -1
  144. package/.next/standalone/packages/ui/.next/server/app-paths-manifest.json +9 -0
  145. package/.next/standalone/packages/ui/.next/server/chunks/6681a__next-internal_server_app_api_projects_[id]_specs_[spec]_route_actions_d018d9e0.js +3 -0
  146. package/.next/standalone/packages/ui/.next/server/chunks/730ea_ui__next-internal_server_app_api_projects_[id]_stats_route_actions_a0bb04a8.js +3 -0
  147. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__0fbfea15._.js +3 -0
  148. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__126dea7b._.js +3 -0
  149. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__1f037512._.js +3 -0
  150. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__3559376c._.js +21 -0
  151. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__548e27d4._.js +3 -0
  152. package/.next/standalone/packages/ui/.next/server/chunks/{[root-of-the-server]__d293d769._.js → [root-of-the-server]__65667b70._.js} +2 -2
  153. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__675a763e._.js +3 -0
  154. package/.next/standalone/packages/ui/.next/server/chunks/{[root-of-the-server]__c83721f3._.js → [root-of-the-server]__803d07f0._.js} +2 -2
  155. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8075fe29._.js +3 -0
  156. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8233e09b._.js +3 -0
  157. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__84cdc14a._.js +3 -0
  158. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__9ce722b4._.js +3 -0
  159. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__a2d7cbed._.js +3 -0
  160. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__aa677b0d._.js +3 -0
  161. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__ac744182._.js +3 -0
  162. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bb9fca84._.js +4 -0
  163. package/.next/standalone/packages/ui/.next/server/chunks/{[root-of-the-server]__fad83967._.js → [root-of-the-server]__bdc3963a._.js} +2 -2
  164. package/.next/standalone/packages/ui/.next/server/chunks/{[root-of-the-server]__57791a48._.js → [root-of-the-server]__f5c6d6b8._.js} +2 -2
  165. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__fb91986f._.js +3 -0
  166. package/.next/standalone/packages/ui/.next/server/chunks/f825c_server_app_api_local-projects_list-directory_route_actions_d620ec1a.js +3 -0
  167. package/.next/standalone/packages/ui/.next/server/chunks/f825c_server_app_api_projects_[id]_specs_[spec]_status_route_actions_e9f1bdc5.js +3 -0
  168. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_projects_[id]_route_actions_bff49675.js +3 -0
  169. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui_src_lib_db_index_ts_556307fa._.js +64 -5
  170. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui_src_lib_specs_sources_database-source_ts_0bd881ee._.js +3 -0
  171. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui_src_lib_specs_sources_database-source_ts_baa0160d._.js +3 -0
  172. package/.next/standalone/packages/ui/.next/server/chunks/ssr/38a22_sonner_dist_index_mjs_207730fe._.js +3 -0
  173. package/.next/standalone/packages/ui/.next/server/chunks/ssr/6e9bd_next_dist_7af75658._.js +3 -0
  174. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{_a5b58449._.js → 6e9bd_next_dist_df5dcbe9._.js} +2 -2
  175. package/.next/standalone/packages/ui/.next/server/chunks/ssr/730ea_ui__next-internal_server_app_projects_[projectId]_specs_page_actions_82e32fe4.js +3 -0
  176. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__01bfc8ff._.js +3 -0
  177. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__1d0c2012._.js +1 -1
  178. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__4ec37765._.js +3 -0
  179. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__1af33d49._.js → [root-of-the-server]__50122e7e._.js} +2 -2
  180. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__34ab4950._.js → [root-of-the-server]__5382b397._.js} +2 -2
  181. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__73f60f12._.js +7 -0
  182. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__88a691ee._.js +3 -0
  183. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a7ae8552._.js +7 -0
  184. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__bdbbba01._.js +3 -0
  185. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__c592f5d1._.js +3 -0
  186. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__cc589a54._.js +3 -0
  187. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__ec5b96a5._.js +3 -0
  188. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__cbbbfb5d._.js → [root-of-the-server]__fd80e4dd._.js} +2 -2
  189. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_000dd317._.js +1 -1
  190. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_196b5a83._.js +3 -0
  191. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_39562b2a._.js +4 -0
  192. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_3b617676._.js +1 -1
  193. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_4129cc0f._.js +3 -0
  194. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_6174313a._.js +3 -0
  195. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_6e4dd8b6._.js +3 -0
  196. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_85effc18._.js +4 -0
  197. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ad8c1e99._.js +1 -1
  198. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_bae6d2b8._.js +4 -0
  199. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_c2f54661._.js +5 -0
  200. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_fdd7780b._.js +4 -0
  201. package/.next/standalone/packages/ui/.next/server/chunks/ssr/f825c_server_app_projects_[projectId]_specs_[specId]_page_actions_22d9c35e.js +3 -0
  202. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_af9d3830._.js +3 -0
  203. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_projects_[projectId]_page_actions_f2986585.js +3 -0
  204. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_projects_page_actions_715940ea.js +3 -0
  205. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_projects_[projectId]_be242d6c._.js +3 -0
  206. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_projects_[projectId]_project-context-syncer_tsx_7954ea3b._.js +3 -0
  207. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_projects_page_tsx_6e166c8e._.js +3 -0
  208. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_specs_specs-client_tsx_0bb8f8f8._.js +1 -1
  209. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_ui_select_tsx_7e21d40f._.js +3 -0
  210. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_lib_specs_sources_database-source_ts_f7186c2a._.js +60 -1
  211. package/.next/standalone/packages/ui/.next/server/middleware-build-manifest.js +5 -4
  212. package/.next/standalone/packages/ui/.next/server/pages/404.html +2 -2
  213. package/.next/standalone/packages/ui/.next/server/pages/500.html +2 -2
  214. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.js +1 -1
  215. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.json +1 -1
  216. package/.next/standalone/packages/ui/.next/static/chunks/07f48b316e895080.js +1 -0
  217. package/.next/standalone/packages/ui/.next/static/chunks/0a7be410b438418a.js +1 -0
  218. package/.next/standalone/packages/ui/.next/static/chunks/1089ca88f6bef846.js +1 -0
  219. package/.next/standalone/packages/ui/.next/static/chunks/17471c87082c392c.js +5 -0
  220. package/.next/standalone/packages/ui/.next/static/chunks/220ba5cb8fe4dd69.js +1 -0
  221. package/.next/standalone/packages/ui/.next/static/chunks/35ccd3286e538bd2.js +1 -0
  222. package/.next/standalone/packages/ui/.next/static/chunks/571033caca823138.js +1 -0
  223. package/.next/standalone/packages/ui/.next/static/chunks/5a6fc30cd64085b4.css +1 -0
  224. package/.next/standalone/packages/ui/.next/static/chunks/5c2072ad938de8ed.js +1 -0
  225. package/.next/standalone/packages/ui/.next/static/chunks/843e1dfdc28e1385.js +1 -0
  226. package/.next/standalone/packages/ui/.next/static/chunks/9dad7fd31627df80.js +1 -0
  227. package/.next/standalone/packages/ui/.next/static/chunks/{c3d4d07de959ecf1.js → a055d4b2866ff8d4.js} +1 -1
  228. package/.next/standalone/packages/ui/.next/static/chunks/afb7c5a4255f4081.js +3 -0
  229. package/.next/standalone/packages/ui/.next/static/chunks/{c557ac675be79771.js → b760a3a9c2c8be28.js} +1 -1
  230. package/.next/standalone/packages/ui/.next/static/chunks/dcdd95180149fa10.js +1 -0
  231. package/.next/standalone/packages/ui/.next/static/chunks/ebd89051637b9a47.js +4 -0
  232. package/.next/standalone/packages/ui/.next/static/chunks/f9db24028d8c058e.js +1 -0
  233. package/.next/standalone/packages/ui/.next/static/chunks/fb640f50455ba34f.js +1 -0
  234. package/.next/standalone/packages/ui/.next/static/chunks/turbopack-b9690cacbf9fe48c.js +3 -0
  235. package/.next/standalone/packages/ui/bin/ui.js +17 -7
  236. package/.next/standalone/packages/ui/package.json +2 -1
  237. package/.next/standalone/packages/ui/src/app/api/local-projects/list-directory/route.ts +38 -0
  238. package/.next/standalone/packages/ui/src/app/api/projects/[id]/route.ts +97 -0
  239. package/.next/standalone/packages/ui/src/app/api/projects/[id]/specs/[spec]/route.ts +38 -0
  240. package/.next/standalone/packages/ui/src/app/api/projects/[id]/specs/[spec]/status/route.ts +97 -0
  241. package/.next/standalone/packages/ui/src/app/api/projects/[id]/specs/route.ts +7 -0
  242. package/.next/standalone/packages/ui/src/app/api/projects/[id]/stats/route.ts +19 -0
  243. package/.next/standalone/packages/ui/src/app/api/projects/route.ts +48 -1
  244. package/.next/standalone/packages/ui/src/app/dashboard-client.tsx +67 -6
  245. package/.next/standalone/packages/ui/src/app/layout.tsx +11 -8
  246. package/.next/standalone/packages/ui/src/app/not-found.tsx +1 -1
  247. package/.next/standalone/packages/ui/src/app/projects/[projectId]/layout.tsx +18 -0
  248. package/.next/standalone/packages/ui/src/app/projects/[projectId]/page.tsx +10 -0
  249. package/.next/standalone/packages/ui/src/app/projects/[projectId]/project-context-syncer.tsx +16 -0
  250. package/.next/standalone/packages/ui/src/app/projects/[projectId]/specs/[specId]/page.tsx +34 -0
  251. package/.next/standalone/packages/ui/src/app/projects/[projectId]/specs/page.tsx +20 -0
  252. package/.next/standalone/packages/ui/src/app/projects/page.tsx +156 -0
  253. package/.next/standalone/packages/ui/src/app/specs/specs-client.tsx +7 -2
  254. package/.next/standalone/packages/ui/src/components/create-project-dialog.tsx +139 -0
  255. package/.next/standalone/packages/ui/src/components/directory-picker.tsx +191 -0
  256. package/.next/standalone/packages/ui/src/components/main-sidebar.tsx +4 -0
  257. package/.next/standalone/packages/ui/src/components/project-switcher.tsx +105 -196
  258. package/.next/standalone/packages/ui/src/components/ui/dropdown-menu.tsx +200 -0
  259. package/.next/standalone/packages/ui/src/components/ui/popover.tsx +31 -0
  260. package/.next/standalone/packages/ui/src/contexts/project-context.tsx +10 -6
  261. package/.next/standalone/packages/ui/src/lib/db/index.ts +100 -0
  262. package/.next/standalone/packages/ui/src/lib/projects/registry.ts +77 -3
  263. package/.next/standalone/packages/ui/src/lib/specs/sources/multi-project-source.ts +4 -4
  264. package/.next/standalone/packages/ui/tsconfig.tsbuildinfo +1 -1
  265. package/.next/static/chunks/07f48b316e895080.js +1 -0
  266. package/.next/static/chunks/0a7be410b438418a.js +1 -0
  267. package/.next/static/chunks/1089ca88f6bef846.js +1 -0
  268. package/.next/static/chunks/17471c87082c392c.js +5 -0
  269. package/.next/static/chunks/220ba5cb8fe4dd69.js +1 -0
  270. package/.next/static/chunks/35ccd3286e538bd2.js +1 -0
  271. package/.next/static/chunks/571033caca823138.js +1 -0
  272. package/.next/static/chunks/5a6fc30cd64085b4.css +1 -0
  273. package/.next/static/chunks/5c2072ad938de8ed.js +1 -0
  274. package/.next/static/chunks/843e1dfdc28e1385.js +1 -0
  275. package/.next/static/chunks/9dad7fd31627df80.js +1 -0
  276. package/.next/static/chunks/{c3d4d07de959ecf1.js → a055d4b2866ff8d4.js} +1 -1
  277. package/.next/static/chunks/afb7c5a4255f4081.js +3 -0
  278. package/.next/static/chunks/{c557ac675be79771.js → b760a3a9c2c8be28.js} +1 -1
  279. package/.next/static/chunks/dcdd95180149fa10.js +1 -0
  280. package/.next/static/chunks/ebd89051637b9a47.js +4 -0
  281. package/.next/static/chunks/f9db24028d8c058e.js +1 -0
  282. package/.next/static/chunks/fb640f50455ba34f.js +1 -0
  283. package/.next/static/chunks/turbopack-b9690cacbf9fe48c.js +3 -0
  284. package/bin/ui.js +17 -7
  285. package/package.json +2 -1
  286. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__175bef84._.js +0 -3
  287. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__4b3c3001._.js +0 -21
  288. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__4b77d48f._.js +0 -3
  289. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__60b6d106._.js +0 -3
  290. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__a627840f._.js +0 -3
  291. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__beb134c0._.js +0 -3
  292. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__c6689757._.js +0 -3
  293. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__c8a20942._.js +0 -3
  294. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__cd1fb0a2._.js +0 -4
  295. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__dfa71dcd._.js +0 -3
  296. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__e9ba3fa9._.js +0 -3
  297. package/.next/standalone/packages/ui/.next/server/chunks/ecee3_js-yaml_dist_js-yaml_mjs_0775f118._.js +0 -3
  298. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a9d7fd42._.js +0 -3
  299. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__b2fe773d._.js +0 -3
  300. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__b3633d6e._.js +0 -3
  301. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__e79a982a._.js +0 -7
  302. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__ff03fc1e._.js +0 -7
  303. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_66209e84._.js +0 -3
  304. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_6cd9a5e0._.js +0 -3
  305. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_b483c9fe._.js +0 -3
  306. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_b5040d31._.js +0 -5
  307. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_9710705b._.js +0 -3
  308. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_b8ff10b9._.js +0 -3
  309. package/.next/standalone/packages/ui/.next/static/chunks/093ea4b175adb770.js +0 -1
  310. package/.next/standalone/packages/ui/.next/static/chunks/5f97d665a4d9dc62.js +0 -3
  311. package/.next/standalone/packages/ui/.next/static/chunks/9b7b7024c39c5f99.js +0 -1
  312. package/.next/standalone/packages/ui/.next/static/chunks/aa47b212786d8695.js +0 -1
  313. package/.next/standalone/packages/ui/.next/static/chunks/ae04dcd433be6dab.js +0 -1
  314. package/.next/standalone/packages/ui/.next/static/chunks/c0576ccd1437ac5e.css +0 -1
  315. package/.next/standalone/packages/ui/.next/static/chunks/c0fe4c94c7282ac0.js +0 -4
  316. package/.next/standalone/packages/ui/.next/static/chunks/c61cbb6a0ba3b6ab.js +0 -1
  317. package/.next/standalone/packages/ui/.next/static/chunks/d79bf953f0dfb650.js +0 -1
  318. package/.next/standalone/packages/ui/.next/static/chunks/e50fb8d0b728cd35.js +0 -5
  319. package/.next/standalone/packages/ui/.next/static/chunks/e6e238dbf1d3e740.js +0 -1
  320. package/.next/standalone/packages/ui/.next/static/chunks/turbopack-9cc79aa1b34ffcbe.js +0 -3
  321. package/.next/static/chunks/093ea4b175adb770.js +0 -1
  322. package/.next/static/chunks/5f97d665a4d9dc62.js +0 -3
  323. package/.next/static/chunks/9b7b7024c39c5f99.js +0 -1
  324. package/.next/static/chunks/aa47b212786d8695.js +0 -1
  325. package/.next/static/chunks/ae04dcd433be6dab.js +0 -1
  326. package/.next/static/chunks/c0576ccd1437ac5e.css +0 -1
  327. package/.next/static/chunks/c0fe4c94c7282ac0.js +0 -4
  328. package/.next/static/chunks/c61cbb6a0ba3b6ab.js +0 -1
  329. package/.next/static/chunks/d79bf953f0dfb650.js +0 -1
  330. package/.next/static/chunks/e50fb8d0b728cd35.js +0 -5
  331. package/.next/static/chunks/e6e238dbf1d3e740.js +0 -1
  332. package/.next/static/chunks/turbopack-9cc79aa1b34ffcbe.js +0 -3
  333. /package/.next/standalone/packages/ui/.next/static/{fMRsihZys1Dhy9qQRwNrc → T1wNN9JmkdwBabQsqL-tC}/_buildManifest.js +0 -0
  334. /package/.next/standalone/packages/ui/.next/static/{fMRsihZys1Dhy9qQRwNrc → T1wNN9JmkdwBabQsqL-tC}/_clientMiddlewareManifest.json +0 -0
  335. /package/.next/standalone/packages/ui/.next/static/{fMRsihZys1Dhy9qQRwNrc → T1wNN9JmkdwBabQsqL-tC}/_ssgManifest.js +0 -0
  336. /package/.next/static/{fMRsihZys1Dhy9qQRwNrc → T1wNN9JmkdwBabQsqL-tC}/_buildManifest.js +0 -0
  337. /package/.next/static/{fMRsihZys1Dhy9qQRwNrc → T1wNN9JmkdwBabQsqL-tC}/_clientMiddlewareManifest.json +0 -0
  338. /package/.next/static/{fMRsihZys1Dhy9qQRwNrc → T1wNN9JmkdwBabQsqL-tC}/_ssgManifest.js +0 -0
@@ -4,6 +4,7 @@ import { Navigation } from "@/components/navigation";
4
4
  import { MainSidebar } from "@/components/main-sidebar";
5
5
  import { ThemeProvider } from "@/components/theme-provider";
6
6
  import { Toast } from "@/components/ui/toast";
7
+ import { ProjectProvider } from "@/contexts/project-context";
7
8
  import { getSpecs } from "@/lib/db/service-queries";
8
9
 
9
10
  export const metadata: Metadata = {
@@ -56,14 +57,16 @@ export default async function RootLayout({
56
57
  enableSystem
57
58
  disableTransitionOnChange
58
59
  >
59
- <Navigation specs={specsForSearch} />
60
- <div className="flex w-full min-w-0">
61
- <MainSidebar />
62
- <main className="flex-1 min-h-[calc(100vh-3.5rem)] min-w-0 w-full lg:w-[calc(100vw-var(--main-sidebar-width,240px))]">
63
- {children}
64
- </main>
65
- </div>
66
- <Toast />
60
+ <ProjectProvider>
61
+ <Navigation specs={specsForSearch} />
62
+ <div className="flex w-full min-w-0">
63
+ <MainSidebar />
64
+ <main className="flex-1 min-h-[calc(100vh-3.5rem)] min-w-0 w-full lg:w-[calc(100vw-var(--main-sidebar-width,240px))]">
65
+ {children}
66
+ </main>
67
+ </div>
68
+ <Toast />
69
+ </ProjectProvider>
67
70
  </ThemeProvider>
68
71
  </body>
69
72
  </html>
@@ -18,7 +18,7 @@ export default function NotFound() {
18
18
  <Link href="/">Go Home</Link>
19
19
  </Button>
20
20
  <Button variant="outline" asChild>
21
- <Link href="/board">View Board</Link>
21
+ <Link href="/specs">View Specs</Link>
22
22
  </Button>
23
23
  </div>
24
24
  </div>
@@ -0,0 +1,18 @@
1
+ import { ProjectContextSyncer } from './project-context-syncer';
2
+
3
+ export default async function ProjectLayout({
4
+ children,
5
+ params,
6
+ }: {
7
+ children: React.ReactNode;
8
+ params: Promise<{ projectId: string }>;
9
+ }) {
10
+ const { projectId } = await params;
11
+
12
+ return (
13
+ <>
14
+ <ProjectContextSyncer projectId={projectId} />
15
+ {children}
16
+ </>
17
+ );
18
+ }
@@ -0,0 +1,10 @@
1
+ import { redirect } from 'next/navigation';
2
+
3
+ export default async function ProjectPage({
4
+ params,
5
+ }: {
6
+ params: Promise<{ projectId: string }>;
7
+ }) {
8
+ const { projectId } = await params;
9
+ redirect(`/projects/${projectId}/specs`);
10
+ }
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+
3
+ import { useEffect } from 'react';
4
+ import { useProject } from '@/contexts/project-context';
5
+
6
+ export function ProjectContextSyncer({ projectId }: { projectId: string }) {
7
+ const { switchProject, currentProject } = useProject();
8
+
9
+ useEffect(() => {
10
+ if (projectId && (!currentProject || currentProject.id !== projectId)) {
11
+ switchProject(projectId).catch(console.error);
12
+ }
13
+ }, [projectId, currentProject, switchProject]);
14
+
15
+ return null;
16
+ }
@@ -0,0 +1,34 @@
1
+ import { notFound } from 'next/navigation';
2
+ import { getSpecById, getSpecsWithSubSpecCount } from '@/lib/db/service-queries';
3
+ import { SpecDetailWrapper } from '@/components/spec-detail-wrapper';
4
+
5
+ export const revalidate = 0; // No caching for local dev
6
+ export const dynamic = 'force-dynamic';
7
+
8
+ export default async function ProjectSpecDetailPage({
9
+ params,
10
+ searchParams
11
+ }: {
12
+ params: Promise<{ projectId: string; specId: string }>;
13
+ searchParams: Promise<{ subspec?: string }>;
14
+ }) {
15
+ const { projectId, specId } = await params;
16
+ const { subspec: currentSubSpec } = await searchParams;
17
+
18
+ const [spec, allSpecs] = await Promise.all([
19
+ getSpecById(specId, projectId),
20
+ getSpecsWithSubSpecCount(projectId)
21
+ ]);
22
+
23
+ if (!spec) {
24
+ notFound();
25
+ }
26
+
27
+ return (
28
+ <SpecDetailWrapper
29
+ spec={spec}
30
+ allSpecs={allSpecs}
31
+ currentSubSpec={currentSubSpec}
32
+ />
33
+ );
34
+ }
@@ -0,0 +1,20 @@
1
+ import { getSpecsWithMetadata, getStats } from '@/lib/db/service-queries';
2
+ import { SpecsClient } from '@/app/specs/specs-client';
3
+
4
+ // Force dynamic rendering
5
+ export const dynamic = 'force-dynamic';
6
+
7
+ export default async function ProjectSpecsPage({
8
+ params,
9
+ }: {
10
+ params: Promise<{ projectId: string }>;
11
+ }) {
12
+ const { projectId } = await params;
13
+
14
+ const [specs, stats] = await Promise.all([
15
+ getSpecsWithMetadata(projectId),
16
+ getStats(projectId),
17
+ ]);
18
+
19
+ return <SpecsClient initialSpecs={specs} initialStats={stats} projectId={projectId} />;
20
+ }
@@ -0,0 +1,156 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Plus, Search, FolderOpen, Star, MoreVertical, Trash2 } from 'lucide-react';
5
+ import { useProject } from '@/contexts/project-context';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Input } from '@/components/ui/input';
8
+ import {
9
+ Card,
10
+ CardContent,
11
+ CardDescription,
12
+ CardHeader,
13
+ CardTitle,
14
+ } from '@/components/ui/card';
15
+ import {
16
+ DropdownMenu,
17
+ DropdownMenuContent,
18
+ DropdownMenuItem,
19
+ DropdownMenuTrigger,
20
+ } from '@/components/ui/dropdown-menu';
21
+ import { CreateProjectDialog } from '@/components/create-project-dialog';
22
+ import dayjs from 'dayjs';
23
+ import relativeTime from 'dayjs/plugin/relativeTime';
24
+
25
+ dayjs.extend(relativeTime);
26
+
27
+ export default function ProjectsPage() {
28
+ const { projects, switchProject, toggleFavorite, removeProject } = useProject();
29
+ const [searchQuery, setSearchQuery] = useState('');
30
+ const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
31
+
32
+ const filteredProjects = projects.filter((p) =>
33
+ p.name.toLowerCase().includes(searchQuery.toLowerCase())
34
+ );
35
+
36
+ const handleProjectClick = async (projectId: string) => {
37
+ await switchProject(projectId);
38
+ // Optionally navigate to dashboard, but switchProject might handle it or we stay here
39
+ };
40
+
41
+ return (
42
+ <div className="container max-w-5xl py-8 space-y-8">
43
+ <div className="flex items-center justify-between">
44
+ <div>
45
+ <h1 className="text-3xl font-bold tracking-tight">Projects</h1>
46
+ <p className="text-muted-foreground mt-2">
47
+ Manage your LeanSpec projects and workspaces.
48
+ </p>
49
+ </div>
50
+ <Button onClick={() => setIsCreateDialogOpen(true)}>
51
+ <Plus className="mr-2 h-4 w-4" />
52
+ Add Project
53
+ </Button>
54
+ </div>
55
+
56
+ <div className="flex items-center space-x-2">
57
+ <div className="relative flex-1 max-w-sm">
58
+ <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
59
+ <Input
60
+ placeholder="Search projects..."
61
+ value={searchQuery}
62
+ onChange={(e) => setSearchQuery(e.target.value)}
63
+ className="pl-8"
64
+ />
65
+ </div>
66
+ </div>
67
+
68
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
69
+ {filteredProjects.map((project) => (
70
+ <Card key={project.id} className="group relative hover:border-primary/50 transition-colors">
71
+ <CardHeader className="pb-4">
72
+ <div className="flex items-start justify-between">
73
+ <div className="flex items-center space-x-2">
74
+ <div
75
+ className="h-8 w-8 rounded-full flex items-center justify-center text-white text-xs font-bold"
76
+ style={{ backgroundColor: project.color || '#666' }}
77
+ >
78
+ {project.name.substring(0, 2).toUpperCase()}
79
+ </div>
80
+ <div className="space-y-1">
81
+ <CardTitle className="text-base leading-none">
82
+ <button
83
+ onClick={() => handleProjectClick(project.id)}
84
+ className="hover:underline focus:outline-none"
85
+ >
86
+ {project.name}
87
+ </button>
88
+ </CardTitle>
89
+ <CardDescription className="text-xs truncate max-w-[150px]">
90
+ {project.path}
91
+ </CardDescription>
92
+ </div>
93
+ </div>
94
+ <DropdownMenu>
95
+ <DropdownMenuTrigger asChild>
96
+ <Button variant="ghost" size="icon" className="h-8 w-8">
97
+ <MoreVertical className="h-4 w-4" />
98
+ <span className="sr-only">Open menu</span>
99
+ </Button>
100
+ </DropdownMenuTrigger>
101
+ <DropdownMenuContent align="end">
102
+ <DropdownMenuItem onClick={() => toggleFavorite(project.id)}>
103
+ <Star className="mr-2 h-4 w-4" />
104
+ {project.favorite ? 'Unfavorite' : 'Favorite'}
105
+ </DropdownMenuItem>
106
+ <DropdownMenuItem className="text-destructive" onClick={() => removeProject(project.id)}>
107
+ <Trash2 className="mr-2 h-4 w-4" />
108
+ Remove
109
+ </DropdownMenuItem>
110
+ </DropdownMenuContent>
111
+ </DropdownMenu>
112
+ </div>
113
+ </CardHeader>
114
+ <CardContent className="pb-4">
115
+ <div className="flex items-center justify-between text-sm text-muted-foreground">
116
+ <div className="flex items-center">
117
+ <FolderOpen className="mr-1 h-3 w-3" />
118
+ <span className="text-xs">Local</span>
119
+ </div>
120
+ {project.lastAccessed && (
121
+ <span className="text-xs">
122
+ Opened {dayjs(project.lastAccessed).fromNow()}
123
+ </span>
124
+ )}
125
+ </div>
126
+ </CardContent>
127
+ {project.favorite && (
128
+ <div className="absolute top-2 right-10 text-yellow-500">
129
+ <Star className="h-4 w-4 fill-current" />
130
+ </div>
131
+ )}
132
+ </Card>
133
+ ))}
134
+
135
+ {filteredProjects.length === 0 && (
136
+ <div className="col-span-full flex flex-col items-center justify-center py-12 text-center border rounded-lg border-dashed">
137
+ <FolderOpen className="h-10 w-10 text-muted-foreground mb-4" />
138
+ <h3 className="text-lg font-medium">No projects found</h3>
139
+ <p className="text-sm text-muted-foreground mt-1 mb-4">
140
+ {searchQuery ? "Try adjusting your search query." : "Get started by adding your first project."}
141
+ </p>
142
+ <Button onClick={() => setIsCreateDialogOpen(true)}>
143
+ <Plus className="mr-2 h-4 w-4" />
144
+ Add Project
145
+ </Button>
146
+ </div>
147
+ )}
148
+ </div>
149
+
150
+ <CreateProjectDialog
151
+ open={isCreateDialogOpen}
152
+ onOpenChange={setIsCreateDialogOpen}
153
+ />
154
+ </div>
155
+ );
156
+ }
@@ -102,12 +102,13 @@ interface Stats {
102
102
  interface SpecsClientProps {
103
103
  initialSpecs: Spec[];
104
104
  initialStats: Stats;
105
+ projectId?: string;
105
106
  }
106
107
 
107
108
  type ViewMode = 'list' | 'board';
108
109
  type SortBy = 'id-desc' | 'id-asc' | 'updated-desc' | 'title-asc';
109
110
 
110
- export function SpecsClient({ initialSpecs }: SpecsClientProps) {
111
+ export function SpecsClient({ initialSpecs, projectId }: SpecsClientProps) {
111
112
  const searchParams = useSearchParams();
112
113
  const router = useRouter();
113
114
 
@@ -147,7 +148,11 @@ export function SpecsClient({ initialSpecs }: SpecsClientProps) {
147
148
  setSpecs((prev) => prev.map(item => item.id === spec.id ? { ...item, status: nextStatus } : item));
148
149
 
149
150
  try {
150
- const response = await fetch(`/api/specs/${encodeURIComponent(spec.specName)}/status`, {
151
+ const url = projectId
152
+ ? `/api/projects/${projectId}/specs/${encodeURIComponent(spec.specName)}/status`
153
+ : `/api/specs/${encodeURIComponent(spec.specName)}/status`;
154
+
155
+ const response = await fetch(url, {
151
156
  method: 'PATCH',
152
157
  headers: {
153
158
  'Content-Type': 'application/json',
@@ -0,0 +1,139 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import { useProject } from '@/contexts/project-context';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Input } from '@/components/ui/input';
8
+ import { DirectoryPicker } from './directory-picker';
9
+ import { FolderOpen } from 'lucide-react';
10
+ import {
11
+ Dialog,
12
+ DialogContent,
13
+ DialogDescription,
14
+ DialogFooter,
15
+ DialogHeader,
16
+ DialogTitle,
17
+ } from '@/components/ui/dialog';
18
+ import { toast } from 'sonner';
19
+
20
+ interface CreateProjectDialogProps {
21
+ open: boolean;
22
+ onOpenChange: (open: boolean) => void;
23
+ }
24
+
25
+ export function CreateProjectDialog({ open, onOpenChange }: CreateProjectDialogProps) {
26
+ const { addProject, switchProject } = useProject();
27
+ const [path, setPath] = useState('');
28
+ const [isLoading, setIsLoading] = useState(false);
29
+ const [mode, setMode] = useState<'picker' | 'manual'>('picker');
30
+ const router = useRouter();
31
+
32
+ useEffect(() => {
33
+ if (open) {
34
+ setMode('picker');
35
+ setPath('');
36
+ }
37
+ }, [open]);
38
+
39
+ const handleAddProject = async (projectPath: string) => {
40
+ try {
41
+ setIsLoading(true);
42
+ const project = await addProject(projectPath);
43
+ await switchProject(project.id);
44
+ toast.success('Project added successfully');
45
+ onOpenChange(false);
46
+ router.push('/'); // Navigate to dashboard
47
+ } catch (error) {
48
+ const message = error instanceof Error ? error.message : 'Failed to add project';
49
+ toast.error(message);
50
+ } finally {
51
+ setIsLoading(false);
52
+ }
53
+ };
54
+
55
+ const handleSubmit = (e: React.FormEvent) => {
56
+ e.preventDefault();
57
+ if (!path) return;
58
+ handleAddProject(path);
59
+ };
60
+
61
+ return (
62
+ <Dialog open={open} onOpenChange={onOpenChange}>
63
+ <DialogContent className="sm:max-w-[600px]">
64
+ <DialogHeader>
65
+ <DialogTitle>Add Project</DialogTitle>
66
+ <DialogDescription>
67
+ {mode === 'picker'
68
+ ? 'Browse and select the project directory.'
69
+ : 'Enter the absolute path to your local project directory.'}
70
+ </DialogDescription>
71
+ </DialogHeader>
72
+
73
+ {mode === 'picker' ? (
74
+ <div className="space-y-2">
75
+ <DirectoryPicker
76
+ onSelect={handleAddProject}
77
+ onCancel={() => onOpenChange(false)}
78
+ initialPath={path}
79
+ actionLabel={isLoading ? "Adding..." : "Add Project"}
80
+ isLoading={isLoading}
81
+ />
82
+ <div className="flex justify-center">
83
+ <Button
84
+ variant="link"
85
+ size="sm"
86
+ onClick={() => setMode('manual')}
87
+ className="text-muted-foreground"
88
+ >
89
+ Enter path manually
90
+ </Button>
91
+ </div>
92
+ </div>
93
+ ) : (
94
+ <form onSubmit={handleSubmit}>
95
+ <div className="grid gap-4 py-4">
96
+ <div className="grid gap-2">
97
+ <label htmlFor="path" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
98
+ Project Path
99
+ </label>
100
+ <div className="flex gap-2">
101
+ <Input
102
+ id="path"
103
+ value={path}
104
+ onChange={(e) => setPath(e.target.value)}
105
+ placeholder="/path/to/your/project"
106
+ className="flex-1"
107
+ disabled={isLoading}
108
+ />
109
+ </div>
110
+ <p className="text-xs text-muted-foreground">
111
+ Select the root directory of your project.
112
+ </p>
113
+ </div>
114
+ </div>
115
+ <DialogFooter className="flex-col sm:flex-row gap-2">
116
+ <div className="flex-1 flex justify-start">
117
+ <Button
118
+ type="button"
119
+ variant="ghost"
120
+ size="sm"
121
+ onClick={() => setMode('picker')}
122
+ >
123
+ <FolderOpen className="h-4 w-4 mr-2" />
124
+ Browse folders
125
+ </Button>
126
+ </div>
127
+ <Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={isLoading}>
128
+ Cancel
129
+ </Button>
130
+ <Button type="submit" disabled={isLoading || !path}>
131
+ {isLoading ? 'Adding...' : 'Add Project'}
132
+ </Button>
133
+ </DialogFooter>
134
+ </form>
135
+ )}
136
+ </DialogContent>
137
+ </Dialog>
138
+ );
139
+ }
@@ -0,0 +1,191 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useRef } from 'react';
4
+ import { Button } from '@/components/ui/button';
5
+ import { Folder, ChevronUp, Loader2, ArrowLeft, Home, ChevronRight } from 'lucide-react';
6
+ import { cn } from '@/lib/utils';
7
+
8
+ interface DirectoryItem {
9
+ name: string;
10
+ path: string;
11
+ isDirectory: boolean;
12
+ }
13
+
14
+ interface DirectoryPickerProps {
15
+ onSelect: (path: string) => void;
16
+ onCancel: () => void;
17
+ initialPath?: string;
18
+ actionLabel?: string;
19
+ isLoading?: boolean;
20
+ }
21
+
22
+ export function DirectoryPicker({ onSelect, onCancel, initialPath, actionLabel = "Select This Folder", isLoading: externalLoading }: DirectoryPickerProps) {
23
+ const [currentPath, setCurrentPath] = useState(initialPath || '');
24
+ const [items, setItems] = useState<DirectoryItem[]>([]);
25
+ const [internalLoading, setInternalLoading] = useState(false);
26
+ const [error, setError] = useState<string | null>(null);
27
+ const scrollContainerRef = useRef<HTMLDivElement>(null);
28
+
29
+ const isLoading = externalLoading || internalLoading;
30
+
31
+ useEffect(() => {
32
+ fetchDirectory(currentPath);
33
+ }, [currentPath]);
34
+
35
+ // Auto-scroll breadcrumbs to end when path changes
36
+ useEffect(() => {
37
+ if (scrollContainerRef.current) {
38
+ scrollContainerRef.current.scrollLeft = scrollContainerRef.current.scrollWidth;
39
+ }
40
+ }, [currentPath]);
41
+
42
+ const fetchDirectory = async (path: string) => {
43
+ try {
44
+ setInternalLoading(true);
45
+ setError(null);
46
+ const response = await fetch('/api/local-projects/list-directory', {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify({ path }),
50
+ });
51
+
52
+ if (!response.ok) {
53
+ throw new Error('Failed to list directory');
54
+ }
55
+
56
+ const data = await response.json();
57
+ setItems(data.items);
58
+ // Update current path to the resolved path from server
59
+ if (!path) {
60
+ setCurrentPath(data.path);
61
+ }
62
+ } catch (err) {
63
+ setError(err instanceof Error ? err.message : String(err));
64
+ } finally {
65
+ setInternalLoading(false);
66
+ }
67
+ };
68
+
69
+ const handleNavigate = (path: string) => {
70
+ setCurrentPath(path);
71
+ };
72
+
73
+ const parentItem = items.find(item => item.name === '..');
74
+ const displayItems = items.filter(item => item.name !== '..');
75
+
76
+ // Parse path segments for breadcrumbs
77
+ const getPathSegments = (path: string) => {
78
+ if (!path) return [];
79
+ // Handle both Unix and Windows separators
80
+ const separator = path.includes('\\') ? '\\' : '/';
81
+ const parts = path.split(separator).filter(Boolean);
82
+
83
+ // If path starts with separator (Unix root), add it back
84
+ const isUnixRoot = path.startsWith('/');
85
+
86
+ return parts.map((part, index) => {
87
+ let segmentPath = parts.slice(0, index + 1).join(separator);
88
+ if (isUnixRoot) segmentPath = '/' + segmentPath;
89
+ // On Windows, the first part (C:) doesn't need a leading separator
90
+
91
+ return { name: part, path: segmentPath };
92
+ });
93
+ };
94
+
95
+ const segments = getPathSegments(currentPath);
96
+
97
+ return (
98
+ <div className="flex flex-col h-[400px] gap-4 min-w-0">
99
+ {/* Navigation Bar */}
100
+ <div className="flex items-center border rounded-md p-1 gap-1 bg-muted/30">
101
+ <Button
102
+ variant="ghost"
103
+ size="icon"
104
+ className="h-8 w-8 shrink-0"
105
+ disabled={!parentItem || isLoading}
106
+ onClick={() => parentItem && handleNavigate(parentItem.path)}
107
+ title="Go to parent directory"
108
+ >
109
+ <ArrowLeft className="h-4 w-4" />
110
+ </Button>
111
+
112
+ <div className="w-px h-5 bg-border mx-1" />
113
+
114
+ <div
115
+ ref={scrollContainerRef}
116
+ className="flex-1 overflow-x-auto whitespace-nowrap flex items-center scrollbar-hide px-1 min-w-0"
117
+ >
118
+ <button
119
+ onClick={() => handleNavigate('/')}
120
+ className="hover:bg-accent p-1 rounded-sm transition-colors shrink-0"
121
+ title="Go to root"
122
+ >
123
+ <Home className="h-4 w-4 text-muted-foreground" />
124
+ </button>
125
+
126
+ {segments.map((segment, i) => (
127
+ <div key={segment.path} className="flex items-center shrink-0">
128
+ <ChevronRight className="h-3 w-3 text-muted-foreground mx-0.5 shrink-0" />
129
+ <button
130
+ onClick={() => handleNavigate(segment.path)}
131
+ className={cn(
132
+ "px-1.5 py-0.5 rounded-sm transition-colors text-sm hover:bg-accent hover:text-accent-foreground",
133
+ i === segments.length - 1 ? "font-medium text-foreground" : "text-muted-foreground"
134
+ )}
135
+ >
136
+ {segment.name}
137
+ </button>
138
+ </div>
139
+ ))}
140
+ </div>
141
+ </div>
142
+
143
+ <div className="flex-1 border rounded-md overflow-hidden relative bg-background min-h-0">
144
+ {isLoading && (
145
+ <div className="absolute inset-0 bg-background/50 flex items-center justify-center z-10">
146
+ <Loader2 className="h-6 w-6 animate-spin" />
147
+ </div>
148
+ )}
149
+
150
+ {error ? (
151
+ <div className="p-4 text-destructive text-sm text-center">
152
+ {error}
153
+ <Button variant="link" onClick={() => fetchDirectory(currentPath)} className="block mx-auto mt-2">
154
+ Retry
155
+ </Button>
156
+ </div>
157
+ ) : (
158
+ <div className="h-full overflow-auto">
159
+ <div className="p-1">
160
+ {displayItems.length === 0 && !isLoading ? (
161
+ <div className="p-4 text-center text-sm text-muted-foreground">
162
+ Empty directory
163
+ </div>
164
+ ) : (
165
+ displayItems.map((item) => (
166
+ <button
167
+ key={item.path}
168
+ onClick={() => handleNavigate(item.path)}
169
+ className="flex items-center gap-3 w-full px-3 py-2 text-sm rounded-sm hover:bg-accent hover:text-accent-foreground text-left group transition-colors"
170
+ >
171
+ <Folder className="h-4 w-4 text-blue-500 fill-blue-500/20 group-hover:fill-blue-500/30 transition-colors shrink-0" />
172
+ <span className="truncate">{item.name}</span>
173
+ </button>
174
+ ))
175
+ )}
176
+ </div>
177
+ </div>
178
+ )}
179
+ </div>
180
+
181
+ <div className="flex justify-end gap-2">
182
+ <Button variant="outline" onClick={onCancel} disabled={isLoading}>
183
+ Cancel
184
+ </Button>
185
+ <Button onClick={() => onSelect(currentPath)} disabled={isLoading || !currentPath}>
186
+ {actionLabel}
187
+ </Button>
188
+ </div>
189
+ </div>
190
+ );
191
+ }
@@ -3,6 +3,7 @@
3
3
  import Link from 'next/link';
4
4
  import { usePathname } from 'next/navigation';
5
5
  import { Home, FileText, BarChart3, ChevronLeft, ChevronRight, X } from 'lucide-react';
6
+ import { ProjectSwitcher } from '@/components/project-switcher';
6
7
  import { Button } from '@/components/ui/button';
7
8
  import { cn } from '@/lib/utils';
8
9
  import * as React from 'react';
@@ -121,6 +122,9 @@ export function MainSidebar() {
121
122
 
122
123
  {/* Navigation */}
123
124
  {mounted && <nav className="flex-1 px-2 py-4 space-y-1">
125
+ <div className="mb-4">
126
+ <ProjectSwitcher collapsed={isCollapsed && !mobileOpen} />
127
+ </div>
124
128
  <SidebarLink
125
129
  href="/"
126
130
  icon={Home}