@leanspec/ui 0.2.5-dev.20251120070726 → 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 (361) 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 +12 -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 +91 -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/app-paths-manifest.json +3 -0
  28. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route/build-manifest.json +11 -0
  29. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route/server-reference-manifest.json +4 -0
  30. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js +6 -0
  31. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.map +5 -0
  32. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.nft.json +1 -0
  33. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route_client-reference-manifest.js +2 -0
  34. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route/app-paths-manifest.json +3 -0
  35. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route/build-manifest.json +11 -0
  36. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route/server-reference-manifest.json +4 -0
  37. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js +6 -0
  38. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.map +5 -0
  39. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.nft.json +1 -0
  40. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route_client-reference-manifest.js +2 -0
  41. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route/app-paths-manifest.json +3 -0
  42. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route/build-manifest.json +11 -0
  43. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route/server-reference-manifest.json +4 -0
  44. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js +6 -0
  45. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.map +5 -0
  46. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.nft.json +1 -0
  47. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route_client-reference-manifest.js +2 -0
  48. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route/app-paths-manifest.json +3 -0
  49. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route/build-manifest.json +11 -0
  50. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route/server-reference-manifest.json +4 -0
  51. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js +6 -0
  52. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.map +5 -0
  53. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.nft.json +1 -0
  54. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route_client-reference-manifest.js +2 -0
  55. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route/app-paths-manifest.json +3 -0
  56. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route/build-manifest.json +11 -0
  57. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route/server-reference-manifest.json +4 -0
  58. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js +8 -0
  59. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.map +5 -0
  60. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.nft.json +1 -0
  61. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +2 -0
  62. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route/app-paths-manifest.json +3 -0
  63. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route/build-manifest.json +11 -0
  64. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route/server-reference-manifest.json +4 -0
  65. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js +9 -0
  66. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.map +5 -0
  67. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.nft.json +1 -0
  68. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route_client-reference-manifest.js +2 -0
  69. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route/app-paths-manifest.json +3 -0
  70. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route/build-manifest.json +11 -0
  71. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route/server-reference-manifest.json +4 -0
  72. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js +8 -0
  73. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.map +5 -0
  74. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.nft.json +1 -0
  75. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route_client-reference-manifest.js +2 -0
  76. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js +4 -2
  77. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
  78. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route/app-paths-manifest.json +3 -0
  79. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route/build-manifest.json +11 -0
  80. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route/server-reference-manifest.json +4 -0
  81. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js +8 -0
  82. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.map +5 -0
  83. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.nft.json +1 -0
  84. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route_client-reference-manifest.js +2 -0
  85. package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js +3 -2
  86. package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js.nft.json +1 -1
  87. package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js +4 -2
  88. package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js.nft.json +1 -1
  89. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js +4 -2
  90. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
  91. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js +4 -2
  92. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
  93. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js +4 -3
  94. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js.nft.json +1 -1
  95. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js +4 -2
  96. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
  97. package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js +4 -2
  98. package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js.nft.json +1 -1
  99. package/.next/standalone/packages/ui/.next/server/app/page/build-manifest.json +5 -4
  100. package/.next/standalone/packages/ui/.next/server/app/page.js +2 -2
  101. package/.next/standalone/packages/ui/.next/server/app/page.js.nft.json +1 -1
  102. package/.next/standalone/packages/ui/.next/server/app/page_client-reference-manifest.js +1 -1
  103. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/app-paths-manifest.json +3 -0
  104. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/build-manifest.json +18 -0
  105. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/next-font-manifest.json +6 -0
  106. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/react-loadable-manifest.json +1 -0
  107. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/server-reference-manifest.json +4 -0
  108. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js +21 -0
  109. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.map +5 -0
  110. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.nft.json +1 -0
  111. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +2 -0
  112. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/app-paths-manifest.json +3 -0
  113. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/build-manifest.json +18 -0
  114. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/next-font-manifest.json +6 -0
  115. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/react-loadable-manifest.json +1 -0
  116. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/server-reference-manifest.json +4 -0
  117. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js +21 -0
  118. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.map +5 -0
  119. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.nft.json +1 -0
  120. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page_client-reference-manifest.js +2 -0
  121. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/app-paths-manifest.json +3 -0
  122. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/build-manifest.json +18 -0
  123. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/next-font-manifest.json +6 -0
  124. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/react-loadable-manifest.json +1 -0
  125. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/server-reference-manifest.json +4 -0
  126. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js +20 -0
  127. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.map +5 -0
  128. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.nft.json +1 -0
  129. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page_client-reference-manifest.js +2 -0
  130. package/.next/standalone/packages/ui/.next/server/app/projects/page/app-paths-manifest.json +3 -0
  131. package/.next/standalone/packages/ui/.next/server/app/projects/page/build-manifest.json +18 -0
  132. package/.next/standalone/packages/ui/.next/server/app/projects/page/next-font-manifest.json +6 -0
  133. package/.next/standalone/packages/ui/.next/server/app/projects/page/react-loadable-manifest.json +1 -0
  134. package/.next/standalone/packages/ui/.next/server/app/projects/page/server-reference-manifest.json +4 -0
  135. package/.next/standalone/packages/ui/.next/server/app/projects/page.js +19 -0
  136. package/.next/standalone/packages/ui/.next/server/app/projects/page.js.map +5 -0
  137. package/.next/standalone/packages/ui/.next/server/app/projects/page.js.nft.json +1 -0
  138. package/.next/standalone/packages/ui/.next/server/app/projects/page_client-reference-manifest.js +2 -0
  139. package/.next/standalone/packages/ui/.next/server/app/projects.html +2 -0
  140. package/.next/standalone/packages/ui/.next/server/app/projects.meta +14 -0
  141. package/.next/standalone/packages/ui/.next/server/app/projects.rsc +34 -0
  142. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_full.segment.rsc +34 -0
  143. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_index.segment.rsc +27 -0
  144. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_tree.segment.rsc +9 -0
  145. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +9 -0
  146. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects.segment.rsc +4 -0
  147. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page/build-manifest.json +5 -4
  148. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js +4 -4
  149. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js.nft.json +1 -1
  150. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
  151. package/.next/standalone/packages/ui/.next/server/app/specs/page/build-manifest.json +5 -4
  152. package/.next/standalone/packages/ui/.next/server/app/specs/page.js +2 -2
  153. package/.next/standalone/packages/ui/.next/server/app/specs/page.js.nft.json +1 -1
  154. package/.next/standalone/packages/ui/.next/server/app/specs/page_client-reference-manifest.js +1 -1
  155. package/.next/standalone/packages/ui/.next/server/app/stats/page/build-manifest.json +5 -4
  156. package/.next/standalone/packages/ui/.next/server/app/stats/page.js +2 -2
  157. package/.next/standalone/packages/ui/.next/server/app/stats/page.js.nft.json +1 -1
  158. package/.next/standalone/packages/ui/.next/server/app/stats/page_client-reference-manifest.js +1 -1
  159. package/.next/standalone/packages/ui/.next/server/app-paths-manifest.json +12 -0
  160. package/.next/standalone/packages/ui/.next/server/chunks/6681a__next-internal_server_app_api_projects_[id]_specs_[spec]_route_actions_d018d9e0.js +3 -0
  161. package/.next/standalone/packages/ui/.next/server/chunks/730ea_ui__next-internal_server_app_api_local-projects_[id]_route_actions_664abe9c.js +3 -0
  162. package/.next/standalone/packages/ui/.next/server/chunks/730ea_ui__next-internal_server_app_api_local-projects_discover_route_actions_e6ec3fa7.js +3 -0
  163. package/.next/standalone/packages/ui/.next/server/chunks/730ea_ui__next-internal_server_app_api_projects_[id]_stats_route_actions_a0bb04a8.js +3 -0
  164. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__0fbfea15._.js +3 -0
  165. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__126dea7b._.js +3 -0
  166. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__1f037512._.js +3 -0
  167. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__3559376c._.js +21 -0
  168. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__548e27d4._.js +3 -0
  169. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__65667b70._.js +3 -0
  170. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__675a763e._.js +3 -0
  171. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__803d07f0._.js +3 -0
  172. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8075fe29._.js +3 -0
  173. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8233e09b._.js +3 -0
  174. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__84cdc14a._.js +3 -0
  175. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__9ce722b4._.js +3 -0
  176. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__a2d7cbed._.js +3 -0
  177. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__aa677b0d._.js +3 -0
  178. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__ac744182._.js +3 -0
  179. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bb9fca84._.js +4 -0
  180. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bdc3963a._.js +3 -0
  181. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__f5c6d6b8._.js +3 -0
  182. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__fb91986f._.js +3 -0
  183. package/.next/standalone/packages/ui/.next/server/chunks/f825c_server_app_api_local-projects_list-directory_route_actions_d620ec1a.js +3 -0
  184. package/.next/standalone/packages/ui/.next/server/chunks/f825c_server_app_api_projects_[id]_specs_[spec]_status_route_actions_e9f1bdc5.js +3 -0
  185. package/.next/standalone/packages/ui/.next/server/chunks/node_modules__pnpm_731b55aa._.js +3 -0
  186. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_local-projects_route_actions_9142d5ad.js +3 -0
  187. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_projects_[id]_route_actions_bff49675.js +3 -0
  188. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui_src_lib_db_index_ts_556307fa._.js +64 -5
  189. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui_src_lib_specs_sources_database-source_ts_0bd881ee._.js +3 -0
  190. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui_src_lib_specs_sources_database-source_ts_baa0160d._.js +3 -0
  191. package/.next/standalone/packages/ui/.next/server/chunks/ssr/38a22_sonner_dist_index_mjs_207730fe._.js +3 -0
  192. package/.next/standalone/packages/ui/.next/server/chunks/ssr/6e9bd_next_dist_7af75658._.js +3 -0
  193. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{_a5b58449._.js → 6e9bd_next_dist_df5dcbe9._.js} +2 -2
  194. package/.next/standalone/packages/ui/.next/server/chunks/ssr/730ea_ui__next-internal_server_app_projects_[projectId]_specs_page_actions_82e32fe4.js +3 -0
  195. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__01bfc8ff._.js +3 -0
  196. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__1d0c2012._.js +1 -1
  197. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__41f5b5c0._.js → [root-of-the-server]__4ec37765._.js} +2 -2
  198. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__1af33d49._.js → [root-of-the-server]__50122e7e._.js} +2 -2
  199. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__5382b397._.js +3 -0
  200. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__73f60f12._.js +7 -0
  201. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__88a691ee._.js +3 -0
  202. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a7ae8552._.js +7 -0
  203. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__bdbbba01._.js +3 -0
  204. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__c592f5d1._.js +3 -0
  205. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__cc589a54._.js +3 -0
  206. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__ec5b96a5._.js +3 -0
  207. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__cbbbfb5d._.js → [root-of-the-server]__fd80e4dd._.js} +2 -2
  208. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_000dd317._.js +1 -1
  209. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_196b5a83._.js +3 -0
  210. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_39562b2a._.js +4 -0
  211. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_3b617676._.js +1 -1
  212. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_4129cc0f._.js +3 -0
  213. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_6174313a._.js +3 -0
  214. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_6e4dd8b6._.js +3 -0
  215. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_85effc18._.js +4 -0
  216. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ad8c1e99._.js +1 -1
  217. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_bae6d2b8._.js +4 -0
  218. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_c2f54661._.js +5 -0
  219. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_fdd7780b._.js +4 -0
  220. package/.next/standalone/packages/ui/.next/server/chunks/ssr/f825c_server_app_projects_[projectId]_specs_[specId]_page_actions_22d9c35e.js +3 -0
  221. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_af9d3830._.js +3 -0
  222. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_projects_[projectId]_page_actions_f2986585.js +3 -0
  223. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_projects_page_actions_715940ea.js +3 -0
  224. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_projects_[projectId]_be242d6c._.js +3 -0
  225. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_projects_[projectId]_project-context-syncer_tsx_7954ea3b._.js +3 -0
  226. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_projects_page_tsx_6e166c8e._.js +3 -0
  227. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_specs_specs-client_tsx_0bb8f8f8._.js +1 -1
  228. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_ui_select_tsx_7e21d40f._.js +3 -0
  229. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_lib_specs_sources_database-source_ts_f7186c2a._.js +60 -1
  230. package/.next/standalone/packages/ui/.next/server/middleware-build-manifest.js +5 -4
  231. package/.next/standalone/packages/ui/.next/server/pages/404.html +2 -2
  232. package/.next/standalone/packages/ui/.next/server/pages/500.html +2 -2
  233. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.js +1 -1
  234. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.json +1 -1
  235. package/.next/standalone/packages/ui/.next/static/chunks/07f48b316e895080.js +1 -0
  236. package/.next/standalone/packages/ui/.next/static/chunks/0a7be410b438418a.js +1 -0
  237. package/.next/standalone/packages/ui/.next/static/chunks/1089ca88f6bef846.js +1 -0
  238. package/.next/standalone/packages/ui/.next/static/chunks/17471c87082c392c.js +5 -0
  239. package/.next/standalone/packages/ui/.next/static/chunks/220ba5cb8fe4dd69.js +1 -0
  240. package/.next/standalone/packages/ui/.next/static/chunks/35ccd3286e538bd2.js +1 -0
  241. package/.next/standalone/packages/ui/.next/static/chunks/571033caca823138.js +1 -0
  242. package/.next/standalone/packages/ui/.next/static/chunks/5a6fc30cd64085b4.css +1 -0
  243. package/.next/standalone/packages/ui/.next/static/chunks/5c2072ad938de8ed.js +1 -0
  244. package/.next/standalone/packages/ui/.next/static/chunks/843e1dfdc28e1385.js +1 -0
  245. package/.next/standalone/packages/ui/.next/static/chunks/9dad7fd31627df80.js +1 -0
  246. package/.next/standalone/packages/ui/.next/static/chunks/{c3d4d07de959ecf1.js → a055d4b2866ff8d4.js} +1 -1
  247. package/.next/standalone/packages/ui/.next/static/chunks/afb7c5a4255f4081.js +3 -0
  248. package/.next/{static/chunks/c557ac675be79771.js → standalone/packages/ui/.next/static/chunks/b760a3a9c2c8be28.js} +1 -1
  249. package/.next/standalone/packages/ui/.next/static/chunks/dcdd95180149fa10.js +1 -0
  250. package/.next/standalone/packages/ui/.next/static/chunks/ebd89051637b9a47.js +4 -0
  251. package/.next/standalone/packages/ui/.next/static/chunks/f9db24028d8c058e.js +1 -0
  252. package/.next/standalone/packages/ui/.next/static/chunks/fb640f50455ba34f.js +1 -0
  253. package/.next/standalone/packages/ui/.next/static/chunks/turbopack-b9690cacbf9fe48c.js +3 -0
  254. package/.next/standalone/packages/ui/bin/ui.js +17 -7
  255. package/.next/standalone/packages/ui/package.json +3 -1
  256. package/.next/standalone/packages/ui/src/app/api/local-projects/[id]/route.ts +117 -0
  257. package/.next/standalone/packages/ui/src/app/api/local-projects/discover/route.ts +41 -0
  258. package/.next/standalone/packages/ui/src/app/api/local-projects/list-directory/route.ts +38 -0
  259. package/.next/standalone/packages/ui/src/app/api/local-projects/route.ts +63 -0
  260. package/.next/standalone/packages/ui/src/app/api/projects/[id]/route.ts +97 -0
  261. package/.next/standalone/packages/ui/src/app/api/projects/[id]/specs/[spec]/route.ts +38 -0
  262. package/.next/standalone/packages/ui/src/app/api/projects/[id]/specs/[spec]/status/route.ts +97 -0
  263. package/.next/standalone/packages/ui/src/app/api/projects/[id]/specs/route.ts +7 -0
  264. package/.next/standalone/packages/ui/src/app/api/projects/[id]/stats/route.ts +19 -0
  265. package/.next/standalone/packages/ui/src/app/api/projects/route.ts +48 -1
  266. package/.next/standalone/packages/ui/src/app/dashboard-client.tsx +67 -6
  267. package/.next/standalone/packages/ui/src/app/layout.tsx +11 -8
  268. package/.next/standalone/packages/ui/src/app/not-found.tsx +1 -1
  269. package/.next/standalone/packages/ui/src/app/projects/[projectId]/layout.tsx +18 -0
  270. package/.next/standalone/packages/ui/src/app/projects/[projectId]/page.tsx +10 -0
  271. package/.next/standalone/packages/ui/src/app/projects/[projectId]/project-context-syncer.tsx +16 -0
  272. package/.next/standalone/packages/ui/src/app/projects/[projectId]/specs/[specId]/page.tsx +34 -0
  273. package/.next/standalone/packages/ui/src/app/projects/[projectId]/specs/page.tsx +20 -0
  274. package/.next/standalone/packages/ui/src/app/projects/page.tsx +156 -0
  275. package/.next/standalone/packages/ui/src/app/specs/specs-client.tsx +7 -2
  276. package/.next/standalone/packages/ui/src/components/create-project-dialog.tsx +139 -0
  277. package/.next/standalone/packages/ui/src/components/directory-picker.tsx +191 -0
  278. package/.next/standalone/packages/ui/src/components/main-sidebar.tsx +4 -0
  279. package/.next/standalone/packages/ui/src/components/project-switcher.tsx +139 -0
  280. package/.next/standalone/packages/ui/src/components/ui/dropdown-menu.tsx +200 -0
  281. package/.next/standalone/packages/ui/src/components/ui/popover.tsx +31 -0
  282. package/.next/standalone/packages/ui/src/contexts/project-context.tsx +229 -0
  283. package/.next/standalone/packages/ui/src/lib/db/index.ts +100 -0
  284. package/.next/standalone/packages/ui/src/lib/projects/index.ts +7 -0
  285. package/.next/standalone/packages/ui/src/lib/projects/registry.ts +467 -0
  286. package/.next/standalone/packages/ui/src/lib/projects/types.ts +37 -0
  287. package/.next/standalone/packages/ui/src/lib/specs/service.ts +13 -1
  288. package/.next/standalone/packages/ui/src/lib/specs/sources/multi-project-source.ts +258 -0
  289. package/.next/standalone/packages/ui/tsconfig.tsbuildinfo +1 -1
  290. package/.next/static/chunks/07f48b316e895080.js +1 -0
  291. package/.next/static/chunks/0a7be410b438418a.js +1 -0
  292. package/.next/static/chunks/1089ca88f6bef846.js +1 -0
  293. package/.next/static/chunks/17471c87082c392c.js +5 -0
  294. package/.next/static/chunks/220ba5cb8fe4dd69.js +1 -0
  295. package/.next/static/chunks/35ccd3286e538bd2.js +1 -0
  296. package/.next/static/chunks/571033caca823138.js +1 -0
  297. package/.next/static/chunks/5a6fc30cd64085b4.css +1 -0
  298. package/.next/static/chunks/5c2072ad938de8ed.js +1 -0
  299. package/.next/static/chunks/843e1dfdc28e1385.js +1 -0
  300. package/.next/static/chunks/9dad7fd31627df80.js +1 -0
  301. package/.next/static/chunks/{c3d4d07de959ecf1.js → a055d4b2866ff8d4.js} +1 -1
  302. package/.next/static/chunks/afb7c5a4255f4081.js +3 -0
  303. package/.next/{standalone/packages/ui/.next/static/chunks/c557ac675be79771.js → static/chunks/b760a3a9c2c8be28.js} +1 -1
  304. package/.next/static/chunks/dcdd95180149fa10.js +1 -0
  305. package/.next/static/chunks/ebd89051637b9a47.js +4 -0
  306. package/.next/static/chunks/f9db24028d8c058e.js +1 -0
  307. package/.next/static/chunks/fb640f50455ba34f.js +1 -0
  308. package/.next/static/chunks/turbopack-b9690cacbf9fe48c.js +3 -0
  309. package/bin/ui.js +17 -7
  310. package/package.json +3 -1
  311. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__175bef84._.js +0 -3
  312. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__3971eae5._.js +0 -3
  313. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__482b093a._.js +0 -21
  314. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__6bca1621._.js +0 -3
  315. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__87a3475a._.js +0 -3
  316. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__9f0f4c0b._.js +0 -3
  317. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__c1c9f5f5._.js +0 -3
  318. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__c6689757._.js +0 -3
  319. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__cd1fb0a2._.js +0 -4
  320. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__e2071b2e._.js +0 -3
  321. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__299c81cc._.js +0 -3
  322. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__5ca2e973._.js +0 -3
  323. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__b2fe773d._.js +0 -3
  324. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__e79a982a._.js +0 -7
  325. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__ff03fc1e._.js +0 -7
  326. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_66209e84._.js +0 -3
  327. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_6cd9a5e0._.js +0 -3
  328. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_b483c9fe._.js +0 -3
  329. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_b5040d31._.js +0 -5
  330. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_9710705b._.js +0 -3
  331. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_b8ff10b9._.js +0 -3
  332. package/.next/standalone/packages/ui/.next/static/chunks/093ea4b175adb770.js +0 -1
  333. package/.next/standalone/packages/ui/.next/static/chunks/5f97d665a4d9dc62.js +0 -3
  334. package/.next/standalone/packages/ui/.next/static/chunks/9a80c22382ddcfaf.css +0 -1
  335. package/.next/standalone/packages/ui/.next/static/chunks/9b7b7024c39c5f99.js +0 -1
  336. package/.next/standalone/packages/ui/.next/static/chunks/aa47b212786d8695.js +0 -1
  337. package/.next/standalone/packages/ui/.next/static/chunks/ae04dcd433be6dab.js +0 -1
  338. package/.next/standalone/packages/ui/.next/static/chunks/c0fe4c94c7282ac0.js +0 -4
  339. package/.next/standalone/packages/ui/.next/static/chunks/c61cbb6a0ba3b6ab.js +0 -1
  340. package/.next/standalone/packages/ui/.next/static/chunks/d79bf953f0dfb650.js +0 -1
  341. package/.next/standalone/packages/ui/.next/static/chunks/e50fb8d0b728cd35.js +0 -5
  342. package/.next/standalone/packages/ui/.next/static/chunks/e6e238dbf1d3e740.js +0 -1
  343. package/.next/standalone/packages/ui/.next/static/chunks/turbopack-9cc79aa1b34ffcbe.js +0 -3
  344. package/.next/static/chunks/093ea4b175adb770.js +0 -1
  345. package/.next/static/chunks/5f97d665a4d9dc62.js +0 -3
  346. package/.next/static/chunks/9a80c22382ddcfaf.css +0 -1
  347. package/.next/static/chunks/9b7b7024c39c5f99.js +0 -1
  348. package/.next/static/chunks/aa47b212786d8695.js +0 -1
  349. package/.next/static/chunks/ae04dcd433be6dab.js +0 -1
  350. package/.next/static/chunks/c0fe4c94c7282ac0.js +0 -4
  351. package/.next/static/chunks/c61cbb6a0ba3b6ab.js +0 -1
  352. package/.next/static/chunks/d79bf953f0dfb650.js +0 -1
  353. package/.next/static/chunks/e50fb8d0b728cd35.js +0 -5
  354. package/.next/static/chunks/e6e238dbf1d3e740.js +0 -1
  355. package/.next/static/chunks/turbopack-9cc79aa1b34ffcbe.js +0 -3
  356. /package/.next/standalone/packages/ui/.next/static/{C8sZuJV5DQETshOIgjsmH → T1wNN9JmkdwBabQsqL-tC}/_buildManifest.js +0 -0
  357. /package/.next/standalone/packages/ui/.next/static/{C8sZuJV5DQETshOIgjsmH → T1wNN9JmkdwBabQsqL-tC}/_clientMiddlewareManifest.json +0 -0
  358. /package/.next/standalone/packages/ui/.next/static/{C8sZuJV5DQETshOIgjsmH → T1wNN9JmkdwBabQsqL-tC}/_ssgManifest.js +0 -0
  359. /package/.next/static/{C8sZuJV5DQETshOIgjsmH → T1wNN9JmkdwBabQsqL-tC}/_buildManifest.js +0 -0
  360. /package/.next/static/{C8sZuJV5DQETshOIgjsmH → T1wNN9JmkdwBabQsqL-tC}/_clientMiddlewareManifest.json +0 -0
  361. /package/.next/static/{C8sZuJV5DQETshOIgjsmH → T1wNN9JmkdwBabQsqL-tC}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,17612,22453,e=>{"use strict";var t=e.i(90022),s=e.i(31231),i=e.i(87985);let l="u">typeof window?s.useLayoutEffect:s.useEffect;function n(e){if(void 0!==e)switch(typeof e){case"number":return e;case"string":if(e.endsWith("px"))return parseFloat(e)}}let r=null;function a({containerElement:e,direction:t,isRtl:s,scrollOffset:i}){if("horizontal"===t&&s)switch(function(e=!1){if(null===r||e){let e=document.createElement("div"),t=e.style;t.width="50px",t.height="50px",t.overflow="scroll",t.direction="rtl";let s=document.createElement("div"),i=s.style;return i.width="100px",i.height="100px",e.appendChild(s),document.body.appendChild(e),e.scrollLeft>0?r="positive-descending":(e.scrollLeft=1,r=0===e.scrollLeft?"negative":"positive-ascending"),document.body.removeChild(e),r}return r}()){case"negative":return-i;case"positive-descending":if(e){let{clientWidth:t,scrollLeft:s,scrollWidth:i}=e;return i-t-s}}return i}function o(e,t="Assertion error"){if(!e)throw console.error(t),Error(t)}function c(e,t){if(e===t)return!0;if(!!e!=!!t||(o(void 0!==e),o(void 0!==t),Object.keys(e).length!==Object.keys(t).length))return!1;for(let s in e)if(!Object.is(t[s],e[s]))return!1;return!0}function d({cachedBounds:e,itemCount:t,itemSize:s}){if(0===t)return 0;if("number"==typeof s)return t*s;{let s=e.get(0===e.size?0:e.size-1);return o(void 0!==s,"Unexpected bounds cache miss"),t*((s.scrollOffset+s.size)/e.size)}}function u({cachedBounds:e,containerScrollOffset:t,containerSize:s,itemCount:i,overscanCount:l}){let n=i-1,r=0,a=-1,o=0,c=-1,d=0;for(;d<n;){let s=e.get(d);if(s.scrollOffset+s.size>t)break;d++}for(o=Math.max(0,(r=d)-l);d<n;){let i=e.get(d);if(i.scrollOffset+i.size>=t+s)break;d++}return c=Math.min(i-1,(a=Math.min(n,d))+l),r<0&&(r=0,a=-1,o=0,c=-1),{startIndexVisible:r,stopIndexVisible:a,startIndexOverscan:o,stopIndexOverscan:c}}function h(e,t){let{ariaAttributes:s,style:i,...l}=e,{ariaAttributes:n,style:r,...a}=t;return c(s,n)&&c(i,r)&&c(l,a)}function f({children:e,className:i,defaultHeight:r=0,listRef:f,onResize:m,onRowsRendered:x,overscanCount:p=3,rowComponent:g,rowCount:v,rowHeight:S,rowProps:b,tagName:w="div",style:j,...y}){let N=(0,s.useMemo)(()=>b,Object.values(b)),C=(0,s.useMemo)(()=>(0,s.memo)(g,h),[g]),[I,z]=(0,s.useState)(null),T=null!=S&&"object"==typeof S&&"getAverageRowHeight"in S&&"function"==typeof S.getAverageRowHeight,{getCellBounds:O,getEstimatedSize:R,scrollToIndex:E,startIndexOverscan:A,startIndexVisible:M,stopIndexOverscan:k,stopIndexVisible:L}=function({containerElement:e,containerStyle:t,defaultContainerSize:i=0,direction:r,isRtl:h=!1,itemCount:f,itemProps:m,itemSize:x,onResize:p,overscanCount:g}){var v;let S,[b,w]=(0,s.useState)({startIndexVisible:0,startIndexOverscan:0,stopIndexVisible:-1,stopIndexOverscan:-1}),{startIndexVisible:j,startIndexOverscan:y,stopIndexVisible:N,stopIndexOverscan:C}={startIndexVisible:Math.min(f-1,b.startIndexVisible),startIndexOverscan:Math.min(f-1,b.startIndexOverscan),stopIndexVisible:Math.min(f-1,b.stopIndexVisible),stopIndexOverscan:Math.min(f-1,b.stopIndexOverscan)},{height:I=i,width:z=i}=function({box:e,defaultHeight:t,defaultWidth:i,disabled:r,element:a,mode:o,style:c}){let{styleHeight:d,styleWidth:u}=(0,s.useMemo)(()=>({styleHeight:n(c?.height),styleWidth:n(c?.width)}),[c?.height,c?.width]),[h,f]=(0,s.useState)({height:t,width:i}),m=r||"only-height"===o&&void 0!==d||"only-width"===o&&void 0!==u||void 0!==d&&void 0!==u;return l(()=>{if(null===a||m)return;let t=new ResizeObserver(e=>{for(let t of e){let{contentRect:e,target:s}=t;a===s&&f(t=>t.height===e.height&&t.width===e.width?t:{height:e.height,width:e.width})}});return t.observe(a,{box:e}),()=>{t?.unobserve(a)}},[e,m,a,d,u]),(0,s.useMemo)(()=>({height:d??h.height,width:u??h.width}),[h,d,u])}({defaultHeight:"vertical"===r?i:void 0,defaultWidth:"horizontal"===r?i:void 0,element:e,mode:"vertical"===r?"only-height":"only-width",style:t}),T=(0,s.useRef)({height:0,width:0}),O="vertical"===r?I:z,R=function({containerSize:e,itemSize:t}){let s;return"string"==typeof t?(o(t.endsWith("%"),`Invalid item size: "${t}"; string values must be percentages (e.g. "100%")`),o(void 0!==e,"Container size must be defined if a percentage item size is specified"),s=e*parseInt(t)/100):s=t,s}({containerSize:O,itemSize:x});(0,s.useLayoutEffect)(()=>{if("function"==typeof p){let e=T.current;(e.height!==I||e.width!==z)&&(p({height:I,width:z},{...e}),e.height=I,e.width=z)}},[I,p,z]);let E=function({itemCount:e,itemProps:t,itemSize:i}){return(0,s.useMemo)(()=>(function({itemCount:e,itemProps:t,itemSize:s}){let i=new Map;return{get(l){for(o(l<e,`Invalid index ${l}`);i.size-1<l;){let e,n=i.size;switch(typeof s){case"function":e=s(n,t);break;case"number":e=s}if(0===n)i.set(n,{size:e,scrollOffset:0});else{let t=i.get(n-1);o(void 0!==t,`Unexpected bounds cache miss for index ${l}`),i.set(n,{scrollOffset:t.scrollOffset+t.size,size:e})}}let n=i.get(l);return o(void 0!==n,`Unexpected bounds cache miss for index ${l}`),n},set(e,t){i.set(e,t)},get size(){return i.size}}})({itemCount:e,itemProps:t,itemSize:i}),[e,t,i])}({itemCount:f,itemProps:m,itemSize:R}),A=(0,s.useCallback)(e=>E.get(e),[E]),M=(0,s.useCallback)(()=>d({cachedBounds:E,itemCount:f,itemSize:R}),[E,f,R]),k=(0,s.useCallback)(t=>u({cachedBounds:E,containerScrollOffset:a({containerElement:e,direction:r,isRtl:h,scrollOffset:t}),containerSize:O,itemCount:f,overscanCount:g}),[E,e,O,r,h,f,g]);return l(()=>{w(k(("vertical"===r?e?.scrollTop:e?.scrollLeft)??0))},[e,r,k]),l(()=>{if(!e)return;let t=()=>{w(t=>{let{scrollLeft:s,scrollTop:i}=e,l=u({cachedBounds:E,containerScrollOffset:a({containerElement:e,direction:r,isRtl:h,scrollOffset:"vertical"===r?i:s}),containerSize:O,itemCount:f,overscanCount:g});return c(l,t)?t:l})};return e.addEventListener("scroll",t),()=>{e.removeEventListener("scroll",t)}},[E,e,O,r,f,g]),{getCellBounds:A,getEstimatedSize:M,scrollToIndex:(v=({align:t="auto",containerScrollOffset:s,index:i})=>{let l=function({align:e,cachedBounds:t,index:s,itemCount:i,itemSize:l,containerScrollOffset:n,containerSize:r}){if(s<0||s>=i)throw RangeError(`Invalid index specified: ${s}`,{cause:`Index ${s} is not within the range of 0 - ${i-1}`});let a=d({cachedBounds:t,itemCount:i,itemSize:l}),o=t.get(s),c=Math.max(0,Math.min(a-r,o.scrollOffset)),u=Math.max(0,o.scrollOffset-r+o.size);switch("smart"===e&&(e=n>=u&&n<=c?"auto":"center"),e){case"start":return c;case"end":return u;case"center":return o.scrollOffset<=r/2?0:o.scrollOffset+o.size/2>=a-r/2?a-r:o.scrollOffset+o.size/2-r/2;default:return n>=u&&n<=c?n:n<u?u:c}}({align:t,cachedBounds:E,containerScrollOffset:s,containerSize:O,index:i,itemCount:f,itemSize:R});if(e){if(l=a({containerElement:e,direction:r,isRtl:h,scrollOffset:l}),"function"!=typeof e.scrollTo){let e=k(l);c(b,e)||w(e)}return l}},S=(0,s.useRef)(()=>{throw Error("Cannot call during render.")}),l(()=>{S.current=v},[v]),(0,s.useCallback)(e=>S.current?.(e),[S])),startIndexOverscan:y,startIndexVisible:j,stopIndexOverscan:C,stopIndexVisible:N}}({containerElement:I,containerStyle:j,defaultContainerSize:r,direction:"vertical",itemCount:v,itemProps:N,itemSize:(0,s.useMemo)(()=>T?e=>S.getRowHeight(e)??S.getAverageRowHeight():S,[T,S]),onResize:m,overscanCount:p});(0,s.useImperativeHandle)(f,()=>({get element(){return I},scrollToRow({align:e="auto",behavior:t="auto",index:s}){let i=E({align:e,containerScrollOffset:I?.scrollTop??0,index:s});"function"==typeof I?.scrollTo&&I.scrollTo({behavior:t,top:i})}}),[I,E]),l(()=>{if(!I)return;let e=Array.from(I.children).filter((e,t)=>{if(e.hasAttribute("aria-hidden"))return!1;let s=`${A+t}`;return e.setAttribute("data-react-window-index",s),!0});if(T)return S.observeRowElements(e)},[I,T,S,A,k]),(0,s.useEffect)(()=>{A>=0&&k>=0&&x&&x({startIndex:M,stopIndex:L},{startIndex:A,stopIndex:k})},[x,A,M,k,L]);let B=(0,s.useMemo)(()=>{let e=[];if(v>0)for(let t=A;t<=k;t++){let i=O(t);e.push((0,s.createElement)(C,{...N,ariaAttributes:{"aria-posinset":t+1,"aria-setsize":v,role:"listitem"},key:t,index:t,style:{position:"absolute",left:0,transform:`translateY(${i.scrollOffset}px)`,height:T?void 0:i.size,width:"100%"}}))}return e},[C,O,T,v,N,A,k]),V=(0,t.jsx)("div",{"aria-hidden":!0,style:{height:R(),width:"100%",zIndex:-1}});return(0,s.createElement)(w,{role:"list",...y,className:i,ref:z,style:{position:"relative",maxHeight:"100%",flexGrow:1,overflowY:"auto",...j}},B,e,V)}s.useState,s.useRef,s.useState,s.useRef;var m=e.i(329),x=e.i(58362),p=e.i(25761),g=e.i(44021),v=e.i(22764);let S=(0,e.i(22436).default)("funnel",[["path",{d:"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z",key:"sc7q7i"}]]);var b=e.i(21079),w=e.i(35893),j=e.i(68497),y=e.i(8402),N=e.i(8737),C=e.i(32137),I=e.i(97705),z=e.i(45878);let T={specs:[],signature:null,scrollTop:0,activeSpecId:null},O=[],R=new Set,E=new Set,A=new Set;function M(){for(let e of R)e()}function k(e){return R.add(e),()=>{R.delete(e)}}function L(){return T}function B(){return(0,s.useSyncExternalStore)(k,L,()=>T)}function V(){let e=s.useCallback(e=>(E.add(e),()=>{E.delete(e)}),[]);return(0,s.useSyncExternalStore)(e,()=>L().specs,()=>O)}function H(){let e=s.useCallback(e=>(A.add(e),()=>{A.delete(e)}),[]);return(0,s.useSyncExternalStore)(e,()=>L().activeSpecId,()=>null)}function P(e){if(0===e.length)return;let t=e.map(e=>[e.id,e.specNumber??"",e.title??"",e.status??"",e.priority??"",e.updatedAt?new Date(e.updatedAt).getTime():0].join(":")).join("|");if(t!==T.signature)for(let s of(T={...T,specs:e,signature:t},M(),E))s()}function $(e){if(T.activeSpecId!==e)for(let t of(T={...T,activeSpecId:e},M(),A))t()}function F(e){1>Math.abs(e-T.scrollTop)||(T={...T,scrollTop:e})}function W(){return T.scrollTop}e.s(["getSidebarScrollTop",()=>W,"primeSpecsSidebar",()=>P,"setActiveSidebarSpec",()=>$,"updateSidebarScrollTop",()=>F,"useSpecsSidebarActiveSpec",()=>H,"useSpecsSidebarSpecs",()=>V,"useSpecsSidebarState",()=>B],22453);let U=s.useLayoutEffect;function q({initialSpecs:e=[],currentSpecId:l,currentSubSpec:n,onSpecHover:r}){let[a,o]=s.useState(""),[c,d]=s.useState("all"),[u,h]=s.useState("all"),[T,O]=s.useState("all"),[R,E]=s.useState(!1),[A,M]=s.useState(()=>"true"===localStorage.getItem("specs-nav-sidebar-collapsed")),[k,L]=s.useState(!1),[B,P]=s.useState(!1),$=s.useRef(null),q=s.useRef(null),D=s.useRef(!1),K=s.useRef(null),Y=s.useRef(0),G=s.useRef(!1),X=s.useRef(!0),J=V(),Q=H(),Z=s.useMemo(()=>J.length>0?J:e,[J,e]),_=l||Q||"";s.useEffect(()=>{P(!0)},[]),s.useEffect(()=>{document.documentElement.style.setProperty("--specs-nav-sidebar-width",A?"0px":"280px"),localStorage.setItem("specs-nav-sidebar-collapsed",String(A))},[A]),s.useEffect(()=>{L(!1)},[_,n]);let ee=s.useMemo(()=>{let e=Z;if(a){let t=a.toLowerCase();e=e.filter(e=>e.title?.toLowerCase().includes(t)||e.specName.toLowerCase().includes(t)||e.specNumber?.toString().includes(t))}return"all"!==c&&(e=e.filter(e=>e.status===c)),"all"!==u&&(e=e.filter(e=>e.priority===u)),"all"!==T&&(e=e.filter(e=>e.tags?.includes(T))),console.debug(e),e},[Z,a,c,u,T]),et=s.useMemo(()=>{let e=new Set;return Z.forEach(t=>{t.tags?.forEach(t=>e.add(t))}),Array.from(e).sort()},[Z]),es="all"!==c||"all"!==u||"all"!==T,ei=s.useMemo(()=>[...ee].sort((e,t)=>(t.specNumber||0)-(e.specNumber||0)),[ee]);U(()=>{let e=null,t=null;Y.current=W(),G.current=Y.current>0;let s=()=>{let i=K.current?.element;if(!i){e=window.requestAnimationFrame(s);return}D.current||(Y.current>0&&(i.scrollTop=Y.current),D.current=!0);let l=()=>{null===q.current&&(q.current=window.requestAnimationFrame(()=>{q.current=null,Y.current=i.scrollTop,F(i.scrollTop)}))};i.addEventListener("scroll",l,{passive:!0}),t=()=>{i.removeEventListener("scroll",l)}};return s(),()=>{t&&t(),null!==e&&window.cancelAnimationFrame(e),null!==q.current&&(window.cancelAnimationFrame(q.current),q.current=null)}},[]),U(()=>{if(!X.current||(X.current=!1,G.current||!_))return;let e=null,t=()=>{if(G.current)return;if(!D.current||!K.current){e=window.requestAnimationFrame(t);return}let s=ei.findIndex(e=>e.id===_);-1!==s&&(G.current=!0,K.current.scrollToRow({index:s,align:"center"}))};return t(),()=>{null!==e&&window.cancelAnimationFrame(e)}},[ei,_]),s.useEffect(()=>(window.toggleSpecsSidebar=()=>L(e=>!e),()=>{window.toggleSpecsSidebar=void 0}),[]);let el=s.useCallback(e=>{let{index:s,style:l}=e,a=ei[s],o=a.id===_,c=(a.contentMd?(0,C.extractH1Title)(a.contentMd):null)||a.title||a.specName;return(0,t.jsx)("div",{style:l,className:"px-1",children:(0,t.jsx)("div",{className:"mb-0.5",children:(0,t.jsx)("div",{className:"flex items-center gap-0.5",children:(0,t.jsxs)(y.Tooltip,{children:[(0,t.jsx)(y.TooltipTrigger,{asChild:!0,children:(0,t.jsxs)(i.default,{ref:o&&!n?$:null,href:`/specs/${a.specNumber||a.id}`,onMouseEnter:()=>r?.(a.specNumber?.toString()||a.id),className:(0,C.cn)("w-full flex flex-col gap-1 p-1.5 rounded-md text-sm transition-colors",o?"bg-accent text-accent-foreground font-medium":"hover:bg-accent/50"),children:[(0,t.jsxs)("div",{className:"flex items-center gap-1.5",children:[a.specNumber&&(0,t.jsxs)("span",{className:"text-xs font-mono text-muted-foreground shrink-0",children:["#",a.specNumber.toString().padStart(3,"0")]}),(0,t.jsx)("span",{className:"truncate text-xs leading-relaxed",children:c})]}),(0,t.jsxs)("div",{className:"flex items-center gap-1.5 flex-wrap",children:[a.status&&(0,t.jsxs)(y.Tooltip,{children:[(0,t.jsx)(y.TooltipTrigger,{asChild:!0,children:(0,t.jsx)("div",{children:(0,t.jsx)(j.StatusBadge,{status:a.status,iconOnly:!0,className:"text-[10px] scale-90"})})}),(0,t.jsx)(y.TooltipContent,{side:"right",children:(0,j.getStatusLabel)(a.status)})]}),a.priority&&(0,t.jsxs)(y.Tooltip,{children:[(0,t.jsx)(y.TooltipTrigger,{asChild:!0,children:(0,t.jsx)("div",{children:(0,t.jsx)(I.PriorityBadge,{priority:a.priority,iconOnly:!0,className:"text-[10px] scale-90"})})}),(0,t.jsx)(y.TooltipContent,{side:"right",children:(0,I.getPriorityLabel)(a.priority)})]}),"number"==typeof a.subSpecsCount&&a.subSpecsCount>0&&(0,t.jsxs)("span",{className:"text-[10px] text-muted-foreground",children:["+",a.subSpecsCount," files"]}),a.updatedAt&&(0,t.jsx)("span",{className:"text-[10px] text-muted-foreground",children:(0,z.formatRelativeTime)(a.updatedAt)})]})]})}),(0,t.jsx)(y.TooltipContent,{side:"right",className:"max-w-[300px]",children:(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)("div",{className:"font-semibold",children:c}),(0,t.jsx)("div",{className:"text-xs text-muted-foreground",children:a.specName})]})})]})})})})},[ei,_,n,r]),en=s.useMemo(()=>window.innerHeight-56-180,[]),er=s.useMemo(()=>s.memo(f),[]);return(0,t.jsxs)(y.TooltipProvider,{delayDuration:700,children:[k&&(0,t.jsx)("div",{className:"fixed inset-0 bg-black/50 z-40 lg:hidden",onClick:()=>L(!1)}),(0,t.jsxs)("div",{className:"relative flex-shrink-0",children:[(0,t.jsxs)("aside",{className:(0,C.cn)("sticky top-14 h-[calc(100vh-3.5rem)] border-r border-border bg-background flex flex-col overflow-hidden transition-all duration-300","hidden lg:flex",B&&A?"lg:w-0 lg:border-r-0":"lg:w-[280px]",k&&"fixed left-0 top-14 z-50 flex w-[280px]"),children:[(0,t.jsxs)("div",{className:"p-4 border-b border-border",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,t.jsx)("h2",{className:"font-semibold text-sm",children:"Specifications"}),(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsxs)(y.Tooltip,{children:[(0,t.jsx)(y.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(w.Button,{variant:R||es?"default":"ghost",size:"sm",onClick:()=>E(!R),className:"h-6 w-6 p-0",children:(0,t.jsx)(S,{className:"h-4 w-4"})})}),(0,t.jsx)(y.TooltipContent,{side:"bottom",children:R?"Hide filters":"Show filters"})]}),(0,t.jsx)(w.Button,{variant:"ghost",size:"sm",onClick:()=>L(!1),className:"h-6 w-6 p-0 lg:hidden",children:(0,t.jsx)(g.X,{className:"h-4 w-4"})}),(0,t.jsx)(w.Button,{variant:"ghost",size:"sm",onClick:()=>M(!0),className:"h-6 w-6 p-0 hidden lg:flex lg:items-center lg:justify-center",children:(0,t.jsx)(x.ChevronLeft,{className:"h-4 w-4"})})]})]}),R&&(0,t.jsxs)("div",{className:"space-y-2 mb-3 pb-3 border-b border-border",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-muted-foreground",children:"Filters"}),es&&(0,t.jsx)(w.Button,{variant:"ghost",size:"sm",onClick:()=>{d("all"),h("all"),O("all")},className:"h-5 text-xs px-2 py-0",children:"Clear"})]}),(0,t.jsxs)(N.Select,{value:c,onValueChange:d,children:[(0,t.jsx)(N.SelectTrigger,{className:"h-8 text-xs",children:(0,t.jsx)(N.SelectValue,{placeholder:"Status"})}),(0,t.jsxs)(N.SelectContent,{children:[(0,t.jsx)(N.SelectItem,{value:"all",children:"All Status"}),(0,t.jsx)(N.SelectItem,{value:"planned",children:"Planned"}),(0,t.jsx)(N.SelectItem,{value:"in-progress",children:"In Progress"}),(0,t.jsx)(N.SelectItem,{value:"complete",children:"Complete"}),(0,t.jsx)(N.SelectItem,{value:"archived",children:"Archived"})]})]}),(0,t.jsxs)(N.Select,{value:u,onValueChange:h,children:[(0,t.jsx)(N.SelectTrigger,{className:"h-8 text-xs",children:(0,t.jsx)(N.SelectValue,{placeholder:"Priority"})}),(0,t.jsxs)(N.SelectContent,{children:[(0,t.jsx)(N.SelectItem,{value:"all",children:"All Priority"}),(0,t.jsx)(N.SelectItem,{value:"low",children:"Low"}),(0,t.jsx)(N.SelectItem,{value:"medium",children:"Medium"}),(0,t.jsx)(N.SelectItem,{value:"high",children:"High"}),(0,t.jsx)(N.SelectItem,{value:"critical",children:"Critical"})]})]}),et.length>0&&(0,t.jsxs)(N.Select,{value:T,onValueChange:O,children:[(0,t.jsx)(N.SelectTrigger,{className:"h-8 text-xs",children:(0,t.jsx)(N.SelectValue,{placeholder:"Tag"})}),(0,t.jsxs)(N.SelectContent,{children:[(0,t.jsx)(N.SelectItem,{value:"all",children:"All Tags"}),et.map(e=>(0,t.jsx)(N.SelectItem,{value:e,children:e},e))]})]})]}),(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)(m.Search,{className:"absolute left-2 top-2.5 h-4 w-4 text-muted-foreground"}),(0,t.jsx)(b.Input,{placeholder:"Search specs...",value:a,onChange:e=>o(e.target.value),className:"pl-8 h-9 border-border"})]})]}),(0,t.jsx)("div",{className:"flex-1 overflow-hidden",children:0===ei.length?(0,t.jsx)("div",{className:"text-center py-8 text-sm text-muted-foreground",children:"No specs found"}):(0,t.jsx)(er,{listRef:K,defaultHeight:en,rowCount:ei.length,rowHeight:72,overscanCount:5,rowComponent:el,rowProps:{}})})]}),B&&A&&(0,t.jsx)(w.Button,{variant:"ghost",size:"sm",onClick:()=>M(!1),className:"hidden lg:items-center lg:justify-center lg:flex h-6 w-6 p-0 fixed z-50 top-20 -translate-y-1 -translate-x-1/2 left-[calc(var(--main-sidebar-width,240px))] bg-background border",children:(0,t.jsx)(p.ChevronRight,{className:"h-4 w-4"})}),(0,t.jsx)(w.Button,{onClick:()=>L(!0),size:"icon",className:"lg:hidden fixed bottom-6 left-6 h-12 w-12 rounded-full shadow-lg z-40 hover:scale-110 transition-transform","aria-label":"Show specifications list",children:(0,t.jsx)(v.List,{className:"h-5 w-5"})})]})]})}e.s(["SpecsNavSidebar",()=>q],17612)},53213,e=>{"use strict";var t=e.i(90022),s=e.i(17612),i=e.i(32137);function l({className:e,...s}){return(0,t.jsx)("div",{className:(0,i.cn)("animate-pulse rounded-md bg-muted",e),...s})}var n=e.i(22453);function r(){let e=(0,n.useSpecsSidebarState)(),i=e.specs,r=e.activeSpecId||"";return(0,t.jsxs)("div",{className:"flex min-h-[calc(100vh-3.5rem)] w-full min-w-0",children:[(0,t.jsx)(s.SpecsNavSidebar,{initialSpecs:i,currentSpecId:r}),(0,t.jsx)("div",{className:"flex-1 min-w-0 px-4 py-6 sm:px-8 sm:py-10",children:(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(l,{className:"h-7 w-56"}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-3",children:[(0,t.jsx)(l,{className:"h-6 w-24"}),(0,t.jsx)(l,{className:"h-6 w-24"}),(0,t.jsx)(l,{className:"h-6 w-20"})]}),(0,t.jsx)(l,{className:"h-4 w-64"})]}),(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(l,{className:"h-5 w-40"}),(0,t.jsx)(l,{className:"h-32 w-full"})]}),(0,t.jsx)("div",{className:"space-y-4",children:[...Array(6)].map((e,s)=>(0,t.jsx)(l,{className:"h-4 w-full"},s))})]})})]})}e.s(["SpecDetailLoadingShell",()=>r],53213)}]);
@@ -0,0 +1,3 @@
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/b760a3a9c2c8be28.js","static/chunks/ebd89051637b9a47.js","static/chunks/7f732ea69e643219.js","static/chunks/f3ec9fd77a8618b1.js","static/chunks/5c2072ad938de8ed.js"],runtimeModuleIds:[79757]}]),(()=>{let e;if(!Array.isArray(globalThis.TURBOPACK))return;let t="/_next/",r=new WeakMap;function n(e,t){this.m=e,this.e=t}let o=n.prototype,l=Object.prototype.hasOwnProperty,i="undefined"!=typeof Symbol&&Symbol.toStringTag;function s(e,t,r){l.call(e,t)||Object.defineProperty(e,t,r)}function u(e,t){let r=e[t];return r||(r=a(t),e[t]=r),r}function a(e){return{exports:{},error:void 0,id:e,namespaceObject:void 0}}function c(e,t){s(e,"__esModule",{value:!0}),i&&s(e,i,{value:"Module"});let r=0;for(;r<t.length;){let n=t[r++],o=t[r++];if("number"==typeof o)if(0===o)s(e,n,{value:t[r++],enumerable:!0,writable:!1});else throw Error(`unexpected tag: ${o}`);else"function"==typeof t[r]?s(e,n,{get:o,set:t[r++],enumerable:!0}):s(e,n,{get:o,enumerable:!0})}Object.seal(e)}o.s=function(e,t){let r,n;null!=t?n=(r=u(this.c,t)).exports:(r=this.m,n=this.e),r.namespaceObject=n,c(n,e)},o.j=function(e,t){var n,o;let i,s,a;null!=t?s=(i=u(this.c,t)).exports:(i=this.m,s=this.e);let c=(n=i,o=s,(a=r.get(n))||(r.set(n,a=[]),n.exports=n.namespaceObject=new Proxy(o,{get(e,t){if(l.call(e,t)||"default"===t||"__esModule"===t)return Reflect.get(e,t);for(let e of a){let r=Reflect.get(e,t);if(void 0!==r)return r}},ownKeys(e){let t=Reflect.ownKeys(e);for(let e of a)for(let r of Reflect.ownKeys(e))"default"===r||t.includes(r)||t.push(r);return t}})),a);"object"==typeof e&&null!==e&&c.push(e)},o.v=function(e,t){(null!=t?u(this.c,t):this.m).exports=e},o.n=function(e,t){let r;(r=null!=t?u(this.c,t):this.m).exports=r.namespaceObject=e};let f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,p=[null,f({}),f([]),f(f)];function h(e,t,r){let n=[],o=-1;for(let t=e;("object"==typeof t||"function"==typeof t)&&!p.includes(t);t=f(t))for(let r of Object.getOwnPropertyNames(t))n.push(r,function(e,t){return()=>e[t]}(e,r)),-1===o&&"default"===r&&(o=n.length-1);return r&&o>=0||(o>=0?n.splice(o,1,0,e):n.push("default",0,e)),c(t,n),t}function d(e){let t=N(e,this.m);if(t.namespaceObject)return t.namespaceObject;let r=t.exports;return t.namespaceObject=h(r,"function"==typeof r?function(...e){return r.apply(this,e)}:Object.create(null),r&&r.__esModule)}function m(){let e,t;return{promise:new Promise((r,n)=>{t=n,e=r}),resolve:e,reject:t}}o.i=d,o.A=function(e){return this.r(e)(d.bind(this))},o.t="function"==typeof require?require:function(){throw Error("Unexpected use of runtime require")},o.r=function(e){return N(e,this.m).exports},o.f=function(e){function t(t){if(l.call(e,t))return e[t].module();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r}return t.keys=()=>Object.keys(e),t.resolve=t=>{if(l.call(e,t))return e[t].id();let r=Error(`Cannot find module '${t}'`);throw r.code="MODULE_NOT_FOUND",r},t.import=async e=>await t(e),t};let b=Symbol("turbopack queues"),y=Symbol("turbopack exports"),O=Symbol("turbopack error");function g(e){e&&1!==e.status&&(e.status=1,e.forEach(e=>e.queueCount--),e.forEach(e=>e.queueCount--?e.queueCount++:e()))}o.a=function(e,t){let r=this.m,n=t?Object.assign([],{status:-1}):void 0,o=new Set,{resolve:l,reject:i,promise:s}=m(),u=Object.assign(s,{[y]:r.exports,[b]:e=>{n&&e(n),o.forEach(e),u.catch(()=>{})}}),a={get:()=>u,set(e){e!==u&&(u[y]=e)}};Object.defineProperty(r,"exports",a),Object.defineProperty(r,"namespaceObject",a),e(function(e){let t=e.map(e=>{if(null!==e&&"object"==typeof e){if(b in e)return e;if(null!=e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then){let t=Object.assign([],{status:0}),r={[y]:{},[b]:e=>e(t)};return e.then(e=>{r[y]=e,g(t)},e=>{r[O]=e,g(t)}),r}}return{[y]:e,[b]:()=>{}}}),r=()=>t.map(e=>{if(e[O])throw e[O];return e[y]}),{promise:l,resolve:i}=m(),s=Object.assign(()=>i(r),{queueCount:0});function u(e){e!==n&&!o.has(e)&&(o.add(e),e&&0===e.status&&(s.queueCount++,e.push(s)))}return t.map(e=>e[b](u)),s.queueCount?l:r()},function(e){e?i(u[O]=e):l(u[y]),g(n)}),n&&-1===n.status&&(n.status=0)};let w=function(e){let t=new URL(e,"x:/"),r={};for(let e in t)r[e]=t[e];for(let t in r.href=e,r.pathname=e.replace(/[?#].*/,""),r.origin=r.protocol="",r.toString=r.toJSON=(...t)=>e,r)Object.defineProperty(this,t,{enumerable:!0,configurable:!0,value:r[t]})};function j(e,t){throw Error(`Invariant: ${t(e)}`)}w.prototype=URL.prototype,o.U=w,o.z=function(e){throw Error("dynamic usage of require is not supported")},o.g=globalThis;let R=n.prototype;var C,U=((C=U||{})[C.Runtime=0]="Runtime",C[C.Parent=1]="Parent",C[C.Update=2]="Update",C);let k=new Map;o.M=k;let v=new Map,_=new Map;async function P(e,t,r){let n;if("string"==typeof r)return A(e,t,S(r));let o=r.included||[],l=o.map(e=>!!k.has(e)||v.get(e));if(l.length>0&&l.every(e=>e))return void await Promise.all(l);let i=r.moduleChunks||[],s=i.map(e=>_.get(e)).filter(e=>e);if(s.length>0){if(s.length===i.length)return void await Promise.all(s);let r=new Set;for(let e of i)_.has(e)||r.add(e);for(let n of r){let r=A(e,t,S(n));_.set(n,r),s.push(r)}n=Promise.all(s)}else{for(let o of(n=A(e,t,S(r.path)),i))_.has(o)||_.set(o,n)}for(let e of o)v.has(e)||v.set(e,n);await n}R.l=function(e){return P(1,this.m.id,e)};let $=Promise.resolve(void 0),T=new WeakMap;function A(t,r,n){let o=e.loadChunkCached(t,n),l=T.get(o);if(void 0===l){let e=T.set.bind(T,o,$);l=o.then(e).catch(e=>{let o;switch(t){case 0:o=`as a runtime dependency of chunk ${r}`;break;case 1:o=`from module ${r}`;break;case 2:o="from an HMR update";break;default:j(t,e=>`Unknown source type: ${e}`)}throw Error(`Failed to load chunk ${n} ${o}${e?`: ${e}`:""}`,e?{cause:e}:void 0)}),T.set(o,l)}return l}function S(e){return`${t}${e.split("/").map(e=>encodeURIComponent(e)).join("/")}`}R.L=function(e){return A(1,this.m.id,e)},R.R=function(e){let t=this.r(e);return t?.default??t},R.P=function(e){return`/ROOT/${e??""}`},R.b=function(e){let t=new Blob([`self.TURBOPACK_WORKER_LOCATION = ${JSON.stringify(location.origin)};
2
+ self.TURBOPACK_NEXT_CHUNK_URLS = ${JSON.stringify(e.reverse().map(S),null,2)};
3
+ importScripts(...self.TURBOPACK_NEXT_CHUNK_URLS.map(c => self.TURBOPACK_WORKER_LOCATION + c).reverse());`],{type:"text/javascript"});return URL.createObjectURL(t)};let E=/\.js(?:\?[^#]*)?(?:#.*)?$/,K=/\.css(?:\?[^#]*)?(?:#.*)?$/;function x(e){return K.test(e)}o.w=function(t,r,n){return e.loadWebAssembly(1,this.m.id,t,r,n)},o.u=function(t,r){return e.loadWebAssemblyModule(1,this.m.id,t,r)};let M={};o.c=M;let N=(e,t)=>{let r=M[e];if(r){if(r.error)throw r.error;return r}return L(e,U.Parent,t.id)};function L(e,t,r){let o=k.get(e);if("function"!=typeof o)throw Error(function(e,t,r){let n;switch(t){case 0:n=`as a runtime entry of chunk ${r}`;break;case 1:n=`because it was required from module ${r}`;break;case 2:n="because of an HMR update";break;default:j(t,e=>`Unknown source type: ${e}`)}return`Module ${e} was instantiated ${n}, but the module factory is not available.`}(e,t,r));let l=a(e),i=l.exports;M[e]=l;let s=new n(l,i);try{o(s,l,i)}catch(e){throw l.error=e,e}return l.namespaceObject&&l.exports!==l.namespaceObject&&h(l.exports,l.namespaceObject),l}function q(r){let n,o=function(e){if("string"==typeof e)return e;let r=decodeURIComponent(("undefined"!=typeof TURBOPACK_NEXT_CHUNK_URLS?TURBOPACK_NEXT_CHUNK_URLS.pop():e.getAttribute("src")).replace(/[?#].*$/,""));return r.startsWith(t)?r.slice(t.length):r}(r[0]);return 2===r.length?n=r[1]:(n=void 0,!function(e,t,r,n){let o=1;for(;o<e.length;){let t=e[o],n=o+1;for(;n<e.length&&"function"!=typeof e[n];)n++;if(n===e.length)throw Error("malformed chunk format, expected a factory function");if(!r.has(t)){let l=e[n];for(Object.defineProperty(l,"name",{value:"module evaluation"});o<n;o++)t=e[o],r.set(t,l)}o=n+1}}(r,0,k)),e.registerChunk(o,n)}let B=new Map;function W(e){let t=B.get(e);if(!t){let r,n;t={resolved:!1,loadingStarted:!1,promise:new Promise((e,t)=>{r=e,n=t}),resolve:()=>{t.resolved=!0,r()},reject:n},B.set(e,t)}return t}e={async registerChunk(e,t){if(W(S(e)).resolve(),null!=t){for(let e of t.otherChunks)W(S("string"==typeof e?e:e.path));if(await Promise.all(t.otherChunks.map(t=>P(0,e,t))),t.runtimeModuleIds.length>0)for(let r of t.runtimeModuleIds)!function(e,t){let r=M[t];if(r){if(r.error)throw r.error;return}L(t,U.Runtime,e)}(e,r)}},loadChunkCached:(e,t)=>(function(e,t){let r=W(t);if(r.loadingStarted)return r.promise;if(e===U.Runtime)return r.loadingStarted=!0,x(t)&&r.resolve(),r.promise;if("function"==typeof importScripts)if(x(t));else if(E.test(t))self.TURBOPACK_NEXT_CHUNK_URLS.push(t),importScripts(TURBOPACK_WORKER_LOCATION+t);else throw Error(`can't infer type of chunk from URL ${t} in worker`);else{let e=decodeURI(t);if(x(t))if(document.querySelectorAll(`link[rel=stylesheet][href="${t}"],link[rel=stylesheet][href^="${t}?"],link[rel=stylesheet][href="${e}"],link[rel=stylesheet][href^="${e}?"]`).length>0)r.resolve();else{let e=document.createElement("link");e.rel="stylesheet",e.href=t,e.onerror=()=>{r.reject()},e.onload=()=>{r.resolve()},document.head.appendChild(e)}else if(E.test(t)){let n=document.querySelectorAll(`script[src="${t}"],script[src^="${t}?"],script[src="${e}"],script[src^="${e}?"]`);if(n.length>0)for(let e of Array.from(n))e.addEventListener("error",()=>{r.reject()});else{let e=document.createElement("script");e.src=t,e.onerror=()=>{r.reject()},document.head.appendChild(e)}}else throw Error(`can't infer type of chunk from URL ${t}`)}return r.loadingStarted=!0,r.promise})(e,t),async loadWebAssembly(e,t,r,n,o){let l=fetch(S(r)),{instance:i}=await WebAssembly.instantiateStreaming(l,o);return i.exports},async loadWebAssemblyModule(e,t,r,n){let o=fetch(S(r));return await WebAssembly.compileStreaming(o)}};let I=globalThis.TURBOPACK;globalThis.TURBOPACK={push:q},I.forEach(q)})();
@@ -17,6 +17,7 @@ program
17
17
  .option('-s, --specs <dir>', 'Specs directory (auto-detected if omitted)')
18
18
  .option('-p, --port <port>', 'Port to run on', '3000')
19
19
  .option('--no-open', "Don't open the browser automatically")
20
+ .option('--multi-project', 'Enable multi-project mode')
20
21
  .option('--dry-run', 'Show what would run without executing')
21
22
  .action(async (options) => {
22
23
  try {
@@ -33,15 +34,24 @@ program.parseAsync(process.argv);
33
34
  async function startUi(options) {
34
35
  const cwd = process.cwd();
35
36
  const port = validatePort(options.port);
36
- const specsDir = resolveSpecsDirectory(cwd, options.specs);
37
+
38
+ let specsDir = '';
39
+ let specsMode = 'filesystem';
40
+
41
+ if (options.multiProject) {
42
+ specsMode = 'multi-project';
43
+ } else {
44
+ specsDir = resolveSpecsDirectory(cwd, options.specs);
45
+ }
46
+
37
47
  const serverPath = getServerPath();
38
48
 
39
49
  if (options.dryRun) {
40
- printDryRun({ port, specsDir, serverPath, openBrowser: options.open });
50
+ printDryRun({ port, specsDir, specsMode, serverPath, openBrowser: options.open });
41
51
  return;
42
52
  }
43
53
 
44
- await launchServer({ port, specsDir, serverPath, openBrowser: options.open });
54
+ await launchServer({ port, specsDir, specsMode, serverPath, openBrowser: options.open });
45
55
  }
46
56
 
47
57
  function validatePort(value) {
@@ -134,22 +144,22 @@ function getServerPath() {
134
144
  throw new Error('LeanSpec UI build not found. Reinstall @leanspec/ui or run pnpm --filter @leanspec/ui build.');
135
145
  }
136
146
 
137
- function printDryRun({ port, specsDir, serverPath, openBrowser }) {
147
+ function printDryRun({ port, specsDir, specsMode, serverPath, openBrowser }) {
138
148
  console.log(chalk.cyan('Would run:'));
139
- console.log(chalk.dim(` SPECS_MODE=filesystem SPECS_DIR=${specsDir} PORT=${port} node ${serverPath}`));
149
+ console.log(chalk.dim(` SPECS_MODE=${specsMode} SPECS_DIR=${specsDir} PORT=${port} node ${serverPath}`));
140
150
  if (openBrowser) {
141
151
  console.log(chalk.dim(` open http://localhost:${port}`));
142
152
  }
143
153
  }
144
154
 
145
- async function launchServer({ port, specsDir, serverPath, openBrowser }) {
155
+ async function launchServer({ port, specsDir, specsMode, serverPath, openBrowser }) {
146
156
  const spinner = ora('Starting LeanSpec UI...').start();
147
157
  const serverDir = dirname(serverPath);
148
158
  const env = {
149
159
  ...process.env,
150
160
  NODE_ENV: 'production',
151
161
  NEXT_TELEMETRY_DISABLED: '1',
152
- SPECS_MODE: 'filesystem',
162
+ SPECS_MODE: specsMode,
153
163
  SPECS_DIR: specsDir,
154
164
  PORT: port,
155
165
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanspec/ui",
3
- "version": "0.2.5-dev.20251120070726",
3
+ "version": "0.2.5-dev.20251120093243",
4
4
  "description": "LeanSpec web UI launcher for visual spec management",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,6 +57,7 @@
57
57
  "@radix-ui/react-avatar": "^1.1.11",
58
58
  "@radix-ui/react-dialog": "^1.1.15",
59
59
  "@radix-ui/react-dropdown-menu": "^2.1.16",
60
+ "@radix-ui/react-popover": "^1.1.15",
60
61
  "@radix-ui/react-progress": "^1.1.8",
61
62
  "@radix-ui/react-select": "^2.1.14",
62
63
  "@radix-ui/react-separator": "^1.1.8",
@@ -101,6 +102,7 @@
101
102
  "@leanspec/core": "workspace:*",
102
103
  "@tailwindcss/typography": "^0.5.15",
103
104
  "@types/better-sqlite3": "^7.6.12",
105
+ "@types/js-yaml": "^4.0.9",
104
106
  "@types/mdast": "^4.0.4",
105
107
  "@types/node": "^20",
106
108
  "@types/react": "^19",
@@ -0,0 +1,117 @@
1
+ /**
2
+ * API Routes for individual project management
3
+ *
4
+ * GET /api/local-projects/[id] - Get project details
5
+ * PATCH /api/local-projects/[id] - Update project
6
+ * DELETE /api/local-projects/[id] - Remove project
7
+ */
8
+
9
+ import { NextRequest, NextResponse } from 'next/server';
10
+ import { projectRegistry } from '@/lib/projects';
11
+
12
+ interface RouteContext {
13
+ params: Promise<{ id: string }>;
14
+ }
15
+
16
+ /**
17
+ * GET /api/local-projects/[id]
18
+ * Get project details and touch lastAccessed
19
+ */
20
+ export async function GET(
21
+ request: NextRequest,
22
+ context: RouteContext
23
+ ) {
24
+ try {
25
+ const { id } = await context.params;
26
+
27
+ const project = await projectRegistry.getProject(id);
28
+ if (!project) {
29
+ return NextResponse.json(
30
+ { error: 'Project not found' },
31
+ { status: 404 }
32
+ );
33
+ }
34
+
35
+ // Touch project to update lastAccessed
36
+ await projectRegistry.touchProject(id);
37
+
38
+ return NextResponse.json({ project });
39
+ } catch (error: any) {
40
+ console.error('Error fetching project:', error);
41
+ return NextResponse.json(
42
+ { error: 'Failed to fetch project', details: error.message },
43
+ { status: 500 }
44
+ );
45
+ }
46
+ }
47
+
48
+ /**
49
+ * PATCH /api/local-projects/[id]
50
+ * Update project metadata
51
+ *
52
+ * Body: { name?: string, color?: string, description?: string, favorite?: boolean }
53
+ */
54
+ export async function PATCH(
55
+ request: NextRequest,
56
+ context: RouteContext
57
+ ) {
58
+ try {
59
+ const { id } = await context.params;
60
+ const body = await request.json();
61
+
62
+ // Handle favorite toggle separately
63
+ if ('favorite' in body && Object.keys(body).length === 1) {
64
+ const favorite = await projectRegistry.toggleFavorite(id);
65
+ const project = await projectRegistry.getProject(id);
66
+ return NextResponse.json({ project, favorite });
67
+ }
68
+
69
+ const { name, color, description } = body;
70
+ const updates: any = {};
71
+
72
+ if (name !== undefined) updates.name = name;
73
+ if (color !== undefined) updates.color = color;
74
+ if (description !== undefined) updates.description = description;
75
+
76
+ const project = await projectRegistry.updateProject(id, updates);
77
+
78
+ return NextResponse.json({ project });
79
+ } catch (error: any) {
80
+ console.error('Error updating project:', error);
81
+
82
+ if (error.message === 'Project not found') {
83
+ return NextResponse.json(
84
+ { error: 'Project not found' },
85
+ { status: 404 }
86
+ );
87
+ }
88
+
89
+ return NextResponse.json(
90
+ { error: 'Failed to update project', details: error.message },
91
+ { status: 500 }
92
+ );
93
+ }
94
+ }
95
+
96
+ /**
97
+ * DELETE /api/local-projects/[id]
98
+ * Remove project from registry (doesn't delete files)
99
+ */
100
+ export async function DELETE(
101
+ request: NextRequest,
102
+ context: RouteContext
103
+ ) {
104
+ try {
105
+ const { id } = await context.params;
106
+
107
+ await projectRegistry.removeProject(id);
108
+
109
+ return NextResponse.json({ success: true });
110
+ } catch (error: any) {
111
+ console.error('Error removing project:', error);
112
+ return NextResponse.json(
113
+ { error: 'Failed to remove project', details: error.message },
114
+ { status: 500 }
115
+ );
116
+ }
117
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * API Route for project discovery
3
+ *
4
+ * POST /api/local-projects/discover - Discover projects in a directory
5
+ */
6
+
7
+ import { NextRequest, NextResponse } from 'next/server';
8
+ import { projectRegistry } from '@/lib/projects';
9
+
10
+ /**
11
+ * POST /api/local-projects/discover
12
+ * Discover LeanSpec projects in a directory tree
13
+ *
14
+ * Body: { path: string, maxDepth?: number }
15
+ */
16
+ export async function POST(request: NextRequest) {
17
+ try {
18
+ const body = await request.json();
19
+ const { path, maxDepth = 3 } = body;
20
+
21
+ if (!path || typeof path !== 'string') {
22
+ return NextResponse.json(
23
+ { error: 'Invalid request: path is required' },
24
+ { status: 400 }
25
+ );
26
+ }
27
+
28
+ const discovered = await projectRegistry.discoverProjects(path, maxDepth);
29
+
30
+ return NextResponse.json({
31
+ discovered,
32
+ count: discovered.length,
33
+ });
34
+ } catch (error: any) {
35
+ console.error('Error discovering projects:', error);
36
+ return NextResponse.json(
37
+ { error: 'Failed to discover projects', details: error.message },
38
+ { status: 500 }
39
+ );
40
+ }
41
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * API Route for listing directory contents
3
+ *
4
+ * POST /api/local-projects/list-directory - List directories in a path
5
+ */
6
+
7
+ import { NextRequest, NextResponse } from 'next/server';
8
+ import { projectRegistry } from '@/lib/projects';
9
+ import { homedir } from 'node:os';
10
+
11
+ /**
12
+ * POST /api/local-projects/list-directory
13
+ * List directories in a given path
14
+ *
15
+ * Body: { path?: string }
16
+ */
17
+ export async function POST(request: NextRequest) {
18
+ try {
19
+ const body = await request.json();
20
+ const { path } = body;
21
+
22
+ // Use CWD if path is not provided, falling back to homedir
23
+ const targetPath = path || process.cwd() || homedir();
24
+
25
+ const items = await projectRegistry.listDirectory(targetPath);
26
+
27
+ return NextResponse.json({
28
+ path: targetPath,
29
+ items,
30
+ });
31
+ } catch (error: any) {
32
+ console.error('Error listing directory:', error);
33
+ return NextResponse.json(
34
+ { error: 'Failed to list directory', details: error.message },
35
+ { status: 500 }
36
+ );
37
+ }
38
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * API Routes for local project management
3
+ *
4
+ * GET /api/local-projects - List all local projects
5
+ * POST /api/local-projects - Add a new project
6
+ */
7
+
8
+ import { NextRequest, NextResponse } from 'next/server';
9
+ import { projectRegistry } from '@/lib/projects';
10
+
11
+ /**
12
+ * GET /api/local-projects
13
+ * Returns all registered local projects
14
+ */
15
+ export async function GET() {
16
+ try {
17
+ const projects = await projectRegistry.getProjects();
18
+ const recentProjects = await projectRegistry.getRecentProjects();
19
+ const favoriteProjects = await projectRegistry.getFavoriteProjects();
20
+
21
+ return NextResponse.json({
22
+ projects,
23
+ recentProjects,
24
+ favoriteProjects,
25
+ });
26
+ } catch (error: any) {
27
+ console.error('Error fetching local projects:', error);
28
+ return NextResponse.json(
29
+ { error: 'Failed to fetch local projects', details: error.message },
30
+ { status: 500 }
31
+ );
32
+ }
33
+ }
34
+
35
+ /**
36
+ * POST /api/local-projects
37
+ * Add a new project to the registry
38
+ *
39
+ * Body: { path: string, favorite?: boolean, color?: string }
40
+ */
41
+ export async function POST(request: NextRequest) {
42
+ try {
43
+ const body = await request.json();
44
+ const { path, favorite, color } = body;
45
+
46
+ if (!path || typeof path !== 'string') {
47
+ return NextResponse.json(
48
+ { error: 'Invalid request: path is required' },
49
+ { status: 400 }
50
+ );
51
+ }
52
+
53
+ const project = await projectRegistry.addProject(path, { favorite, color });
54
+
55
+ return NextResponse.json({ project }, { status: 201 });
56
+ } catch (error: any) {
57
+ console.error('Error adding project:', error);
58
+ return NextResponse.json(
59
+ { error: 'Failed to add project', details: error.message },
60
+ { status: 500 }
61
+ );
62
+ }
63
+ }
@@ -0,0 +1,97 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { getProjectById } from '@/lib/db/queries';
3
+ import { projectRegistry } from '@/lib/projects/registry';
4
+
5
+ export async function GET(
6
+ request: Request,
7
+ { params }: { params: Promise<{ id: string }> }
8
+ ) {
9
+ try {
10
+ const { id } = await params;
11
+
12
+ if (process.env.SPECS_MODE === 'multi-project') {
13
+ const project = await projectRegistry.getProject(id);
14
+ if (!project) {
15
+ return NextResponse.json(
16
+ { error: 'Project not found' },
17
+ { status: 404 }
18
+ );
19
+ }
20
+ // Touch project to update lastAccessed
21
+ await projectRegistry.touchProject(id);
22
+ return NextResponse.json({ project });
23
+ }
24
+
25
+ const project = await getProjectById(id);
26
+ if (!project) {
27
+ return NextResponse.json(
28
+ { error: 'Project not found' },
29
+ { status: 404 }
30
+ );
31
+ }
32
+ return NextResponse.json({ project });
33
+ } catch (error) {
34
+ console.error('Error fetching project:', error);
35
+ return NextResponse.json(
36
+ { error: 'Failed to fetch project' },
37
+ { status: 500 }
38
+ );
39
+ }
40
+ }
41
+
42
+ export async function DELETE(
43
+ request: Request,
44
+ { params }: { params: Promise<{ id: string }> }
45
+ ) {
46
+ try {
47
+ if (process.env.SPECS_MODE !== 'multi-project') {
48
+ return NextResponse.json(
49
+ { error: 'Multi-project mode is not enabled' },
50
+ { status: 400 }
51
+ );
52
+ }
53
+
54
+ const { id } = await params;
55
+ await projectRegistry.removeProject(id);
56
+ return NextResponse.json({ success: true });
57
+ } catch (error) {
58
+ console.error('Error deleting project:', error);
59
+ return NextResponse.json(
60
+ { error: 'Failed to delete project' },
61
+ { status: 500 }
62
+ );
63
+ }
64
+ }
65
+
66
+ export async function PATCH(
67
+ request: Request,
68
+ { params }: { params: Promise<{ id: string }> }
69
+ ) {
70
+ try {
71
+ if (process.env.SPECS_MODE !== 'multi-project') {
72
+ return NextResponse.json(
73
+ { error: 'Multi-project mode is not enabled' },
74
+ { status: 400 }
75
+ );
76
+ }
77
+
78
+ const { id } = await params;
79
+ const body = await request.json();
80
+
81
+ // Handle favorite toggle separately
82
+ if ('favorite' in body) {
83
+ const favorite = await projectRegistry.toggleFavorite(id);
84
+ const project = await projectRegistry.getProject(id);
85
+ return NextResponse.json({ project, favorite });
86
+ }
87
+
88
+ const project = await projectRegistry.updateProject(id, body);
89
+ return NextResponse.json({ project });
90
+ } catch (error) {
91
+ console.error('Error updating project:', error);
92
+ return NextResponse.json(
93
+ { error: 'Failed to update project' },
94
+ { status: 500 }
95
+ );
96
+ }
97
+ }
@@ -0,0 +1,38 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { getSpecById } from '@/lib/db/queries';
3
+ import { specsService } from '@/lib/specs/service';
4
+
5
+ export async function GET(
6
+ request: Request,
7
+ { params }: { params: Promise<{ id: string; spec: string }> }
8
+ ) {
9
+ try {
10
+ const { id, spec: specId } = await params;
11
+
12
+ if (process.env.SPECS_MODE === 'multi-project') {
13
+ const spec = await specsService.getSpec(specId, id);
14
+ if (!spec) {
15
+ return NextResponse.json(
16
+ { error: 'Spec not found' },
17
+ { status: 404 }
18
+ );
19
+ }
20
+ return NextResponse.json({ spec });
21
+ }
22
+
23
+ const spec = await getSpecById(specId);
24
+ if (!spec) {
25
+ return NextResponse.json(
26
+ { error: 'Spec not found' },
27
+ { status: 404 }
28
+ );
29
+ }
30
+ return NextResponse.json({ spec });
31
+ } catch (error) {
32
+ console.error('Error fetching spec:', error);
33
+ return NextResponse.json(
34
+ { error: 'Failed to fetch spec' },
35
+ { status: 500 }
36
+ );
37
+ }
38
+ }
@@ -0,0 +1,97 @@
1
+ import { NextResponse } from 'next/server';
2
+ import path from 'node:path';
3
+ import { readFile, writeFile } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { createUpdatedFrontmatter } from '@leanspec/core';
6
+ import { projectRegistry } from '@/lib/projects/registry';
7
+
8
+ const ALLOWED_STATUSES = ['planned', 'in-progress', 'complete', 'archived'] as const;
9
+ type AllowedStatus = (typeof ALLOWED_STATUSES)[number];
10
+
11
+ async function findSpecDirectory(specsDir: string, specIdentifier: string): Promise<string | null> {
12
+ if (!existsSync(specsDir)) {
13
+ return null;
14
+ }
15
+
16
+ const { readdir } = await import('node:fs/promises');
17
+ const entries = await readdir(specsDir, { withFileTypes: true });
18
+
19
+ // Match by spec number or full directory name
20
+ const specPattern = /^(\d{2,})-/;
21
+ const specNum = parseInt(specIdentifier.split('-')[0], 10);
22
+
23
+ for (const entry of entries) {
24
+ if (!entry.isDirectory()) continue;
25
+
26
+ // Match by full name or by spec number
27
+ if (entry.name === specIdentifier) {
28
+ return path.join(specsDir, entry.name);
29
+ }
30
+
31
+ if (!isNaN(specNum) && specPattern.test(entry.name)) {
32
+ const dirNum = parseInt(entry.name.split('-')[0], 10);
33
+ if (dirNum === specNum) {
34
+ return path.join(specsDir, entry.name);
35
+ }
36
+ }
37
+ }
38
+
39
+ return null;
40
+ }
41
+
42
+ export async function PATCH(
43
+ request: Request,
44
+ { params }: { params: Promise<{ id: string; spec: string }> }
45
+ ) {
46
+ try {
47
+ const { id: projectId, spec: specId } = await params;
48
+
49
+ if (process.env.SPECS_MODE !== 'multi-project') {
50
+ return NextResponse.json({ error: 'Multi-project mode not enabled' }, { status: 400 });
51
+ }
52
+
53
+ const project = await projectRegistry.getProject(projectId);
54
+ if (!project) {
55
+ return NextResponse.json({ error: 'Project not found' }, { status: 404 });
56
+ }
57
+
58
+ let payload: { status?: AllowedStatus } = {};
59
+ try {
60
+ payload = await request.json();
61
+ } catch {
62
+ return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 });
63
+ }
64
+
65
+ const { status } = payload;
66
+ if (!status || !ALLOWED_STATUSES.includes(status)) {
67
+ return NextResponse.json({ error: 'Invalid status value' }, { status: 400 });
68
+ }
69
+
70
+ const specIdentifier = decodeURIComponent(specId);
71
+ const specDir = await findSpecDirectory(project.specsDir, specIdentifier);
72
+
73
+ if (!specDir) {
74
+ return NextResponse.json({ error: 'Spec not found' }, { status: 404 });
75
+ }
76
+
77
+ const readmePath = path.join(specDir, 'README.md');
78
+
79
+ if (!existsSync(readmePath)) {
80
+ return NextResponse.json({ error: 'Spec README.md not found' }, { status: 404 });
81
+ }
82
+
83
+ // Read current content
84
+ const currentContent = await readFile(readmePath, 'utf-8');
85
+
86
+ // Update frontmatter using @leanspec/core
87
+ const { content: updatedContent } = createUpdatedFrontmatter(currentContent, { status });
88
+
89
+ // Write back to file
90
+ await writeFile(readmePath, updatedContent, 'utf-8');
91
+
92
+ return NextResponse.json({ success: true });
93
+ } catch (error) {
94
+ console.error('Failed to update spec status:', error);
95
+ return NextResponse.json({ error: 'Failed to update spec status' }, { status: 500 });
96
+ }
97
+ }