@leanspec/ui 0.2.7 → 0.2.8
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.
- package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64 → @img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64}/README.md +2 -2
- package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64 → @img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64}/lib/glib-2.0/include/glibconfig.h +9 -8
- package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64/lib/libvips-cpp.8.17.3.dylib → @img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3} +0 -0
- package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64 → @img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64}/package.json +11 -5
- package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +46 -0
- 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 +221 -0
- package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +1 -0
- 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
- package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +42 -0
- package/.next/standalone/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@1.2.4/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +30 -0
- 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
- package/.next/standalone/node_modules/.pnpm/{@img+sharp-darwin-arm64@0.34.5/node_modules/@img/sharp-darwin-arm64 → @img+sharp-linux-x64@0.34.5/node_modules/@img/sharp-linux-x64}/package.json +13 -7
- 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
- package/.next/standalone/node_modules/.pnpm/@img+sharp-linuxmusl-x64@0.34.5/node_modules/@img/sharp-linuxmusl-x64/package.json +46 -0
- package/.next/standalone/node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
- package/.next/standalone/packages/ui/.next/BUILD_ID +1 -1
- package/.next/standalone/packages/ui/.next/app-path-routes-manifest.json +2 -0
- package/.next/standalone/packages/ui/.next/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/prerender-manifest.json +3 -3
- package/.next/standalone/packages/ui/.next/required-server-files.json +4 -4
- package/.next/standalone/packages/ui/.next/routes-manifest.json +12 -0
- package/.next/standalone/packages/ui/.next/server/app/_global-error.html +2 -2
- package/.next/standalone/packages/ui/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/packages/ui/.next/server/app/_not-found.rsc +18 -18
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_full.segment.rsc +18 -18
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_tree.segment.rsc +6 -6
- package/.next/standalone/packages/ui/.next/server/app/api/context/route/app-paths-manifest.json +3 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route/build-manifest.json +11 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route/server-reference-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route.js +8 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.map +5 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.nft.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route_client-reference-manifest.js +2 -0
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/context/page/app-paths-manifest.json +3 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/build-manifest.json +18 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/next-font-manifest.json +6 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/server-reference-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page.js +19 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page.js.map +5 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page.js.nft.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page_client-reference-manifest.js +2 -0
- package/.next/standalone/packages/ui/.next/server/app/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects.html +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects.rsc +12 -12
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/_full.segment.rsc +12 -12
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/_index.segment.rsc +9 -9
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/_tree.segment.rsc +3 -3
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/stats/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/stats/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/stats/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app-paths-manifest.json +2 -0
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__3559376c._.js +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__65667b70._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__803d07f0._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__84cdc14a._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8a9ab1a3._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bdc3963a._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__f5c6d6b8._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_context_route_actions_dead6daa.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__12b4eb41._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__69a0d63a._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__6e739186._.js +7 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a4c56419._.js +7 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__b6632d78._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__daee3355._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__5382b397._.js → [root-of-the-server]__ead1539c._.js} +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_000dd317._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_0f9ffe32._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_28fe1532._.js +5 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_315f3b3a._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_959ad3d8._.js +4 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_9dcf102b._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/{_497c8b73._.js → _b397e94a._.js} +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_8272a49c._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_context_page_actions_1a062d48.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_context_context-client_tsx_4ba99a62._.js +12 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_specs_specs-client_tsx_0bb8f8f8._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_specs-nav-sidebar_tsx_8237ed13._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/pages/404.html +2 -2
- package/.next/standalone/packages/ui/.next/server/pages/500.html +2 -2
- package/.next/standalone/packages/ui/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/packages/ui/.next/static/chunks/1eb8283995f370c6.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/336e8e8fc6b0fba8.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/37a1236ed50645a6.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/9d84ba08a41145ec.js +5 -0
- package/.next/standalone/packages/ui/.next/static/chunks/c4b1faff3361a749.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/{294dea6dbec43ca6.js → d7420d2a867e57b5.js} +1 -1
- package/.next/{static/chunks/cca4441cde342ae3.js → standalone/packages/ui/.next/static/chunks/dae403679aae65f4.js} +1 -1
- package/.next/standalone/packages/ui/.next/static/chunks/efded9da04c960d8.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/f382932f1a5d6359.js +10 -0
- package/.next/standalone/packages/ui/.next/static/chunks/f43b6e43b4da1a32.css +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/f6dd06e6d22d2d12.js +3 -0
- package/.next/standalone/packages/ui/dist/BUILD_ID +1 -0
- package/.next/standalone/packages/ui/dist/standalone/packages/web/package.json +1 -9
- package/.next/standalone/packages/ui/dist/standalone/packages/web/server.js +1 -1
- package/.next/standalone/packages/ui/dist/standalone/specs/035-live-specs-showcase/README.md +3 -7
- package/.next/standalone/packages/ui/dist/standalone/specs/072-ai-agent-first-use-workflow/README.md +3 -5
- package/.next/standalone/packages/ui/dist/standalone/specs/081-web-app-ux-redesign/README.md +1 -2
- package/.next/standalone/packages/ui/dist/standalone/specs/082-web-realtime-sync-architecture/README.md +3 -8
- package/.next/standalone/packages/ui/dist/standalone/specs/087-cli-ui-command/README.md +259 -73
- package/.next/standalone/packages/ui/dist/standalone/specs/088-core-concepts-terminology-only/README.md +3 -5
- package/.next/standalone/packages/ui/dist/standalone/specs/089-sdd-practical-tutorials/README.md +3 -5
- package/.next/standalone/packages/ui/dist/standalone/specs/090-leanspec-sdd-case-studies/README.md +3 -5
- package/.next/standalone/packages/ui/dist/standalone/specs/091-chinese-localization-strategy/README.md +23 -33
- package/.next/standalone/packages/ui/dist/standalone/specs/092-docs-site-submodule-migration/README.md +3 -7
- package/.next/standalone/packages/ui/dist/standalone/specs/093-spec-detail-ui-improvements/README.md +14 -25
- package/.next/standalone/packages/ui/dist/static/chunks/0c19c69aa7625475.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/116800b03245a1e5.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/15843a3d7584e314.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/19e80edf527aef5c.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/465954d5af3284a9.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/5abeeb89f1412a80.js +3 -0
- package/.next/standalone/packages/ui/dist/static/chunks/5c2072ad938de8ed.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/6a05a93ec8fa7b83.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/778e42188e450b39.css +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/a02c1f50ff00204f.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/a45464b9776dd88e.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/a6dad97d9634a72d.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/b0ea0ac61604f843.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/c06e85b449720194.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/c557ac675be79771.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/cad005a57ffbb2d3.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/cdf6fe33bc65efbc.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/d12ed5dbe44caed7.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/d1ebe5c1a344f4ca.js +5 -0
- package/.next/standalone/packages/ui/dist/static/chunks/d42cf1682bc46652.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/dde5d8bddd7fbfcf.js +1 -0
- package/.next/standalone/packages/ui/dist/static/chunks/ebd89051637b9a47.js +4 -0
- package/.next/standalone/packages/ui/dist/static/chunks/ec82875d18b29f47.js +2 -0
- package/.next/standalone/packages/ui/dist/static/chunks/f0b701df9769bcc5.js +19 -0
- package/.next/standalone/packages/ui/dist/static/chunks/turbopack-1c09a99f4c9e28d3.js +3 -0
- package/.next/standalone/packages/ui/package.json +3 -1
- package/.next/standalone/packages/ui/server.js +1 -1
- package/.next/standalone/packages/ui/src/app/api/context/route.ts +22 -0
- package/.next/standalone/packages/ui/src/app/context/context-client.tsx +371 -0
- package/.next/standalone/packages/ui/src/app/context/page.tsx +17 -0
- package/.next/standalone/packages/ui/src/app/globals.css +16 -16
- package/.next/standalone/packages/ui/src/app/layout.tsx +4 -7
- package/.next/standalone/packages/ui/src/components/context-file-viewer.tsx +291 -0
- package/.next/standalone/packages/ui/src/components/main-sidebar.tsx +10 -1
- package/.next/standalone/packages/ui/src/components/spec-detail-client.tsx +181 -134
- package/.next/standalone/packages/ui/src/components/spec-detail-wrapper.tsx +20 -0
- package/.next/standalone/packages/ui/src/components/specs-nav-sidebar.tsx +3 -2
- package/.next/standalone/packages/ui/src/components/ui/accordion.tsx +58 -0
- package/.next/standalone/packages/ui/src/lib/db/service-queries.ts +172 -3
- package/.next/standalone/packages/ui/src/lib/specs/types.ts +44 -0
- package/.next/standalone/packages/ui/tsconfig.tsbuildinfo +1 -1
- package/.next/static/-Mn9iD4O5f_khGd1P3kmB/_buildManifest.js +11 -0
- package/.next/static/-Mn9iD4O5f_khGd1P3kmB/_clientMiddlewareManifest.json +1 -0
- package/.next/static/-Mn9iD4O5f_khGd1P3kmB/_ssgManifest.js +1 -0
- package/.next/static/chunks/1eb8283995f370c6.js +1 -0
- package/.next/static/chunks/336e8e8fc6b0fba8.js +1 -0
- package/.next/static/chunks/37a1236ed50645a6.js +1 -0
- package/.next/static/chunks/9d84ba08a41145ec.js +5 -0
- package/.next/static/chunks/c4b1faff3361a749.js +1 -0
- package/.next/static/chunks/{294dea6dbec43ca6.js → d7420d2a867e57b5.js} +1 -1
- package/.next/{standalone/packages/ui/.next/static/chunks/cca4441cde342ae3.js → static/chunks/dae403679aae65f4.js} +1 -1
- package/.next/static/chunks/efded9da04c960d8.js +1 -0
- package/.next/static/chunks/f382932f1a5d6359.js +10 -0
- package/.next/static/chunks/f43b6e43b4da1a32.css +1 -0
- package/.next/static/chunks/f6dd06e6d22d2d12.js +3 -0
- package/package.json +4 -2
- 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
- package/.next/standalone/node_modules/.pnpm/source-map@0.8.0-beta.0/node_modules/source-map/package.json +0 -95
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__1d0c2012._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__73f60f12._.js +0 -7
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a7ae8552._.js +0 -7
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_14118969._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_4129cc0f._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_c2f54661._.js +0 -5
- package/.next/standalone/packages/ui/.next/static/chunks/16ff9833ae1bb3ae.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/2204c0f16b23ec4c.js +0 -3
- package/.next/standalone/packages/ui/.next/static/chunks/7590e65bcaa41e8b.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/b6976cf6c48996e5.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/b845813463167db0.js +0 -5
- package/.next/standalone/packages/ui/.next/static/chunks/bd9893e28f8f6a9a.css +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/d784d84d5b880e48.js +0 -1
- package/.next/standalone/packages/ui/dist/standalone/packages/web/components.json +0 -20
- package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/0000_reflective_thena.sql +0 -59
- package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/0001_fresh_carmella_unuscione.sql +0 -1
- package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/meta/0000_snapshot.json +0 -427
- package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/meta/0001_snapshot.json +0 -436
- package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle/meta/_journal.json +0 -20
- package/.next/standalone/packages/ui/dist/standalone/packages/web/drizzle.config.ts +0 -10
- package/.next/standalone/packages/ui/dist/standalone/packages/web/eslint.config.mjs +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/next.config.ts +0 -7
- package/.next/standalone/packages/ui/dist/standalone/packages/web/postcss.config.mjs +0 -8
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/projects/[id]/specs/route.ts +0 -23
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/projects/route.ts +0 -19
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/revalidate/route.ts +0 -63
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/dependency-graph/route.test.ts +0 -51
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/dependency-graph/route.ts +0 -171
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/route.ts +0 -36
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/specs/[id]/subspecs/[file]/route.ts +0 -46
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/api/stats/route.ts +0 -19
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/board/board-client.tsx +0 -162
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/board/loading.tsx +0 -43
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/board/page.tsx +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/dashboard-client.tsx +0 -364
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/error.tsx +0 -43
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/globals.css +0 -531
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/home-client.tsx +0 -277
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/layout.tsx +0 -70
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/loading.tsx +0 -87
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/not-found.tsx +0 -27
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/page.tsx +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/[id]/loading.tsx +0 -5
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/[id]/page.tsx +0 -43
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/page.tsx +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/specs/specs-client.tsx +0 -425
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/stats/page.tsx +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/app/stats/stats-client.tsx +0 -283
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/back-to-top.tsx +0 -46
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/empty-state.tsx +0 -52
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/main-sidebar.tsx +0 -175
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/markdown-link.test.ts +0 -96
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/markdown-link.tsx +0 -95
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/navigation.tsx +0 -210
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/priority-badge.tsx +0 -53
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/quick-search.tsx +0 -180
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/skeletons.tsx +0 -119
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-dependency-graph.tsx +0 -369
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-detail-client.tsx +0 -372
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-detail-loading-shell.tsx +0 -42
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-detail-wrapper.tsx +0 -70
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-metadata.tsx +0 -136
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-sidebar.tsx +0 -127
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/spec-timeline.tsx +0 -186
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/specs-nav-sidebar.tsx +0 -561
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/status-badge.tsx +0 -53
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/sub-spec-tabs.tsx +0 -143
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/table-of-contents.tsx +0 -130
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/theme-provider.tsx +0 -11
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/theme-toggle.tsx +0 -37
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/avatar.tsx +0 -50
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/badge.tsx +0 -36
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/breadcrumb.tsx +0 -110
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/button.tsx +0 -57
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/card.tsx +0 -76
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/command.tsx +0 -153
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/dialog.tsx +0 -122
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/input.tsx +0 -24
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/select.tsx +0 -159
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/separator.tsx +0 -31
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/skeleton.tsx +0 -15
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/tabs.tsx +0 -55
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/toast.tsx +0 -30
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/components/ui/tooltip.tsx +0 -32
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/date-utils.ts +0 -76
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/index.ts +0 -42
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/migrate.ts +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/queries.ts +0 -114
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/schema.ts +0 -123
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/seed.ts +0 -156
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/db/service-queries.ts +0 -216
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/dependency-graph.ts +0 -105
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/service.ts +0 -120
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/sources/database-source.ts +0 -94
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/sources/filesystem-source.ts +0 -249
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/specs/types.ts +0 -55
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/stores/specs-sidebar-store.ts +0 -152
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/sub-specs.ts +0 -171
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/lib/utils.ts +0 -17
- package/.next/standalone/packages/ui/dist/standalone/packages/web/src/types/specs.ts +0 -18
- package/.next/standalone/packages/ui/dist/standalone/packages/web/tailwind.config.ts +0 -58
- package/.next/standalone/packages/ui/dist/standalone/packages/web/tsconfig.json +0 -34
- package/.next/standalone/packages/ui/dist/standalone/packages/web/tsconfig.tsbuildinfo +0 -1
- package/.next/standalone/packages/ui/dist/standalone/packages/web/vitest.config.ts +0 -14
- package/.next/standalone/packages/ui/dist/standalone/specs/094-ai-chatbot-web-integration/README.md +0 -332
- package/.next/standalone/packages/ui/dist/standalone/specs/095-pr-migration-verification/README.md +0 -339
- package/.next/standalone/packages/ui/dist/standalone/specs/096-docs-beginner-first-reorg/README.md +0 -399
- package/.next/standalone/packages/ui/dist/standalone/specs/097-dag-visualization-library/README.md +0 -525
- package/.next/standalone/packages/ui/dist/standalone/specs/098-github-multi-project-integration/README.md +0 -387
- package/.next/standalone/packages/ui/dist/standalone/specs/099-enhanced-dependency-commands-cli-mcp/README.md +0 -613
- package/.next/standalone/packages/ui/dist/standalone/specs/100-release-process-typecheck-failure/README.md +0 -266
- package/.next/standalone/packages/ui/dist/standalone/specs/101-sidebar-scroll-position-drift/README.md +0 -100
- package/.next/standalone/packages/ui/dist/standalone/specs/102-mcp-wrapper-package/README.md +0 -172
- package/.next/static/chunks/16ff9833ae1bb3ae.js +0 -1
- package/.next/static/chunks/2204c0f16b23ec4c.js +0 -3
- package/.next/static/chunks/7590e65bcaa41e8b.js +0 -1
- package/.next/static/chunks/b6976cf6c48996e5.js +0 -1
- package/.next/static/chunks/b845813463167db0.js +0 -5
- package/.next/static/chunks/bd9893e28f8f6a9a.css +0 -1
- package/.next/static/chunks/d784d84d5b880e48.js +0 -1
- /package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64 → @img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64}/lib/index.js +0 -0
- /package/.next/standalone/node_modules/.pnpm/{@img+sharp-libvips-darwin-arm64@1.2.4/node_modules/@img/sharp-libvips-darwin-arm64 → @img+sharp-libvips-linux-x64@1.2.4/node_modules/@img/sharp-libvips-linux-x64}/versions.json +0 -0
- /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → -Mn9iD4O5f_khGd1P3kmB}/_buildManifest.js +0 -0
- /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → -Mn9iD4O5f_khGd1P3kmB}/_clientMiddlewareManifest.json +0 -0
- /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → -Mn9iD4O5f_khGd1P3kmB}/_ssgManifest.js +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/f864aa7e7061c0600e35cf3d879b27cf.txt +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/favicon.ico +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/file.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/github-mark-white.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/github-mark.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/globe.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/icon.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/logo-dark-bg.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/logo-with-bg.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/logo.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/next.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/vercel.svg +0 -0
- /package/.next/standalone/packages/ui/dist/{standalone/packages/web/public → public}/window.svg +0 -0
- /package/.next/{static/6nq7WNafPv5Bf_7mWgRQ- → standalone/packages/ui/dist/static/4ZnYN1WbN4LGJQOwP6FkT}/_buildManifest.js +0 -0
- /package/.next/{static/6nq7WNafPv5Bf_7mWgRQ- → standalone/packages/ui/dist/static/4ZnYN1WbN4LGJQOwP6FkT}/_clientMiddlewareManifest.json +0 -0
- /package/.next/{static/6nq7WNafPv5Bf_7mWgRQ- → standalone/packages/ui/dist/static/4ZnYN1WbN4LGJQOwP6FkT}/_ssgManifest.js +0 -0
|
@@ -1,249 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,152 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,171 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
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
|
-
};
|