@leanspec/ui 0.2.8 → 0.2.9

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 (399) hide show
  1. package/.next/standalone/node_modules/.pnpm/@img+sharp-darwin-arm64@0.34.5/node_modules/@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node +0 -0
  2. package/.next/standalone/node_modules/.pnpm/{@img+sharp-linux-x64@0.34.5/node_modules/@img/sharp-linux-x64 → @img+sharp-darwin-arm64@0.34.5/node_modules/@img/sharp-darwin-arm64}/package.json +7 -13
  3. package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64 → @img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64}/README.md +2 -2
  4. package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64 → @img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64}/lib/glib-2.0/include/glibconfig.h +8 -9
  5. package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 → @img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64/lib/libvips-cpp.8.17.3.dylib} +0 -0
  6. package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64 → @img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64}/package.json +5 -11
  7. package/.next/standalone/node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
  8. package/.next/standalone/packages/ui/.next/BUILD_ID +1 -1
  9. package/.next/standalone/packages/ui/.next/app-path-routes-manifest.json +2 -0
  10. package/.next/standalone/packages/ui/.next/build-manifest.json +4 -4
  11. package/.next/standalone/packages/ui/.next/prerender-manifest.json +3 -3
  12. package/.next/standalone/packages/ui/.next/required-server-files.json +4 -4
  13. package/.next/standalone/packages/ui/.next/routes-manifest.json +12 -0
  14. package/.next/standalone/packages/ui/.next/server/app/_global-error/page/build-manifest.json +2 -2
  15. package/.next/standalone/packages/ui/.next/server/app/_global-error/page.js.nft.json +1 -1
  16. package/.next/standalone/packages/ui/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/packages/ui/.next/server/app/_global-error.html +2 -2
  18. package/.next/standalone/packages/ui/.next/server/app/_global-error.rsc +1 -1
  19. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  20. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  21. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  22. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  23. package/.next/standalone/packages/ui/.next/server/app/_not-found/page/build-manifest.json +2 -2
  24. package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js.nft.json +1 -1
  25. package/.next/standalone/packages/ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  26. package/.next/standalone/packages/ui/.next/server/app/_not-found.html +2 -2
  27. package/.next/standalone/packages/ui/.next/server/app/_not-found.rsc +18 -18
  28. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_full.segment.rsc +18 -18
  29. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  30. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
  31. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  32. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_tree.segment.rsc +5 -5
  33. package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.nft.json +1 -1
  34. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/app-paths-manifest.json +3 -0
  35. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/build-manifest.json +11 -0
  36. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/server-reference-manifest.json +4 -0
  37. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js +8 -0
  38. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js.map +5 -0
  39. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js.nft.json +1 -0
  40. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route_client-reference-manifest.js +2 -0
  41. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.nft.json +1 -1
  42. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.nft.json +1 -1
  43. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.nft.json +1 -1
  44. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.nft.json +1 -1
  45. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
  46. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.nft.json +1 -1
  47. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.nft.json +1 -1
  48. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
  49. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.nft.json +1 -1
  50. package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js.nft.json +1 -1
  51. package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js.nft.json +1 -1
  52. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
  53. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
  54. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js.nft.json +1 -1
  55. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
  56. package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js.nft.json +1 -1
  57. package/.next/standalone/packages/ui/.next/server/app/context/page/build-manifest.json +2 -2
  58. package/.next/standalone/packages/ui/.next/server/app/context/page.js.nft.json +1 -1
  59. package/.next/standalone/packages/ui/.next/server/app/context/page_client-reference-manifest.js +1 -1
  60. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/app-paths-manifest.json +3 -0
  61. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/build-manifest.json +18 -0
  62. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/next-font-manifest.json +6 -0
  63. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/react-loadable-manifest.json +1 -0
  64. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/server-reference-manifest.json +4 -0
  65. package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js +19 -0
  66. package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js.map +5 -0
  67. package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js.nft.json +1 -0
  68. package/.next/standalone/packages/ui/.next/server/app/dependencies/page_client-reference-manifest.js +2 -0
  69. package/.next/standalone/packages/ui/.next/server/app/page/build-manifest.json +2 -2
  70. package/.next/standalone/packages/ui/.next/server/app/page.js.nft.json +1 -1
  71. package/.next/standalone/packages/ui/.next/server/app/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/build-manifest.json +2 -2
  73. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.nft.json +1 -1
  74. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +1 -1
  75. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/build-manifest.json +2 -2
  76. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.nft.json +1 -1
  77. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page_client-reference-manifest.js +1 -1
  78. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/build-manifest.json +2 -2
  79. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.nft.json +1 -1
  80. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page_client-reference-manifest.js +1 -1
  81. package/.next/standalone/packages/ui/.next/server/app/projects/page/build-manifest.json +2 -2
  82. package/.next/standalone/packages/ui/.next/server/app/projects/page.js.nft.json +1 -1
  83. package/.next/standalone/packages/ui/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  84. package/.next/standalone/packages/ui/.next/server/app/projects.html +2 -2
  85. package/.next/standalone/packages/ui/.next/server/app/projects.rsc +24 -23
  86. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_full.segment.rsc +24 -23
  87. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_index.segment.rsc +9 -9
  88. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  89. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +2 -2
  90. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects.segment.rsc +1 -1
  91. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page/build-manifest.json +2 -2
  92. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js.nft.json +1 -1
  93. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
  94. package/.next/standalone/packages/ui/.next/server/app/specs/page/build-manifest.json +2 -2
  95. package/.next/standalone/packages/ui/.next/server/app/specs/page.js.nft.json +1 -1
  96. package/.next/standalone/packages/ui/.next/server/app/specs/page_client-reference-manifest.js +1 -1
  97. package/.next/standalone/packages/ui/.next/server/app/stats/page/build-manifest.json +2 -2
  98. package/.next/standalone/packages/ui/.next/server/app/stats/page.js.nft.json +1 -1
  99. package/.next/standalone/packages/ui/.next/server/app/stats/page_client-reference-manifest.js +1 -1
  100. package/.next/standalone/packages/ui/.next/server/app-paths-manifest.json +2 -0
  101. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__65667b70._.js +1 -1
  102. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__803d07f0._.js +1 -1
  103. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__84cdc14a._.js +1 -1
  104. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8a9ab1a3._.js +1 -1
  105. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__b0969111._.js +3 -0
  106. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bdc3963a._.js +1 -1
  107. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__f5c6d6b8._.js +1 -1
  108. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_dependencies_route_actions_cf6b14c3.js +3 -0
  109. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__12b4eb41._.js +1 -1
  110. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__3c77d95b._.js +3 -0
  111. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__44b603f9._.js +3 -0
  112. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__daee3355._.js → [root-of-the-server]__8608a6fa._.js} +2 -2
  113. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__fd80e4dd._.js → [root-of-the-server]__a965a67b._.js} +2 -2
  114. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__daedd80e._.js +3 -0
  115. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__dc176c61._.js +3 -0
  116. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_03aa8d19._.js +7 -0
  117. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_28fe1532._.js +1 -1
  118. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_8cec504f._.js +3 -0
  119. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{_22274047._.js → _adb9d7cb._.js} +2 -2
  120. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_da18b655._.js +3 -0
  121. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ea899b87._.js +3 -0
  122. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_f38e75b7._.js +4 -0
  123. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_fe120f8a._.js +3 -0
  124. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_015f83ca._.js +3 -0
  125. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_1120b57c._.js +3 -0
  126. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_151891de._.js +3 -0
  127. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_1c916fe3._.js +3 -0
  128. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_80605a06._.js +3 -0
  129. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_bb80de48._.js +3 -0
  130. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_e8075f9b._.js +3 -0
  131. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_f919ef4a._.js +3 -0
  132. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_dependencies_page_actions_57387d47.js +3 -0
  133. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_context_context-client_tsx_4ba99a62._.js +2 -2
  134. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_dependencies_dependencies-client_tsx_0e82443a._.js +4 -0
  135. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_spec-detail-wrapper_tsx_fd35401c._.js +3 -0
  136. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_specs-nav-sidebar_tsx_8237ed13._.js +1 -1
  137. package/.next/standalone/packages/ui/.next/server/middleware-build-manifest.js +2 -2
  138. package/.next/standalone/packages/ui/.next/server/pages/404.html +2 -2
  139. package/.next/standalone/packages/ui/.next/server/pages/500.html +2 -2
  140. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.js +1 -1
  141. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.json +1 -1
  142. package/.next/standalone/packages/ui/.next/static/chunks/094cf9f4e3553261.js +1 -0
  143. package/.next/standalone/packages/ui/.next/static/chunks/1c015eb9eaaf9f9c.js +1 -0
  144. package/.next/standalone/packages/ui/.next/static/chunks/{f6dd06e6d22d2d12.js → 1d36660b2877d213.js} +3 -3
  145. package/.next/standalone/packages/ui/.next/static/chunks/46275d9d67603bf5.js +1 -0
  146. package/.next/standalone/packages/ui/.next/static/chunks/4d29ca0fa6843070.js +2 -0
  147. package/.next/standalone/packages/ui/.next/static/chunks/59854b15bf046467.js +1 -0
  148. package/.next/{static/chunks/dae403679aae65f4.js → standalone/packages/ui/.next/static/chunks/5fd8101e32b076b1.js} +1 -1
  149. package/.next/standalone/packages/ui/.next/static/chunks/6d938a49daa10208.js +2 -0
  150. package/.next/standalone/packages/ui/.next/static/chunks/979625373d5474b6.js +1 -0
  151. package/.next/standalone/packages/ui/.next/static/chunks/a33f10af6abef4df.js +10 -0
  152. package/.next/{static/chunks/794f3931f1ca12d2.js → standalone/packages/ui/.next/static/chunks/a3d7e1be47de010b.js} +1 -1
  153. package/.next/standalone/packages/ui/.next/static/chunks/a5e25b9fa6b88eee.js +1 -0
  154. package/.next/standalone/packages/ui/.next/static/chunks/b53250480fde6816.js +1 -0
  155. package/.next/standalone/packages/ui/.next/static/chunks/b7f19087afe1d2c9.css +1 -0
  156. package/.next/standalone/packages/ui/.next/static/chunks/c658e22a605e0ed1.js +1 -0
  157. package/.next/standalone/packages/ui/.next/static/chunks/c92660d8d0c4763d.js +1 -0
  158. package/.next/standalone/packages/ui/.next/static/chunks/ddd87cd0d26bc2f5.js +1 -0
  159. package/.next/standalone/packages/ui/.next/static/chunks/eeec245955b3b600.js +5 -0
  160. package/.next/standalone/packages/ui/.next/static/chunks/ff11efb770d5a0bc.js +1 -0
  161. package/.next/{static/chunks/turbopack-5fa55215af0efb15.js → standalone/packages/ui/.next/static/chunks/turbopack-261c5dcdd873f310.js} +1 -1
  162. package/.next/standalone/packages/ui/dist/standalone/packages/web/components.json +20 -0
  163. package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/0000_reflective_thena.sql +59 -0
  164. package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/0001_fresh_carmella_unuscione.sql +1 -0
  165. package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/meta/0000_snapshot.json +427 -0
  166. package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/meta/0001_snapshot.json +436 -0
  167. package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/meta/_journal.json +20 -0
  168. package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle.config.ts +10 -0
  169. package/.next/standalone/packages/ui/dist/standalone/packages/web/eslint.config.mjs +18 -0
  170. package/.next/standalone/packages/ui/dist/standalone/packages/web/next.config.ts +7 -0
  171. package/.next/standalone/packages/ui/dist/standalone/packages/web/package.json +9 -1
  172. package/.next/standalone/packages/ui/dist/standalone/packages/web/postcss.config.mjs +8 -0
  173. package/.next/standalone/packages/ui/dist/standalone/packages/web/server.js +1 -1
  174. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/projects/[id]/specs/route.ts +23 -0
  175. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/projects/route.ts +19 -0
  176. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/revalidate/route.ts +63 -0
  177. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/dependency-graph/route.test.ts +51 -0
  178. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/dependency-graph/route.ts +171 -0
  179. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/route.ts +36 -0
  180. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/subspecs/[file]/route.ts +46 -0
  181. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/stats/route.ts +19 -0
  182. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/board/board-client.tsx +162 -0
  183. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/board/loading.tsx +43 -0
  184. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/board/page.tsx +18 -0
  185. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/dashboard-client.tsx +364 -0
  186. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/error.tsx +43 -0
  187. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/globals.css +531 -0
  188. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/home-client.tsx +277 -0
  189. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/layout.tsx +70 -0
  190. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/loading.tsx +87 -0
  191. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/not-found.tsx +27 -0
  192. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/page.tsx +18 -0
  193. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/[id]/loading.tsx +5 -0
  194. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/[id]/page.tsx +43 -0
  195. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/page.tsx +18 -0
  196. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/specs-client.tsx +425 -0
  197. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/stats/page.tsx +18 -0
  198. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/stats/stats-client.tsx +283 -0
  199. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/back-to-top.tsx +46 -0
  200. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/empty-state.tsx +52 -0
  201. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/main-sidebar.tsx +175 -0
  202. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/markdown-link.test.ts +96 -0
  203. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/markdown-link.tsx +95 -0
  204. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/navigation.tsx +210 -0
  205. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/priority-badge.tsx +53 -0
  206. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/quick-search.tsx +180 -0
  207. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/skeletons.tsx +119 -0
  208. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-dependency-graph.tsx +369 -0
  209. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-detail-client.tsx +372 -0
  210. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-detail-loading-shell.tsx +42 -0
  211. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-detail-wrapper.tsx +70 -0
  212. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-metadata.tsx +136 -0
  213. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-sidebar.tsx +127 -0
  214. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-timeline.tsx +186 -0
  215. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/specs-nav-sidebar.tsx +561 -0
  216. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/status-badge.tsx +53 -0
  217. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/sub-spec-tabs.tsx +143 -0
  218. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/table-of-contents.tsx +130 -0
  219. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/theme-provider.tsx +11 -0
  220. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/theme-toggle.tsx +37 -0
  221. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/avatar.tsx +50 -0
  222. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/badge.tsx +36 -0
  223. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/breadcrumb.tsx +110 -0
  224. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/button.tsx +57 -0
  225. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/card.tsx +76 -0
  226. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/command.tsx +153 -0
  227. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/dialog.tsx +122 -0
  228. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/input.tsx +24 -0
  229. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/select.tsx +159 -0
  230. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/separator.tsx +31 -0
  231. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/skeleton.tsx +15 -0
  232. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/tabs.tsx +55 -0
  233. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/toast.tsx +30 -0
  234. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/tooltip.tsx +32 -0
  235. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/date-utils.ts +76 -0
  236. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/index.ts +42 -0
  237. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/migrate.ts +18 -0
  238. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/queries.ts +114 -0
  239. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/schema.ts +123 -0
  240. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/seed.ts +156 -0
  241. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/service-queries.ts +216 -0
  242. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/dependency-graph.ts +105 -0
  243. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/service.ts +120 -0
  244. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/sources/database-source.ts +94 -0
  245. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/sources/filesystem-source.ts +249 -0
  246. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/types.ts +55 -0
  247. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/stores/specs-sidebar-store.ts +152 -0
  248. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/sub-specs.ts +171 -0
  249. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/utils.ts +17 -0
  250. package/.next/standalone/packages/ui/dist/standalone/packages/web/src/types/specs.ts +18 -0
  251. package/.next/standalone/packages/ui/dist/standalone/packages/web/tailwind.config.ts +58 -0
  252. package/.next/standalone/packages/ui/dist/standalone/packages/web/tsconfig.json +34 -0
  253. package/.next/standalone/packages/ui/dist/standalone/packages/web/tsconfig.tsbuildinfo +1 -0
  254. package/.next/standalone/packages/ui/dist/standalone/packages/web/vitest.config.ts +14 -0
  255. package/.next/standalone/packages/ui/dist/standalone/specs/035-live-specs-showcase/README.md +7 -3
  256. package/.next/standalone/packages/ui/dist/standalone/specs/072-ai-agent-first-use-workflow/README.md +5 -3
  257. package/.next/standalone/packages/ui/dist/standalone/specs/081-web-app-ux-redesign/README.md +2 -1
  258. package/.next/standalone/packages/ui/dist/standalone/specs/082-web-realtime-sync-architecture/README.md +8 -3
  259. package/.next/standalone/packages/ui/dist/standalone/specs/087-cli-ui-command/README.md +73 -259
  260. package/.next/standalone/packages/ui/dist/standalone/specs/088-core-concepts-terminology-only/README.md +5 -3
  261. package/.next/standalone/packages/ui/dist/standalone/specs/089-sdd-practical-tutorials/README.md +5 -3
  262. package/.next/standalone/packages/ui/dist/standalone/specs/090-leanspec-sdd-case-studies/README.md +5 -3
  263. package/.next/standalone/packages/ui/dist/standalone/specs/091-chinese-localization-strategy/README.md +33 -23
  264. package/.next/standalone/packages/ui/dist/standalone/specs/092-docs-site-submodule-migration/README.md +7 -3
  265. package/.next/standalone/packages/ui/dist/standalone/specs/093-spec-detail-ui-improvements/README.md +25 -14
  266. package/.next/standalone/packages/ui/dist/standalone/specs/094-ai-chatbot-web-integration/README.md +332 -0
  267. package/.next/standalone/packages/ui/dist/standalone/specs/095-pr-migration-verification/README.md +339 -0
  268. package/.next/standalone/packages/ui/dist/standalone/specs/096-docs-beginner-first-reorg/README.md +399 -0
  269. package/.next/standalone/packages/ui/dist/standalone/specs/097-dag-visualization-library/README.md +525 -0
  270. package/.next/standalone/packages/ui/dist/standalone/specs/098-github-multi-project-integration/README.md +387 -0
  271. package/.next/standalone/packages/ui/dist/standalone/specs/099-enhanced-dependency-commands-cli-mcp/README.md +613 -0
  272. package/.next/standalone/packages/ui/dist/standalone/specs/100-release-process-typecheck-failure/README.md +266 -0
  273. package/.next/standalone/packages/ui/dist/standalone/specs/101-sidebar-scroll-position-drift/README.md +100 -0
  274. package/.next/standalone/packages/ui/dist/standalone/specs/102-mcp-wrapper-package/README.md +172 -0
  275. package/.next/standalone/packages/ui/package.json +3 -1
  276. package/.next/standalone/packages/ui/server.js +1 -1
  277. package/.next/standalone/packages/ui/src/app/api/dependencies/route.ts +81 -0
  278. package/.next/standalone/packages/ui/src/app/context/context-client.tsx +23 -1
  279. package/.next/standalone/packages/ui/src/app/dependencies/constants.ts +24 -0
  280. package/.next/standalone/packages/ui/src/app/dependencies/dependencies-client.tsx +625 -0
  281. package/.next/standalone/packages/ui/src/app/dependencies/index.ts +19 -0
  282. package/.next/standalone/packages/ui/src/app/dependencies/page.tsx +38 -0
  283. package/.next/standalone/packages/ui/src/app/dependencies/spec-node.tsx +80 -0
  284. package/.next/standalone/packages/ui/src/app/dependencies/spec-sidebar.tsx +198 -0
  285. package/.next/standalone/packages/ui/src/app/dependencies/types.ts +37 -0
  286. package/.next/standalone/packages/ui/src/app/dependencies/utils.ts +194 -0
  287. package/.next/standalone/packages/ui/src/components/context-file-detail.tsx +308 -0
  288. package/.next/standalone/packages/ui/src/components/context-file-viewer.tsx +96 -2
  289. package/.next/standalone/packages/ui/src/components/main-sidebar.tsx +10 -1
  290. package/.next/standalone/packages/ui/tsconfig.tsbuildinfo +1 -1
  291. package/.next/static/chunks/094cf9f4e3553261.js +1 -0
  292. package/.next/static/chunks/1c015eb9eaaf9f9c.js +1 -0
  293. package/.next/static/chunks/{f6dd06e6d22d2d12.js → 1d36660b2877d213.js} +3 -3
  294. package/.next/static/chunks/46275d9d67603bf5.js +1 -0
  295. package/.next/static/chunks/4d29ca0fa6843070.js +2 -0
  296. package/.next/static/chunks/59854b15bf046467.js +1 -0
  297. package/.next/{standalone/packages/ui/.next/static/chunks/dae403679aae65f4.js → static/chunks/5fd8101e32b076b1.js} +1 -1
  298. package/.next/static/chunks/6d938a49daa10208.js +2 -0
  299. package/.next/static/chunks/979625373d5474b6.js +1 -0
  300. package/.next/static/chunks/a33f10af6abef4df.js +10 -0
  301. package/.next/{standalone/packages/ui/.next/static/chunks/794f3931f1ca12d2.js → static/chunks/a3d7e1be47de010b.js} +1 -1
  302. package/.next/static/chunks/a5e25b9fa6b88eee.js +1 -0
  303. package/.next/static/chunks/b53250480fde6816.js +1 -0
  304. package/.next/static/chunks/b7f19087afe1d2c9.css +1 -0
  305. package/.next/static/chunks/c658e22a605e0ed1.js +1 -0
  306. package/.next/static/chunks/c92660d8d0c4763d.js +1 -0
  307. package/.next/static/chunks/ddd87cd0d26bc2f5.js +1 -0
  308. package/.next/static/chunks/eeec245955b3b600.js +5 -0
  309. package/.next/static/chunks/ff11efb770d5a0bc.js +1 -0
  310. package/.next/{standalone/packages/ui/.next/static/chunks/turbopack-5fa55215af0efb15.js → static/chunks/turbopack-261c5dcdd873f310.js} +1 -1
  311. package/package.json +4 -2
  312. package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  313. package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  314. package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  315. package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  316. package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  317. package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  318. package/.next/standalone/node_modules/.pnpm/@img+sharp-linux-x64@0.34.5/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  319. package/.next/standalone/node_modules/.pnpm/@img+sharp-linuxmusl-x64@0.34.5/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  320. package/.next/standalone/node_modules/.pnpm/@img+sharp-linuxmusl-x64@0.34.5/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  321. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__6e739186._.js +0 -7
  322. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a4c56419._.js +0 -7
  323. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__b6632d78._.js +0 -3
  324. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_0f9ffe32._.js +0 -3
  325. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_315f3b3a._.js +0 -3
  326. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_9dcf102b._.js +0 -3
  327. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ac867463._.js +0 -3
  328. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_b397e94a._.js +0 -3
  329. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_8272a49c._.js +0 -3
  330. package/.next/standalone/packages/ui/.next/static/chunks/1eb8283995f370c6.js +0 -1
  331. package/.next/standalone/packages/ui/.next/static/chunks/336e8e8fc6b0fba8.js +0 -1
  332. package/.next/standalone/packages/ui/.next/static/chunks/37a1236ed50645a6.js +0 -1
  333. package/.next/standalone/packages/ui/.next/static/chunks/9d84ba08a41145ec.js +0 -5
  334. package/.next/standalone/packages/ui/.next/static/chunks/b8353eb8c6fb895e.js +0 -1
  335. package/.next/standalone/packages/ui/.next/static/chunks/c4b1faff3361a749.js +0 -1
  336. package/.next/standalone/packages/ui/.next/static/chunks/d7420d2a867e57b5.js +0 -1
  337. package/.next/standalone/packages/ui/.next/static/chunks/efded9da04c960d8.js +0 -1
  338. package/.next/standalone/packages/ui/.next/static/chunks/f382932f1a5d6359.js +0 -10
  339. package/.next/standalone/packages/ui/.next/static/chunks/f43b6e43b4da1a32.css +0 -1
  340. package/.next/standalone/packages/ui/dist/BUILD_ID +0 -1
  341. package/.next/standalone/packages/ui/dist/static/chunks/0c19c69aa7625475.js +0 -1
  342. package/.next/standalone/packages/ui/dist/static/chunks/116800b03245a1e5.js +0 -1
  343. package/.next/standalone/packages/ui/dist/static/chunks/15843a3d7584e314.js +0 -1
  344. package/.next/standalone/packages/ui/dist/static/chunks/19e80edf527aef5c.js +0 -1
  345. package/.next/standalone/packages/ui/dist/static/chunks/465954d5af3284a9.js +0 -1
  346. package/.next/standalone/packages/ui/dist/static/chunks/5abeeb89f1412a80.js +0 -3
  347. package/.next/standalone/packages/ui/dist/static/chunks/5c2072ad938de8ed.js +0 -1
  348. package/.next/standalone/packages/ui/dist/static/chunks/6a05a93ec8fa7b83.js +0 -1
  349. package/.next/standalone/packages/ui/dist/static/chunks/778e42188e450b39.css +0 -1
  350. package/.next/standalone/packages/ui/dist/static/chunks/a02c1f50ff00204f.js +0 -1
  351. package/.next/standalone/packages/ui/dist/static/chunks/a45464b9776dd88e.js +0 -1
  352. package/.next/standalone/packages/ui/dist/static/chunks/a6dad97d9634a72d.js +0 -1
  353. package/.next/standalone/packages/ui/dist/static/chunks/b0ea0ac61604f843.js +0 -1
  354. package/.next/standalone/packages/ui/dist/static/chunks/c06e85b449720194.js +0 -1
  355. package/.next/standalone/packages/ui/dist/static/chunks/c557ac675be79771.js +0 -1
  356. package/.next/standalone/packages/ui/dist/static/chunks/cad005a57ffbb2d3.js +0 -1
  357. package/.next/standalone/packages/ui/dist/static/chunks/cdf6fe33bc65efbc.js +0 -1
  358. package/.next/standalone/packages/ui/dist/static/chunks/d12ed5dbe44caed7.js +0 -1
  359. package/.next/standalone/packages/ui/dist/static/chunks/d1ebe5c1a344f4ca.js +0 -5
  360. package/.next/standalone/packages/ui/dist/static/chunks/d42cf1682bc46652.js +0 -1
  361. package/.next/standalone/packages/ui/dist/static/chunks/dde5d8bddd7fbfcf.js +0 -1
  362. package/.next/standalone/packages/ui/dist/static/chunks/ebd89051637b9a47.js +0 -4
  363. package/.next/standalone/packages/ui/dist/static/chunks/ec82875d18b29f47.js +0 -2
  364. package/.next/standalone/packages/ui/dist/static/chunks/f0b701df9769bcc5.js +0 -19
  365. package/.next/standalone/packages/ui/dist/static/chunks/turbopack-1c09a99f4c9e28d3.js +0 -3
  366. package/.next/static/-Mn9iD4O5f_khGd1P3kmB/_buildManifest.js +0 -11
  367. package/.next/static/-Mn9iD4O5f_khGd1P3kmB/_clientMiddlewareManifest.json +0 -1
  368. package/.next/static/-Mn9iD4O5f_khGd1P3kmB/_ssgManifest.js +0 -1
  369. package/.next/static/chunks/1eb8283995f370c6.js +0 -1
  370. package/.next/static/chunks/336e8e8fc6b0fba8.js +0 -1
  371. package/.next/static/chunks/37a1236ed50645a6.js +0 -1
  372. package/.next/static/chunks/9d84ba08a41145ec.js +0 -5
  373. package/.next/static/chunks/b8353eb8c6fb895e.js +0 -1
  374. package/.next/static/chunks/c4b1faff3361a749.js +0 -1
  375. package/.next/static/chunks/d7420d2a867e57b5.js +0 -1
  376. package/.next/static/chunks/efded9da04c960d8.js +0 -1
  377. package/.next/static/chunks/f382932f1a5d6359.js +0 -10
  378. package/.next/static/chunks/f43b6e43b4da1a32.css +0 -1
  379. /package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64 → @img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64}/lib/index.js +0 -0
  380. /package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64 → @img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64}/versions.json +0 -0
  381. /package/.next/standalone/packages/ui/.next/static/{-Mn9iD4O5f_khGd1P3kmB → 8PwFWS-09QjFSbDbfp15t}/_buildManifest.js +0 -0
  382. /package/.next/standalone/packages/ui/.next/static/{-Mn9iD4O5f_khGd1P3kmB → 8PwFWS-09QjFSbDbfp15t}/_clientMiddlewareManifest.json +0 -0
  383. /package/.next/standalone/packages/ui/.next/static/{-Mn9iD4O5f_khGd1P3kmB → 8PwFWS-09QjFSbDbfp15t}/_ssgManifest.js +0 -0
  384. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/f864aa7e7061c0600e35cf3d879b27cf.txt +0 -0
  385. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/favicon.ico +0 -0
  386. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/file.svg +0 -0
  387. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/github-mark-white.svg +0 -0
  388. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/github-mark.svg +0 -0
  389. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/globe.svg +0 -0
  390. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/icon.svg +0 -0
  391. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/logo-dark-bg.svg +0 -0
  392. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/logo-with-bg.svg +0 -0
  393. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/logo.svg +0 -0
  394. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/next.svg +0 -0
  395. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/vercel.svg +0 -0
  396. /package/.next/standalone/packages/ui/dist/{public → standalone/packages/web/public}/window.svg +0 -0
  397. /package/.next/{standalone/packages/ui/dist/static/4ZnYN1WbN4LGJQOwP6FkT → static/8PwFWS-09QjFSbDbfp15t}/_buildManifest.js +0 -0
  398. /package/.next/{standalone/packages/ui/dist/static/4ZnYN1WbN4LGJQOwP6FkT → static/8PwFWS-09QjFSbDbfp15t}/_clientMiddlewareManifest.json +0 -0
  399. /package/.next/{standalone/packages/ui/dist/static/4ZnYN1WbN4LGJQOwP6FkT → static/8PwFWS-09QjFSbDbfp15t}/_ssgManifest.js +0 -0
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Filesystem-based spec source
3
+ * Reads specs directly from the filesystem with in-memory caching
4
+ */
5
+
6
+ import * as fs from 'node:fs/promises';
7
+ import * as path from 'node:path';
8
+ import matter from 'gray-matter';
9
+ import type { SpecSource, CachedSpec } from '../types';
10
+ import type { Spec } from '../../db/schema';
11
+
12
+ // Cache TTL from environment
13
+ // Default: 0ms in development, 60s in production
14
+ const isDev = process.env.NODE_ENV === 'development';
15
+ const CACHE_TTL = parseInt(process.env.CACHE_TTL || (isDev ? '0' : '60000'), 10);
16
+
17
+ /**
18
+ * Filesystem source implementation
19
+ * Reads specs from local filesystem with in-memory caching
20
+ */
21
+ export class FilesystemSource implements SpecSource {
22
+ private cache = new Map<string, CachedSpec<Spec | Spec[]>>();
23
+ private specsDir: string;
24
+
25
+ constructor(specsDir?: string) {
26
+ // Default to ../../specs relative to the web package
27
+ this.specsDir = specsDir || path.join(process.cwd(), '../../specs');
28
+ }
29
+
30
+ /**
31
+ * Get all specs from filesystem
32
+ */
33
+ async getAllSpecs(): Promise<Spec[]> {
34
+ const cacheKey = '__all_specs__';
35
+ const cached = this.cache.get(cacheKey);
36
+
37
+ if (cached && Date.now() < cached.expiresAt) {
38
+ return cached.data as Spec[];
39
+ }
40
+
41
+ const specs = await this.loadSpecsFromFilesystem();
42
+
43
+ this.cache.set(cacheKey, {
44
+ data: specs,
45
+ expiresAt: Date.now() + CACHE_TTL,
46
+ });
47
+
48
+ return specs;
49
+ }
50
+
51
+ /**
52
+ * Get a single spec by path
53
+ */
54
+ async getSpec(specPath: string): Promise<Spec | null> {
55
+ const cacheKey = `spec:${specPath}`;
56
+ const cached = this.cache.get(cacheKey);
57
+
58
+ if (cached && Date.now() < cached.expiresAt) {
59
+ return cached.data as Spec;
60
+ }
61
+
62
+ // Parse spec number from path (e.g., "035" or "035-my-spec")
63
+ const specNum = parseInt(specPath.split('-')[0], 10);
64
+ if (isNaN(specNum)) {
65
+ return null;
66
+ }
67
+
68
+ const spec = await this.loadSpecByNumber(specNum);
69
+
70
+ if (spec) {
71
+ this.cache.set(cacheKey, {
72
+ data: spec,
73
+ expiresAt: Date.now() + CACHE_TTL,
74
+ });
75
+ }
76
+
77
+ return spec;
78
+ }
79
+
80
+ /**
81
+ * Get specs by status
82
+ */
83
+ async getSpecsByStatus(status: 'planned' | 'in-progress' | 'complete' | 'archived'): Promise<Spec[]> {
84
+ const allSpecs = await this.getAllSpecs();
85
+ return allSpecs.filter((spec) => spec.status === status);
86
+ }
87
+
88
+ /**
89
+ * Search specs by query (basic implementation)
90
+ */
91
+ async searchSpecs(query: string): Promise<Spec[]> {
92
+ const allSpecs = await this.getAllSpecs();
93
+ const lowerQuery = query.toLowerCase();
94
+
95
+ return allSpecs.filter((spec) => {
96
+ // Search in spec name, title, and content
97
+ return (
98
+ spec.specName.toLowerCase().includes(lowerQuery) ||
99
+ spec.title?.toLowerCase().includes(lowerQuery) ||
100
+ spec.contentMd.toLowerCase().includes(lowerQuery)
101
+ );
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Invalidate cache
107
+ */
108
+ invalidateCache(specPath?: string): void {
109
+ if (specPath) {
110
+ this.cache.delete(`spec:${specPath}`);
111
+ // Also invalidate the all specs cache since it contains this spec
112
+ this.cache.delete('__all_specs__');
113
+ } else {
114
+ this.cache.clear();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Load all specs from filesystem
120
+ */
121
+ private async loadSpecsFromFilesystem(): Promise<Spec[]> {
122
+ const specs: Spec[] = [];
123
+
124
+ try {
125
+ await fs.access(this.specsDir);
126
+ } catch {
127
+ // Specs directory doesn't exist
128
+ return [];
129
+ }
130
+
131
+ // Pattern to match spec directories (2 or more digits followed by dash)
132
+ const specPattern = /^(\d{2,})-/;
133
+
134
+ const entries = await fs.readdir(this.specsDir, { withFileTypes: true });
135
+
136
+ for (const entry of entries) {
137
+ if (!entry.isDirectory()) continue;
138
+ if (entry.name === 'archived') continue; // Skip archived directory
139
+
140
+ if (specPattern.test(entry.name)) {
141
+ const specDir = path.join(this.specsDir, entry.name);
142
+ const spec = await this.loadSpecFromDirectory(specDir, entry.name);
143
+ if (spec) {
144
+ specs.push(spec);
145
+ }
146
+ }
147
+ }
148
+
149
+ // Sort by spec number
150
+ return specs.sort((a, b) => (a.specNumber || 0) - (b.specNumber || 0));
151
+ }
152
+
153
+ /**
154
+ * Load a single spec by number
155
+ */
156
+ private async loadSpecByNumber(specNum: number): Promise<Spec | null> {
157
+ try {
158
+ await fs.access(this.specsDir);
159
+ } catch {
160
+ return null;
161
+ }
162
+
163
+ const entries = await fs.readdir(this.specsDir, { withFileTypes: true });
164
+ const specPattern = new RegExp(`^0*${specNum}-`);
165
+
166
+ for (const entry of entries) {
167
+ if (!entry.isDirectory()) continue;
168
+ if (specPattern.test(entry.name)) {
169
+ const specDir = path.join(this.specsDir, entry.name);
170
+ return await this.loadSpecFromDirectory(specDir, entry.name);
171
+ }
172
+ }
173
+
174
+ return null;
175
+ }
176
+
177
+ /**
178
+ * Load a spec from a directory
179
+ */
180
+ private async loadSpecFromDirectory(specDir: string, specName: string): Promise<Spec | null> {
181
+ const readmePath = path.join(specDir, 'README.md');
182
+
183
+ try {
184
+ const rawContent = await fs.readFile(readmePath, 'utf-8');
185
+ const { data: frontmatter, content: markdownContent } = matter(rawContent);
186
+
187
+ if (!frontmatter || !frontmatter.status) {
188
+ return null;
189
+ }
190
+
191
+ // Extract spec number from directory name
192
+ const specNumMatch = specName.match(/^(\d+)/);
193
+ const specNumber = specNumMatch ? parseInt(specNumMatch[1], 10) : null;
194
+
195
+ // Generate a pseudo-ID for filesystem specs (not stored in DB)
196
+ const id = `fs-${specName}`;
197
+
198
+ const createdValue = frontmatter.created_at ?? frontmatter.created;
199
+ const updatedValue = frontmatter.updated_at ?? frontmatter.updated;
200
+ const completedValue = frontmatter.completed_at ?? frontmatter.completed;
201
+
202
+ const toDate = (value: unknown): Date | null => {
203
+ if (!value) return null;
204
+ const parsed = new Date(value as string | number | Date);
205
+ return isNaN(parsed.getTime()) ? null : parsed;
206
+ };
207
+
208
+ // Create a Spec object compatible with the schema
209
+ const spec: Spec = {
210
+ id,
211
+ projectId: 'leanspec', // Default project for LeanSpec's own specs
212
+ specNumber,
213
+ specName,
214
+ title: this.extractTitle(markdownContent),
215
+ status: frontmatter.status || 'planned',
216
+ priority: frontmatter.priority || null,
217
+ tags: frontmatter.tags ? JSON.stringify(frontmatter.tags) : null,
218
+ assignee: frontmatter.assignee || null,
219
+ contentMd: markdownContent, // Use parsed content without frontmatter
220
+ contentHtml: null, // Not pre-rendered for filesystem mode
221
+ createdAt: toDate(createdValue),
222
+ updatedAt: toDate(updatedValue),
223
+ completedAt: toDate(completedValue),
224
+ filePath: `specs/${specName}/README.md`,
225
+ githubUrl: `https://github.com/codervisor/lean-spec/tree/main/specs/${specName}/README.md`,
226
+ syncedAt: new Date(), // Current time for filesystem reads
227
+ };
228
+
229
+ return spec;
230
+ } catch {
231
+ // File doesn't exist or can't be read
232
+ return null;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Extract title from markdown content (first H1)
238
+ */
239
+ private extractTitle(content: string): string | null {
240
+ const lines = content.split('\n');
241
+ for (const line of lines) {
242
+ const match = line.match(/^#\s+(.+)$/);
243
+ if (match) {
244
+ return match[1].trim();
245
+ }
246
+ }
247
+ return null;
248
+ }
249
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Types for the specs service layer
3
+ */
4
+
5
+ import type { Spec } from '../db/schema';
6
+
7
+ /**
8
+ * Unified interface for accessing specs from different sources
9
+ * (filesystem or database)
10
+ */
11
+ export interface SpecSource {
12
+ /**
13
+ * Get all specs, optionally filtered by projectId
14
+ * @param projectId - Optional project ID for database mode
15
+ */
16
+ getAllSpecs(projectId?: string): Promise<Spec[]>;
17
+
18
+ /**
19
+ * Get a single spec by its identifier
20
+ * @param specPath - Spec identifier (e.g., "035" or "035-my-spec")
21
+ * @param projectId - Optional project ID for database mode
22
+ */
23
+ getSpec(specPath: string, projectId?: string): Promise<Spec | null>;
24
+
25
+ /**
26
+ * Get specs filtered by status
27
+ * @param status - Status to filter by
28
+ * @param projectId - Optional project ID for database mode
29
+ */
30
+ getSpecsByStatus(
31
+ status: 'planned' | 'in-progress' | 'complete' | 'archived',
32
+ projectId?: string
33
+ ): Promise<Spec[]>;
34
+
35
+ /**
36
+ * Search specs by query
37
+ * @param query - Search query string
38
+ * @param projectId - Optional project ID for database mode
39
+ */
40
+ searchSpecs(query: string, projectId?: string): Promise<Spec[]>;
41
+
42
+ /**
43
+ * Invalidate cache for a specific spec or all specs
44
+ * @param specPath - Optional spec path to invalidate, or undefined for all
45
+ */
46
+ invalidateCache(specPath?: string): void;
47
+ }
48
+
49
+ /**
50
+ * Cached spec entry with expiration
51
+ */
52
+ export interface CachedSpec<T = Spec | Spec[]> {
53
+ data: T;
54
+ expiresAt: number;
55
+ }
@@ -0,0 +1,152 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { useSyncExternalStore } from 'react';
5
+ import type { SidebarSpec } from '@/types/specs';
6
+
7
+ interface SidebarState {
8
+ specs: SidebarSpec[];
9
+ signature: string | null;
10
+ scrollTop: number;
11
+ activeSpecId: string | null;
12
+ }
13
+
14
+ let state: SidebarState = {
15
+ specs: [],
16
+ signature: null,
17
+ scrollTop: 0,
18
+ activeSpecId: null,
19
+ };
20
+
21
+ const EMPTY_SIDEBAR_SPECS: SidebarSpec[] = [];
22
+
23
+ const listeners = new Set<() => void>();
24
+
25
+ // Separate listeners for different state slices to avoid unnecessary re-renders
26
+ const specsListeners = new Set<() => void>();
27
+ const activeSpecListeners = new Set<() => void>();
28
+
29
+ function emitChange() {
30
+ for (const listener of listeners) {
31
+ listener();
32
+ }
33
+ }
34
+
35
+ function emitSpecsChange() {
36
+ for (const listener of specsListeners) {
37
+ listener();
38
+ }
39
+ }
40
+
41
+ function emitActiveSpecChange() {
42
+ for (const listener of activeSpecListeners) {
43
+ listener();
44
+ }
45
+ }
46
+
47
+ function subscribe(listener: () => void) {
48
+ listeners.add(listener);
49
+ return () => {
50
+ listeners.delete(listener);
51
+ };
52
+ }
53
+
54
+ function getState() {
55
+ return state;
56
+ }
57
+
58
+ function computeSignature(specs: SidebarSpec[]): string {
59
+ return specs
60
+ .map((spec) => [
61
+ spec.id,
62
+ spec.specNumber ?? '',
63
+ spec.title ?? '',
64
+ spec.status ?? '',
65
+ spec.priority ?? '',
66
+ spec.updatedAt ? new Date(spec.updatedAt).getTime() : 0,
67
+ ].join(':'))
68
+ .join('|');
69
+ }
70
+
71
+ export function useSpecsSidebarState() {
72
+ return useSyncExternalStore(subscribe, getState, () => state);
73
+ }
74
+
75
+ // Optimized selector hooks that only subscribe to specific state slices
76
+ export function useSpecsSidebarSpecs() {
77
+ const subscribeToSpecs = React.useCallback((listener: () => void) => {
78
+ specsListeners.add(listener);
79
+ return () => {
80
+ specsListeners.delete(listener);
81
+ };
82
+ }, []);
83
+
84
+ return useSyncExternalStore(
85
+ subscribeToSpecs,
86
+ () => getState().specs,
87
+ () => EMPTY_SIDEBAR_SPECS
88
+ );
89
+ }
90
+
91
+ export function useSpecsSidebarActiveSpec() {
92
+ const subscribeToActiveSpec = React.useCallback((listener: () => void) => {
93
+ activeSpecListeners.add(listener);
94
+ return () => {
95
+ activeSpecListeners.delete(listener);
96
+ };
97
+ }, []);
98
+
99
+ return useSyncExternalStore(
100
+ subscribeToActiveSpec,
101
+ () => getState().activeSpecId,
102
+ () => null
103
+ );
104
+ }
105
+
106
+ export function primeSpecsSidebar(specs: SidebarSpec[]) {
107
+ if (specs.length === 0) {
108
+ return;
109
+ }
110
+
111
+ const signature = computeSignature(specs);
112
+ if (signature === state.signature) {
113
+ return;
114
+ }
115
+
116
+ state = {
117
+ ...state,
118
+ specs,
119
+ signature,
120
+ };
121
+ emitChange();
122
+ emitSpecsChange(); // Notify specs-specific listeners
123
+ }
124
+
125
+ export function setActiveSidebarSpec(specId: string) {
126
+ if (state.activeSpecId === specId) {
127
+ return;
128
+ }
129
+
130
+ state = {
131
+ ...state,
132
+ activeSpecId: specId,
133
+ };
134
+ emitChange();
135
+ emitActiveSpecChange(); // Notify activeSpec-specific listeners
136
+ }
137
+
138
+ export function updateSidebarScrollTop(nextScrollTop: number) {
139
+ if (Math.abs(nextScrollTop - state.scrollTop) < 1) {
140
+ return;
141
+ }
142
+
143
+ state = {
144
+ ...state,
145
+ scrollTop: nextScrollTop,
146
+ };
147
+ // Scroll position persistence should not trigger subscriber re-renders.
148
+ }
149
+
150
+ export function getSidebarScrollTop() {
151
+ return state.scrollTop;
152
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Sub-spec detection and management
3
+ */
4
+
5
+ import { readdirSync, readFileSync, existsSync, statSync } from 'fs';
6
+ import { join } from 'path';
7
+ import matter from 'gray-matter';
8
+
9
+ export interface SubSpec {
10
+ name: string;
11
+ file: string;
12
+ iconName: string;
13
+ color: string;
14
+ content: string;
15
+ }
16
+
17
+ // Icon and color mapping with regex patterns for flexible matching
18
+ const ICON_PATTERNS: Array<{ pattern: RegExp; iconName: string; color: string }> = [
19
+ // Design & UI
20
+ { pattern: /design|ui|ux|mockup|wireframe|prototype/i, iconName: 'Palette', color: 'text-purple-600' },
21
+
22
+ // Architecture & Structure
23
+ { pattern: /architecture|structure|system|diagram/i, iconName: 'Map', color: 'text-indigo-600' },
24
+
25
+ // Implementation & Code
26
+ { pattern: /implementation|code|develop|build/i, iconName: 'Code', color: 'text-green-600' },
27
+
28
+ // API & Integration
29
+ { pattern: /api|endpoint|integration|interface/i, iconName: 'Code', color: 'text-blue-600' },
30
+
31
+ // Testing & QA
32
+ { pattern: /test|qa|quality|validation/i, iconName: 'TestTube', color: 'text-orange-600' },
33
+
34
+ // Tasks & Project Management
35
+ { pattern: /task|todo|checklist|milestone/i, iconName: 'CheckSquare', color: 'text-gray-600' },
36
+
37
+ // Configuration & Setup
38
+ { pattern: /config|setup|settings|environment/i, iconName: 'Wrench', color: 'text-yellow-600' },
39
+
40
+ // Deployment & DevOps
41
+ { pattern: /deploy|devops|ci|cd|pipeline|release/i, iconName: 'Wrench', color: 'text-orange-600' },
42
+
43
+ // Migration & Updates
44
+ { pattern: /migration|upgrade|refactor|transition/i, iconName: 'GitBranch', color: 'text-cyan-600' },
45
+
46
+ // Security & Authentication
47
+ { pattern: /security|auth|permission|access|encryption/i, iconName: 'CheckSquare', color: 'text-red-600' },
48
+
49
+ // Performance & Optimization
50
+ { pattern: /performance|optimization|speed|cache|benchmark/i, iconName: 'TrendingUp', color: 'text-green-600' },
51
+
52
+ // Database & Data
53
+ { pattern: /database|data|schema|model|query/i, iconName: 'FileText', color: 'text-blue-600' },
54
+
55
+ // Documentation
56
+ { pattern: /doc|guide|manual|reference/i, iconName: 'FileText', color: 'text-gray-500' },
57
+
58
+ // GitHub & Git
59
+ { pattern: /github|git|vcs|version/i, iconName: 'GitBranch', color: 'text-pink-600' },
60
+ ];
61
+
62
+ // Default icon for unknown sub-spec types
63
+ const DEFAULT_ICON = { iconName: 'FileText', color: 'text-gray-600' };
64
+
65
+ /**
66
+ * Get icon and color for a sub-spec based on its name using regex patterns
67
+ */
68
+ function getIconForSubSpec(fileName: string): { iconName: string; color: string } {
69
+ // Remove .md extension
70
+ const baseName = fileName.replace(/\.md$/i, '');
71
+
72
+ // Try to match against patterns
73
+ for (const { pattern, iconName, color } of ICON_PATTERNS) {
74
+ if (pattern.test(baseName)) {
75
+ return { iconName, color };
76
+ }
77
+ }
78
+
79
+ return DEFAULT_ICON;
80
+ }
81
+
82
+ /**
83
+ * Convert filename to display name (e.g., "DESIGN.md" -> "Design")
84
+ */
85
+ function formatSubSpecName(fileName: string): string {
86
+ const baseName = fileName.replace(/\.md$/i, '');
87
+ // Convert to title case: "API-DESIGN" -> "Api Design", "TESTING" -> "Testing"
88
+ return baseName
89
+ .split(/[-_]/)
90
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
91
+ .join(' ');
92
+ }
93
+
94
+ /**
95
+ * Detect sub-spec files in a spec directory (dynamically finds all .md files except README.md)
96
+ */
97
+ export function detectSubSpecs(specDirPath: string): SubSpec[] {
98
+ const subSpecs: SubSpec[] = [];
99
+
100
+ if (!existsSync(specDirPath)) {
101
+ return subSpecs;
102
+ }
103
+
104
+ try {
105
+ const entries = readdirSync(specDirPath);
106
+
107
+ for (const entry of entries) {
108
+ // Skip README.md (main spec file), non-.md files, and directories
109
+ if (entry === 'README.md' || !entry.endsWith('.md')) {
110
+ continue;
111
+ }
112
+
113
+ const filePath = join(specDirPath, entry);
114
+ const stat = statSync(filePath);
115
+
116
+ // Skip directories
117
+ if (!stat.isFile()) {
118
+ continue;
119
+ }
120
+
121
+ try {
122
+ const content = readFileSync(filePath, 'utf-8');
123
+ // Remove frontmatter if present
124
+ const { content: markdownContent } = matter(content);
125
+ const iconConfig = getIconForSubSpec(entry);
126
+
127
+ subSpecs.push({
128
+ name: formatSubSpecName(entry),
129
+ file: entry,
130
+ iconName: iconConfig.iconName,
131
+ color: iconConfig.color,
132
+ content: markdownContent,
133
+ });
134
+ } catch (error) {
135
+ console.error(`Error reading sub-spec ${entry}:`, error);
136
+ }
137
+ }
138
+
139
+ // Sort alphabetically by filename for consistent ordering
140
+ subSpecs.sort((a, b) => a.file.localeCompare(b.file));
141
+ } catch (error) {
142
+ console.error(`Error reading spec directory ${specDirPath}:`, error);
143
+ }
144
+
145
+ return subSpecs;
146
+ }
147
+
148
+ /**
149
+ * Get sub-spec by name from a spec directory
150
+ */
151
+ export function getSubSpec(specDirPath: string, fileName: string): SubSpec | null {
152
+ const filePath = join(specDirPath, fileName);
153
+ if (!existsSync(filePath)) return null;
154
+
155
+ try {
156
+ const content = readFileSync(filePath, 'utf-8');
157
+ const { content: markdownContent } = matter(content);
158
+ const iconConfig = getIconForSubSpec(fileName);
159
+
160
+ return {
161
+ name: formatSubSpecName(fileName),
162
+ file: fileName,
163
+ iconName: iconConfig.iconName,
164
+ color: iconConfig.color,
165
+ content: markdownContent,
166
+ };
167
+ } catch (error) {
168
+ console.error(`Error reading sub-spec ${fileName}:`, error);
169
+ return null;
170
+ }
171
+ }
@@ -0,0 +1,17 @@
1
+ import { type ClassValue, clsx } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
7
+
8
+ /**
9
+ * Extract the first H1 heading from markdown content
10
+ */
11
+ export function extractH1Title(markdown: string): string | null {
12
+ if (!markdown) return null;
13
+
14
+ // Match first H1 heading (# Title)
15
+ const match = markdown.match(/^#\s+(.+)$/m);
16
+ return match ? match[1].trim() : null;
17
+ }
@@ -0,0 +1,18 @@
1
+ import type { ParsedSpec } from '@/lib/db/service-queries';
2
+ import type { SubSpec } from '@/lib/sub-specs';
3
+
4
+ export interface SpecRelationships {
5
+ dependsOn: string[];
6
+ related: string[];
7
+ requiredBy?: string[]; // Downstream dependents (specs that depend on this one)
8
+ }
9
+
10
+ export type SpecWithMetadata = ParsedSpec & {
11
+ subSpecs?: SubSpec[];
12
+ relationships?: SpecRelationships;
13
+ };
14
+
15
+ export type SidebarSpec = Pick<SpecWithMetadata, 'id' | 'specNumber' | 'title' | 'specName' | 'status' | 'priority' | 'contentMd' | 'updatedAt'> & {
16
+ tags: string[] | null;
17
+ subSpecsCount?: number;
18
+ };