@leanspec/ui 0.2.3 → 0.2.4

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 (187) hide show
  1. package/dist/standalone/packages/web/.next/BUILD_ID +1 -1
  2. package/dist/standalone/packages/web/.next/build-manifest.json +2 -2
  3. package/dist/standalone/packages/web/.next/prerender-manifest.json +3 -3
  4. package/dist/standalone/packages/web/.next/server/app/_global-error.html +2 -2
  5. package/dist/standalone/packages/web/.next/server/app/_global-error.rsc +1 -1
  6. package/dist/standalone/packages/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/dist/standalone/packages/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/dist/standalone/packages/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/dist/standalone/packages/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/dist/standalone/packages/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  11. package/dist/standalone/packages/web/.next/server/app/_not-found.html +2 -2
  12. package/dist/standalone/packages/web/.next/server/app/_not-found.rsc +2 -2
  13. package/dist/standalone/packages/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  14. package/dist/standalone/packages/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  15. package/dist/standalone/packages/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  16. package/dist/standalone/packages/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  17. package/dist/standalone/packages/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  18. package/dist/standalone/packages/web/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
  19. package/dist/standalone/packages/web/.next/server/app/api/projects/route.js.nft.json +1 -1
  20. package/dist/standalone/packages/web/.next/server/app/api/revalidate/route.js.nft.json +1 -1
  21. package/dist/standalone/packages/web/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
  22. package/dist/standalone/packages/web/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
  23. package/dist/standalone/packages/web/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
  24. package/dist/standalone/packages/web/.next/server/app/api/stats/route.js.nft.json +1 -1
  25. package/dist/standalone/packages/web/.next/server/app/board/page.js.nft.json +1 -1
  26. package/dist/standalone/packages/web/.next/server/app/board.html +1 -1
  27. package/dist/standalone/packages/web/.next/server/app/board.rsc +2 -2
  28. package/dist/standalone/packages/web/.next/server/app/board.segments/_full.segment.rsc +2 -2
  29. package/dist/standalone/packages/web/.next/server/app/board.segments/_index.segment.rsc +1 -1
  30. package/dist/standalone/packages/web/.next/server/app/board.segments/_tree.segment.rsc +1 -1
  31. package/dist/standalone/packages/web/.next/server/app/board.segments/board/__PAGE__.segment.rsc +1 -1
  32. package/dist/standalone/packages/web/.next/server/app/board.segments/board.segment.rsc +1 -1
  33. package/dist/standalone/packages/web/.next/server/app/page.js.nft.json +1 -1
  34. package/dist/standalone/packages/web/.next/server/app/specs/[id]/page.js.nft.json +1 -1
  35. package/dist/standalone/packages/web/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
  36. package/dist/standalone/packages/web/.next/server/app/specs/page.js.nft.json +1 -1
  37. package/dist/standalone/packages/web/.next/server/app/stats/page.js.nft.json +1 -1
  38. package/dist/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2e0f9179._.js +1 -1
  39. package/dist/standalone/packages/web/.next/server/chunks/[root-of-the-server]__577d6d08._.js +1 -1
  40. package/dist/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e54bc4b8._.js +1 -1
  41. package/dist/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f8978f3e._.js +1 -1
  42. package/dist/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__be46bb7c._.js +1 -1
  43. package/dist/standalone/packages/web/.next/server/chunks/ssr/_7dedc302._.js +1 -1
  44. package/dist/standalone/packages/web/.next/server/chunks/ssr/_ad71cd8c._.js +1 -1
  45. package/dist/standalone/packages/web/.next/server/chunks/ssr/_c5a5c652._.js +1 -1
  46. package/dist/standalone/packages/web/.next/server/pages/404.html +2 -2
  47. package/dist/standalone/packages/web/.next/server/pages/500.html +2 -2
  48. package/dist/standalone/packages/web/.next/server/server-reference-manifest.js +1 -1
  49. package/dist/standalone/packages/web/.next/server/server-reference-manifest.json +1 -1
  50. package/dist/{static/chunks/0de258404bcae76f.js → standalone/packages/web/.next/static/chunks/8864b47e107cbe63.js} +1 -1
  51. package/dist/{static/chunks/09ff02250dd56621.js → standalone/packages/web/.next/static/chunks/a2889ecda42c83e7.js} +1 -1
  52. package/dist/standalone/packages/web/.next/static/chunks/c22619397bb8368e.js +1 -0
  53. package/dist/standalone/packages/web/components.json +20 -0
  54. package/dist/standalone/packages/web/drizzle/0000_reflective_thena.sql +59 -0
  55. package/dist/standalone/packages/web/drizzle/0001_fresh_carmella_unuscione.sql +1 -0
  56. package/dist/standalone/packages/web/drizzle/meta/0000_snapshot.json +427 -0
  57. package/dist/standalone/packages/web/drizzle/meta/0001_snapshot.json +436 -0
  58. package/dist/standalone/packages/web/drizzle/meta/_journal.json +20 -0
  59. package/dist/standalone/packages/web/drizzle.config.ts +10 -0
  60. package/dist/standalone/packages/web/eslint.config.mjs +18 -0
  61. package/dist/standalone/packages/web/next.config.ts +7 -0
  62. package/dist/standalone/packages/web/package.json +1 -1
  63. package/dist/standalone/packages/web/postcss.config.mjs +8 -0
  64. package/dist/standalone/packages/web/src/app/api/projects/[id]/specs/route.ts +23 -0
  65. package/dist/standalone/packages/web/src/app/api/projects/route.ts +19 -0
  66. package/dist/standalone/packages/web/src/app/api/revalidate/route.ts +63 -0
  67. package/dist/standalone/packages/web/src/app/api/specs/[id]/dependency-graph/route.test.ts +51 -0
  68. package/dist/standalone/packages/web/src/app/api/specs/[id]/dependency-graph/route.ts +171 -0
  69. package/dist/standalone/packages/web/src/app/api/specs/[id]/route.ts +36 -0
  70. package/dist/standalone/packages/web/src/app/api/specs/[id]/subspecs/[file]/route.ts +46 -0
  71. package/dist/standalone/packages/web/src/app/api/stats/route.ts +19 -0
  72. package/dist/standalone/packages/web/src/app/board/board-client.tsx +162 -0
  73. package/dist/standalone/packages/web/src/app/board/loading.tsx +43 -0
  74. package/dist/standalone/packages/web/src/app/board/page.tsx +18 -0
  75. package/dist/standalone/packages/web/src/app/dashboard-client.tsx +364 -0
  76. package/dist/standalone/packages/web/src/app/error.tsx +43 -0
  77. package/dist/standalone/packages/web/src/app/globals.css +531 -0
  78. package/dist/standalone/packages/web/src/app/home-client.tsx +277 -0
  79. package/dist/standalone/packages/web/src/app/layout.tsx +70 -0
  80. package/dist/standalone/packages/web/src/app/loading.tsx +87 -0
  81. package/dist/standalone/packages/web/src/app/not-found.tsx +27 -0
  82. package/dist/standalone/packages/web/src/app/page.tsx +18 -0
  83. package/dist/standalone/packages/web/src/app/specs/[id]/loading.tsx +5 -0
  84. package/dist/standalone/packages/web/src/app/specs/[id]/page.tsx +43 -0
  85. package/dist/standalone/packages/web/src/app/specs/page.tsx +18 -0
  86. package/dist/standalone/packages/web/src/app/specs/specs-client.tsx +425 -0
  87. package/dist/standalone/packages/web/src/app/stats/page.tsx +18 -0
  88. package/dist/standalone/packages/web/src/app/stats/stats-client.tsx +283 -0
  89. package/dist/standalone/packages/web/src/components/back-to-top.tsx +46 -0
  90. package/dist/standalone/packages/web/src/components/empty-state.tsx +52 -0
  91. package/dist/standalone/packages/web/src/components/main-sidebar.tsx +175 -0
  92. package/dist/standalone/packages/web/src/components/markdown-link.test.ts +96 -0
  93. package/dist/standalone/packages/web/src/components/markdown-link.tsx +95 -0
  94. package/dist/standalone/packages/web/src/components/navigation.tsx +210 -0
  95. package/dist/standalone/packages/web/src/components/priority-badge.tsx +53 -0
  96. package/dist/standalone/packages/web/src/components/quick-search.tsx +180 -0
  97. package/dist/standalone/packages/web/src/components/skeletons.tsx +119 -0
  98. package/dist/standalone/packages/web/src/components/spec-dependency-graph.tsx +369 -0
  99. package/dist/standalone/packages/web/src/components/spec-detail-client.tsx +372 -0
  100. package/dist/standalone/packages/web/src/components/spec-detail-loading-shell.tsx +42 -0
  101. package/dist/standalone/packages/web/src/components/spec-detail-wrapper.tsx +70 -0
  102. package/dist/standalone/packages/web/src/components/spec-metadata.tsx +136 -0
  103. package/dist/standalone/packages/web/src/components/spec-sidebar.tsx +127 -0
  104. package/dist/standalone/packages/web/src/components/spec-timeline.tsx +186 -0
  105. package/dist/standalone/packages/web/src/components/specs-nav-sidebar.tsx +561 -0
  106. package/dist/standalone/packages/web/src/components/status-badge.tsx +53 -0
  107. package/dist/standalone/packages/web/src/components/sub-spec-tabs.tsx +143 -0
  108. package/dist/standalone/packages/web/src/components/table-of-contents.tsx +130 -0
  109. package/dist/standalone/packages/web/src/components/theme-provider.tsx +11 -0
  110. package/dist/standalone/packages/web/src/components/theme-toggle.tsx +37 -0
  111. package/dist/standalone/packages/web/src/components/ui/avatar.tsx +50 -0
  112. package/dist/standalone/packages/web/src/components/ui/badge.tsx +36 -0
  113. package/dist/standalone/packages/web/src/components/ui/breadcrumb.tsx +110 -0
  114. package/dist/standalone/packages/web/src/components/ui/button.tsx +57 -0
  115. package/dist/standalone/packages/web/src/components/ui/card.tsx +76 -0
  116. package/dist/standalone/packages/web/src/components/ui/command.tsx +153 -0
  117. package/dist/standalone/packages/web/src/components/ui/dialog.tsx +122 -0
  118. package/dist/standalone/packages/web/src/components/ui/input.tsx +24 -0
  119. package/dist/standalone/packages/web/src/components/ui/select.tsx +159 -0
  120. package/dist/standalone/packages/web/src/components/ui/separator.tsx +31 -0
  121. package/dist/standalone/packages/web/src/components/ui/skeleton.tsx +15 -0
  122. package/dist/standalone/packages/web/src/components/ui/tabs.tsx +55 -0
  123. package/dist/standalone/packages/web/src/components/ui/toast.tsx +30 -0
  124. package/dist/standalone/packages/web/src/components/ui/tooltip.tsx +32 -0
  125. package/dist/standalone/packages/web/src/lib/date-utils.ts +76 -0
  126. package/dist/standalone/packages/web/src/lib/db/index.ts +42 -0
  127. package/dist/standalone/packages/web/src/lib/db/migrate.ts +18 -0
  128. package/dist/standalone/packages/web/src/lib/db/queries.ts +114 -0
  129. package/dist/standalone/packages/web/src/lib/db/schema.ts +123 -0
  130. package/dist/standalone/packages/web/src/lib/db/seed.ts +156 -0
  131. package/dist/standalone/packages/web/src/lib/db/service-queries.ts +216 -0
  132. package/dist/standalone/packages/web/src/lib/dependency-graph.ts +105 -0
  133. package/dist/standalone/packages/web/src/lib/specs/service.ts +120 -0
  134. package/dist/standalone/packages/web/src/lib/specs/sources/database-source.ts +94 -0
  135. package/dist/standalone/packages/web/src/lib/specs/sources/filesystem-source.ts +249 -0
  136. package/dist/standalone/packages/web/src/lib/specs/types.ts +55 -0
  137. package/dist/standalone/packages/web/src/lib/stores/specs-sidebar-store.ts +152 -0
  138. package/dist/standalone/packages/web/src/lib/sub-specs.ts +171 -0
  139. package/dist/standalone/packages/web/src/lib/utils.ts +17 -0
  140. package/dist/standalone/packages/web/src/types/specs.ts +18 -0
  141. package/dist/standalone/packages/web/tailwind.config.ts +58 -0
  142. package/dist/standalone/packages/web/tsconfig.json +34 -0
  143. package/dist/standalone/packages/web/vitest.config.ts +14 -0
  144. package/dist/standalone/specs/100-release-process-typecheck-failure/README.md +266 -0
  145. package/dist/standalone/specs/101-sidebar-scroll-position-drift/README.md +100 -0
  146. package/package.json +5 -3
  147. package/dist/BUILD_ID +0 -1
  148. package/dist/static/chunks/a3e649fcddd3d715.js +0 -1
  149. /package/dist/{static/Z_BxkB0KJViCNbULN1S5p → standalone/packages/web/.next/static/DDHAmoL_2Poji-whvFjry}/_buildManifest.js +0 -0
  150. /package/dist/{static/Z_BxkB0KJViCNbULN1S5p → standalone/packages/web/.next/static/DDHAmoL_2Poji-whvFjry}/_clientMiddlewareManifest.json +0 -0
  151. /package/dist/{static/Z_BxkB0KJViCNbULN1S5p → standalone/packages/web/.next/static/DDHAmoL_2Poji-whvFjry}/_ssgManifest.js +0 -0
  152. /package/dist/{static → standalone/packages/web/.next/static}/chunks/0c19c69aa7625475.js +0 -0
  153. /package/dist/{static → standalone/packages/web/.next/static}/chunks/116800b03245a1e5.js +0 -0
  154. /package/dist/{static → standalone/packages/web/.next/static}/chunks/19e80edf527aef5c.js +0 -0
  155. /package/dist/{static → standalone/packages/web/.next/static}/chunks/2ece90370908f56c.js +0 -0
  156. /package/dist/{static → standalone/packages/web/.next/static}/chunks/36fd2dddb486f6bc.js +0 -0
  157. /package/dist/{static → standalone/packages/web/.next/static}/chunks/5c2072ad938de8ed.js +0 -0
  158. /package/dist/{static → standalone/packages/web/.next/static}/chunks/6577fe797a336bab.js +0 -0
  159. /package/dist/{static → standalone/packages/web/.next/static}/chunks/6a05a93ec8fa7b83.js +0 -0
  160. /package/dist/{static → standalone/packages/web/.next/static}/chunks/7f732ea69e643219.js +0 -0
  161. /package/dist/{static → standalone/packages/web/.next/static}/chunks/a02c1f50ff00204f.js +0 -0
  162. /package/dist/{static → standalone/packages/web/.next/static}/chunks/a45464b9776dd88e.js +0 -0
  163. /package/dist/{static → standalone/packages/web/.next/static}/chunks/a6dad97d9634a72d.js +0 -0
  164. /package/dist/{static → standalone/packages/web/.next/static}/chunks/ae04dcd433be6dab.js +0 -0
  165. /package/dist/{static → standalone/packages/web/.next/static}/chunks/b20313408e970968.css +0 -0
  166. /package/dist/{static → standalone/packages/web/.next/static}/chunks/c46095e1a421d93f.js +0 -0
  167. /package/dist/{static → standalone/packages/web/.next/static}/chunks/c48dd4c72d7c5ef4.js +0 -0
  168. /package/dist/{static → standalone/packages/web/.next/static}/chunks/c557ac675be79771.js +0 -0
  169. /package/dist/{static → standalone/packages/web/.next/static}/chunks/dca0c854c59234cd.js +0 -0
  170. /package/dist/{static → standalone/packages/web/.next/static}/chunks/df1731c03abf1aee.css +0 -0
  171. /package/dist/{static → standalone/packages/web/.next/static}/chunks/dfd41488ad062cd5.js +0 -0
  172. /package/dist/{static → standalone/packages/web/.next/static}/chunks/ebd89051637b9a47.js +0 -0
  173. /package/dist/{static → standalone/packages/web/.next/static}/chunks/f3ec9fd77a8618b1.js +0 -0
  174. /package/dist/{static → standalone/packages/web/.next/static}/chunks/turbopack-7450632b40b2e378.js +0 -0
  175. /package/dist/{public → standalone/packages/web/public}/f864aa7e7061c0600e35cf3d879b27cf.txt +0 -0
  176. /package/dist/{public → standalone/packages/web/public}/favicon.ico +0 -0
  177. /package/dist/{public → standalone/packages/web/public}/file.svg +0 -0
  178. /package/dist/{public → standalone/packages/web/public}/github-mark-white.svg +0 -0
  179. /package/dist/{public → standalone/packages/web/public}/github-mark.svg +0 -0
  180. /package/dist/{public → standalone/packages/web/public}/globe.svg +0 -0
  181. /package/dist/{public → standalone/packages/web/public}/icon.svg +0 -0
  182. /package/dist/{public → standalone/packages/web/public}/logo-dark-bg.svg +0 -0
  183. /package/dist/{public → standalone/packages/web/public}/logo-with-bg.svg +0 -0
  184. /package/dist/{public → standalone/packages/web/public}/logo.svg +0 -0
  185. /package/dist/{public → standalone/packages/web/public}/next.svg +0 -0
  186. /package/dist/{public → standalone/packages/web/public}/vercel.svg +0 -0
  187. /package/dist/{public → standalone/packages/web/public}/window.svg +0 -0
@@ -0,0 +1,58 @@
1
+ import type { Config } from "tailwindcss";
2
+ import typography from "@tailwindcss/typography";
3
+
4
+ const config: Config = {
5
+ darkMode: "class",
6
+ content: [
7
+ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
8
+ "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
9
+ "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
10
+ ],
11
+ theme: {
12
+ extend: {
13
+ colors: {
14
+ background: "hsl(var(--background))",
15
+ foreground: "hsl(var(--foreground))",
16
+ card: {
17
+ DEFAULT: "hsl(var(--card))",
18
+ foreground: "hsl(var(--card-foreground))",
19
+ },
20
+ popover: {
21
+ DEFAULT: "hsl(var(--popover))",
22
+ foreground: "hsl(var(--popover-foreground))",
23
+ },
24
+ primary: {
25
+ DEFAULT: "hsl(var(--primary))",
26
+ foreground: "hsl(var(--primary-foreground))",
27
+ },
28
+ secondary: {
29
+ DEFAULT: "hsl(var(--secondary))",
30
+ foreground: "hsl(var(--secondary-foreground))",
31
+ },
32
+ muted: {
33
+ DEFAULT: "hsl(var(--muted))",
34
+ foreground: "hsl(var(--muted-foreground))",
35
+ },
36
+ accent: {
37
+ DEFAULT: "hsl(var(--accent))",
38
+ foreground: "hsl(var(--accent-foreground))",
39
+ },
40
+ destructive: {
41
+ DEFAULT: "hsl(var(--destructive))",
42
+ foreground: "hsl(var(--destructive-foreground))",
43
+ },
44
+ border: "hsl(var(--border))",
45
+ input: "hsl(var(--input))",
46
+ ring: "hsl(var(--ring))",
47
+ },
48
+ borderRadius: {
49
+ lg: "var(--radius)",
50
+ md: "calc(var(--radius) - 2px)",
51
+ sm: "calc(var(--radius) - 4px)",
52
+ },
53
+ },
54
+ },
55
+ plugins: [typography],
56
+ };
57
+
58
+ export default config;
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import path from 'path';
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ globals: true,
7
+ environment: 'node',
8
+ },
9
+ resolve: {
10
+ alias: {
11
+ '@': path.resolve(__dirname, './src'),
12
+ },
13
+ },
14
+ });
@@ -0,0 +1,266 @@
1
+ ---
2
+ status: complete
3
+ created: '2025-11-17'
4
+ tags:
5
+ - process
6
+ - quality
7
+ - ci-cd
8
+ - post-mortem
9
+ priority: high
10
+ created_at: '2025-11-17T21:12:06.305Z'
11
+ completed_at: '2025-11-17T21:12:00.000Z'
12
+ updated_at: '2025-11-17T13:13:28.300Z'
13
+ completed: '2025-11-17'
14
+ ---
15
+
16
+ # Post-Mortem: v0.2.3 TypeScript Check Failure
17
+
18
+ ## Overview
19
+
20
+ On November 17, 2025, we attempted to release v0.2.3 only to discover **30+ TypeScript compilation errors** that should have been caught before the release process began. This spec documents what went wrong, why it happened, and how to prevent it in the future.
21
+
22
+ **Impact**: Blocked release, required emergency fix session, wasted development time, damaged trust in release process.
23
+
24
+ ## What Went Wrong
25
+
26
+ ### The Problem
27
+ Version 0.2.3 was tagged and released without running `pnpm typecheck`, leading to a published package that:
28
+ - Failed TypeScript compilation (`tsc --noEmit` showed 30+ errors)
29
+ - Had broken MCP SDK integration (signature mismatches)
30
+ - Had type mismatches across packages (core vs CLI)
31
+ - Would break for users with strict TypeScript checking
32
+
33
+ ### Root Causes
34
+
35
+ 1. **No Pre-Release Type Check**
36
+ - Release process did NOT include `pnpm typecheck` as a required step
37
+ - Only ran `pnpm build` which uses `tsup` with less strict checking
38
+ - `tsup` successfully bundles code even with type errors when `noCheck: true` or similar flags
39
+
40
+ 2. **No CI/CD Type Checking**
41
+ - GitHub Actions publish workflow (`.github/workflows/publish.yml`) does NOT run `pnpm typecheck`
42
+ - Only runs `pnpm build` before publishing
43
+ - No gate preventing broken releases
44
+
45
+ 3. **Monorepo Complexity**
46
+ - Errors were spread across CLI and Core packages
47
+ - Cross-package type dependencies not validated
48
+ - Core package exported types used in CLI weren't properly exposed
49
+
50
+ 4. **MCP SDK Version Upgrade**
51
+ - SDK v1.21.0 changed handler signatures (added `extra` parameter)
52
+ - No automated check for SDK compatibility
53
+ - Breaking changes went unnoticed until compilation
54
+
55
+ ### Timeline of Errors
56
+
57
+ The errors fell into several categories:
58
+
59
+ **Type Export Issues (1 error)**
60
+ - `isolate.ts` couldn't import `Frontmatter` type from core (not exported)
61
+
62
+ **Interface Mismatches (2 errors)**
63
+ - `SpecInfo.date` was required in CLI but optional in core
64
+ - `deps.ts` failed due to this mismatch
65
+
66
+ **Type Casting Issues (2 errors)**
67
+ - `search.ts` had `unknown` types for `title`/`description` from frontmatter
68
+ - Needed explicit type guards
69
+
70
+ **MCP SDK Signature Changes (25+ errors)**
71
+ - All tool handlers missing required `extra` parameter
72
+ - Resource callbacks missing `variables` and `extra` parameters
73
+ - Console capturing code broken by incorrect multi_replace edits
74
+ - Type literal issues (`type: 'text'` vs `type: string`)
75
+
76
+ ## Why Didn't We Catch This?
77
+
78
+ ### Human Factors
79
+ - **Assumption**: "If build passes, types are good"
80
+ - **Habit**: Not running `pnpm typecheck` before releases
81
+ - **Time pressure**: Rush to publish without full validation
82
+ - **Trust**: Assumed CI would catch issues (but it didn't)
83
+
84
+ ### Process Gaps
85
+ - No checklist for releases
86
+ - No automated pre-release validation
87
+ - No CI gate for type checking
88
+ - No cross-package type validation
89
+
90
+ ### Tool Configuration
91
+ - `tsup.config.ts` may have been too lenient
92
+ - Build tool doesn't enforce strict type checking
93
+ - Missing `turbo run typecheck` in release workflow
94
+
95
+ ## What Should Have Happened
96
+
97
+ ### Ideal Pre-Release Checklist
98
+ ```bash
99
+ # 1. Type check all packages
100
+ pnpm typecheck
101
+
102
+ # 2. Run all tests
103
+ pnpm test:run
104
+
105
+ # 3. Build all packages
106
+ pnpm build
107
+
108
+ # 4. Validate docs build
109
+ cd docs-site && npm run build
110
+
111
+ # 5. Run local spec validation
112
+ node bin/lean-spec.js validate
113
+
114
+ # 6. Update CHANGELOG.md
115
+
116
+ # 7. Commit and tag
117
+ git add -A
118
+ git commit -m "chore: bump version to X.Y.Z"
119
+ git tag vX.Y.Z
120
+ git push origin main --tags
121
+
122
+ # 8. Create GitHub release (triggers CI)
123
+ gh release create vX.Y.Z
124
+ ```
125
+
126
+ ### Ideal CI/CD Workflow
127
+ ```yaml
128
+ # .github/workflows/publish.yml
129
+ jobs:
130
+ publish:
131
+ steps:
132
+ - name: Install dependencies
133
+ run: pnpm install
134
+
135
+ - name: Type check ⚠️ MISSING
136
+ run: pnpm typecheck
137
+
138
+ - name: Run tests ⚠️ MISSING
139
+ run: pnpm test:run
140
+
141
+ - name: Build
142
+ run: pnpm build
143
+
144
+ - name: Publish to npm
145
+ if: all tests pass
146
+ run: pnpm publish
147
+ ```
148
+
149
+ ## Lessons Learned
150
+
151
+ ### What Worked
152
+ - ✅ Fast identification and triage of errors
153
+ - ✅ Systematic fix approach (categorize, prioritize, fix)
154
+ - ✅ Good git practices (committed fix, tagged properly)
155
+ - ✅ Clear documentation of what was fixed
156
+
157
+ ### What Didn't Work
158
+ - ❌ No automated type checking in CI
159
+ - ❌ No pre-release validation checklist
160
+ - ❌ Build tools don't enforce type safety
161
+ - ❌ Assumed "build passes" = "types are correct"
162
+ - ❌ No cross-package type validation
163
+
164
+ ## Action Items
165
+
166
+ ### Immediate (Before Next Release)
167
+
168
+ **1. Add Type Checking to CI Workflow**
169
+ ```yaml
170
+ # .github/workflows/publish.yml
171
+ - name: Type check all packages
172
+ run: pnpm typecheck
173
+
174
+ - name: Run tests
175
+ run: pnpm test:run
176
+ ```
177
+
178
+ **2. Create Release Checklist**
179
+ Add to `CONTRIBUTING.md` or create `RELEASING.md`:
180
+ - [ ] Run `pnpm typecheck`
181
+ - [ ] Run `pnpm test:run`
182
+ - [ ] Run `pnpm build`
183
+ - [ ] Validate with `node bin/lean-spec.js validate`
184
+ - [ ] Update CHANGELOG.md
185
+ - [ ] Commit, tag, push
186
+ - [ ] Create GitHub release
187
+
188
+ **3. Add Pre-Push Hook** (Optional)
189
+ ```bash
190
+ # .husky/pre-push
191
+ pnpm typecheck || (echo "Type check failed!" && exit 1)
192
+ ```
193
+
194
+ ### Short-term (Next Sprint)
195
+
196
+ **4. Improve Package Scripts**
197
+ Add a `pre-release` script:
198
+ ```json
199
+ {
200
+ "scripts": {
201
+ "pre-release": "pnpm typecheck && pnpm test:run && pnpm build && pnpm validate"
202
+ }
203
+ }
204
+ ```
205
+
206
+ **5. Enhanced CI Pipeline**
207
+ - Add separate typecheck job that runs on all PRs
208
+ - Require passing typecheck before merge
209
+ - Add matrix testing across Node versions
210
+
211
+ **6. Documentation**
212
+ - Document the release process in `AGENTS.md`
213
+ - Add "Why typecheck matters" section
214
+ - Include common type error patterns
215
+
216
+ ### Long-term (Future)
217
+
218
+ **7. Automated Release Process**
219
+ Consider tools like:
220
+ - `semantic-release` for automated versioning
221
+ - `changesets` for monorepo releases
222
+ - `release-please` for GitHub-native releases
223
+
224
+ **8. Type Safety Improvements**
225
+ - Enable stricter TypeScript compiler options
226
+ - Add `strict: true` to all `tsconfig.json`
227
+ - Use `exactOptionalPropertyTypes`
228
+ - Enable `noUncheckedIndexedAccess`
229
+
230
+ **9. Monorepo Type Validation**
231
+ - Add Turbo task for cross-package type checking
232
+ - Validate type exports/imports between packages
233
+ - Add package boundary lint rules
234
+
235
+ ## Metrics to Track
236
+
237
+ Going forward, track:
238
+ - **Time to catch type errors**: Pre-push vs CI vs post-release
239
+ - **Type error frequency**: Trend over time
240
+ - **Release confidence**: Did we catch issues before release?
241
+ - **Developer friction**: Does strict checking slow development?
242
+
243
+ ## Success Criteria
244
+
245
+ This post-mortem is successful when:
246
+ - ✅ CI blocks releases with type errors
247
+ - ✅ `pnpm typecheck` is part of standard workflow
248
+ - ✅ Developers run typecheck before PRs
249
+ - ✅ Zero type-related release failures for 3 months
250
+ - ✅ Release checklist is documented and followed
251
+
252
+ ## References
253
+
254
+ - [TypeScript Handbook - Type Checking](https://www.typescriptlang.org/docs/handbook/2/basic-types.html)
255
+ - [Turbo: Type Checking in Monorepos](https://turbo.build/repo/docs/handbook/linting)
256
+ - [GitHub Actions: Required Status Checks](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches#require-status-checks-before-merging)
257
+
258
+ ## Conclusion
259
+
260
+ This was a **preventable failure** caused by process gaps, not technical limitations. The fix is straightforward:
261
+
262
+ 1. **Always run `pnpm typecheck` before releasing**
263
+ 2. **Add typecheck to CI/CD pipeline**
264
+ 3. **Document and follow release checklist**
265
+
266
+ The tools exist, we just need to use them consistently. This post-mortem serves as both documentation and action plan to ensure this never happens again.
@@ -0,0 +1,100 @@
1
+ ---
2
+ status: complete
3
+ created: '2025-11-17'
4
+ tags: []
5
+ priority: high
6
+ created_at: '2025-11-17T14:22:14.161Z'
7
+ updated_at: '2025-11-17T14:54:01.282Z'
8
+ completed_at: '2025-11-17T14:54:01.282Z'
9
+ completed: '2025-11-17'
10
+ transitions:
11
+ - status: complete
12
+ at: '2025-11-17T14:54:01.282Z'
13
+ ---
14
+
15
+ # Fix Sidebar Scroll Position Drift
16
+
17
+ > **Status**: ✅ Complete · **Priority**: High · **Created**: 2025-11-17
18
+
19
+ **Project**: lean-spec
20
+ **Team**: Core Development
21
+
22
+ ## Overview
23
+
24
+ The specs navigation sidebar in the web package experiences scroll position drift when navigating between specs. The list jumps or loses its scroll position during navigation, causing poor UX especially with large spec lists.
25
+
26
+ **Root Cause**: Multiple performance optimization attempts revealed the issue stems from:
27
+ 1. Store design causing unnecessary re-renders - `updateSidebarScrollTop` spreads state, triggering all subscribers even when only `scrollTop` changes
28
+ 2. Component subscribing to entire store state rather than specific slices
29
+ 3. `cachedSpecs` creating new references on every render before memoization
30
+ 4. Complex interaction between react-window's internal scroll management and external state updates
31
+
32
+ **Why Now**: This affects daily workflow navigation and has resisted multiple quick fixes. Needs proper investigation and testing.
33
+
34
+ ## Design
35
+
36
+ ### Investigation Completed
37
+ - Verified React 19 `useSyncExternalStore` requirements: unstable server snapshot references were causing infinite loops
38
+ - Determined global store broadcasts on every scroll write were the primary source of drift
39
+ - Confirmed `react-window` retains internal scroll state reliably when left to manage DOM scroll positions
40
+ - Observed that auto-anchoring logic was running too late, producing flicker during hydration
41
+
42
+ ### Final Approach
43
+ 1. **Selector-driven store reads** – keep existing selector hooks but ensure server snapshots are stable constants
44
+ 2. **Isolate scroll persistence** – keep global persistence value, but stop emitting change events when the value updates
45
+ 3. **Component-local scroll management** – mirror scrollTop in refs, throttle writes with `requestAnimationFrame`, and restore via `useIsomorphicLayoutEffect`
46
+ 4. **Controlled auto-anchoring** – only scroll the virtual list on the first render (when no stored offset exists) and guard future attempts with refs
47
+
48
+ ### Current Optimizations Applied
49
+ - Wrapped List in React.memo
50
+ - Memoized RowComponent with useCallback
51
+ - Memoized cachedSpecs
52
+ - Added selector-based store hooks (useSpecsSidebarSpecs, useSpecsSidebarActiveSpec)
53
+ - Separate listener sets per state slice
54
+
55
+ ## Plan
56
+
57
+ - [ ] Add detailed logging to track re-render causes (component, store, props changes)
58
+ - [x] Profile with React DevTools to identify actual render triggers
59
+ - [x] Test removing all scroll management code to establish baseline behavior (browser-managed scroll proved stable)
60
+ - [x] Implement proper selector pattern with verified render prevention
61
+ - [x] Test with large spec lists (100+ items) to verify performance
62
+ - [x] Document final solution and architecture decision
63
+
64
+ ### Implementation Summary
65
+
66
+ - Updated `useSyncExternalStore` server snapshot for specs to return a memoized empty array, eliminating React 19 infinite-loop warnings.
67
+ - Prevented `updateSidebarScrollTop` from emitting global store changes so unrelated subscribers no longer re-render on scroll.
68
+ - Added scroll persistence effect in `SpecsNavSidebar` that restores the cached offset via `useIsomorphicLayoutEffect` and throttled listeners.
69
+ - Introduced guarded auto-anchoring that only runs on the initial render when no stored offset exists, ensuring refreshed pages center the active spec without affecting later interactions.
70
+ - Added retry logic for auto-anchoring to wait until the virtualized list ref is ready, removing flicker.
71
+
72
+ ### Validation
73
+
74
+ - Navigating between specs preserves scroll position without jumps.
75
+ - Filtering, collapsing, and mobile toggles retain the current offset.
76
+ - Rapid spec changes and scrolling back to the top no longer trigger downward drift.
77
+ - Browser refresh loads with the active spec centered when no previous scroll position was saved.
78
+ - Large spec lists (>100 entries) scroll smoothly with no lag or unexpected reflows.
79
+
80
+ ## Test
81
+
82
+ - [x] Navigate between specs - scroll position should remain stable
83
+ - [x] Filter specs while scrolled - list should not jump
84
+ - [x] Open/close mobile sidebar - no scroll position loss
85
+ - [x] Rapid navigation (click multiple specs quickly) - no drift or jumping
86
+ - [x] Large spec lists (100+) - smooth scrolling without lag
87
+ - [x] Browser refresh - reasonable scroll restoration behavior
88
+
89
+ ## Notes
90
+
91
+ **Attempted Fixes (Session 1)**:
92
+ - Removed scroll restoration on navigation
93
+ - Removed scroll tracking callbacks
94
+ - Wrapped List in memo
95
+ - Memoized cachedSpecs to prevent reference changes
96
+ - Implemented selector-based store subscriptions
97
+
98
+ **Key Learning**: The issue persisted despite multiple optimizations, suggesting the problem is architectural rather than a simple memoization issue. The store design fundamentally causes re-renders when any state changes, even with selector hooks.
99
+
100
+ **Next Steps**: Monitor for regressions when introducing future sidebar features (e.g., grouping, pinning). Add logging only if new drift reports appear.
package/package.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  "name": "@leanspec/ui",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "LeanSpec web UI launcher for visual spec management",
5
5
  "type": "module",
6
- "bin": "./bin/ui.js",
6
+ "bin": {
7
+ "leanspec-ui": "./bin/ui.js"
8
+ },
7
9
  "scripts": {
8
10
  "build": "node ./scripts/prepare-dist.mjs",
9
11
  "prepublishOnly": "pnpm run build"
10
12
  },
11
13
  "files": [
12
14
  "bin/",
13
- "dist/",
15
+ "dist/standalone/",
14
16
  "README.md",
15
17
  "LICENSE"
16
18
  ],
package/dist/BUILD_ID DELETED
@@ -1 +0,0 @@
1
- Z_BxkB0KJViCNbULN1S5p
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,22764,e=>{"use strict";let t=(0,e.i(22436).default)("list",[["path",{d:"M3 5h.01",key:"18ugdj"}],["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M3 19h.01",key:"noohij"}],["path",{d:"M8 5h13",key:"1pao27"}],["path",{d:"M8 12h13",key:"1za7za"}],["path",{d:"M8 19h13",key:"m83p4d"}]]);e.s(["List",()=>t],22764)},28954,(e,t,r)=>{e.e,t.exports=function(){"use strict";var e="millisecond",t="second",r="minute",s="hour",n="week",i="month",a="quarter",l="year",o="date",c="Invalid Date",u=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,d=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,h=function(e,t,r){var s=String(e);return!s||s.length>=t?e:""+Array(t+1-s.length).join(r)+e},f="en",m={};m[f]={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(e){var t=["th","st","nd","rd"],r=e%100;return"["+e+(t[(r-20)%10]||t[r]||t[0])+"]"}};var p="$isDayjsObject",x=function(e){return e instanceof y||!(!e||!e[p])},g=function e(t,r,s){var n;if(!t)return f;if("string"==typeof t){var i=t.toLowerCase();m[i]&&(n=i),r&&(m[i]=r,n=i);var a=t.split("-");if(!n&&a.length>1)return e(a[0])}else{var l=t.name;m[l]=t,n=l}return!s&&n&&(f=n),n||!s&&f},v=function(e,t){if(x(e))return e.clone();var r="object"==typeof t?t:{};return r.date=e,r.args=arguments,new y(r)},S={s:h,z:function(e){var t=-e.utcOffset(),r=Math.abs(t);return(t<=0?"+":"-")+h(Math.floor(r/60),2,"0")+":"+h(r%60,2,"0")},m:function e(t,r){if(t.date()<r.date())return-e(r,t);var s=12*(r.year()-t.year())+(r.month()-t.month()),n=t.clone().add(s,i),a=r-n<0,l=t.clone().add(s+(a?-1:1),i);return+(-(s+(r-n)/(a?n-l:l-n))||0)},a:function(e){return e<0?Math.ceil(e)||0:Math.floor(e)},p:function(c){return({M:i,y:l,w:n,d:"day",D:o,h:s,m:r,s:t,ms:e,Q:a})[c]||String(c||"").toLowerCase().replace(/s$/,"")},u:function(e){return void 0===e}};S.l=g,S.i=x,S.w=function(e,t){return v(e,{locale:t.$L,utc:t.$u,x:t.$x,$offset:t.$offset})};var y=function(){function h(e){this.$L=g(e.locale,null,!0),this.parse(e),this.$x=this.$x||e.x||{},this[p]=!0}var f=h.prototype;return f.parse=function(e){this.$d=function(e){var t=e.date,r=e.utc;if(null===t)return new Date(NaN);if(S.u(t))return new Date;if(t instanceof Date)return new Date(t);if("string"==typeof t&&!/Z$/i.test(t)){var s=t.match(u);if(s){var n=s[2]-1||0,i=(s[7]||"0").substring(0,3);return r?new Date(Date.UTC(s[1],n,s[3]||1,s[4]||0,s[5]||0,s[6]||0,i)):new Date(s[1],n,s[3]||1,s[4]||0,s[5]||0,s[6]||0,i)}}return new Date(t)}(e),this.init()},f.init=function(){var e=this.$d;this.$y=e.getFullYear(),this.$M=e.getMonth(),this.$D=e.getDate(),this.$W=e.getDay(),this.$H=e.getHours(),this.$m=e.getMinutes(),this.$s=e.getSeconds(),this.$ms=e.getMilliseconds()},f.$utils=function(){return S},f.isValid=function(){return this.$d.toString()!==c},f.isSame=function(e,t){var r=v(e);return this.startOf(t)<=r&&r<=this.endOf(t)},f.isAfter=function(e,t){return v(e)<this.startOf(t)},f.isBefore=function(e,t){return this.endOf(t)<v(e)},f.$g=function(e,t,r){return S.u(e)?this[t]:this.set(r,e)},f.unix=function(){return Math.floor(this.valueOf()/1e3)},f.valueOf=function(){return this.$d.getTime()},f.startOf=function(e,a){var c=this,u=!!S.u(a)||a,d=S.p(e),h=function(e,t){var r=S.w(c.$u?Date.UTC(c.$y,t,e):new Date(c.$y,t,e),c);return u?r:r.endOf("day")},f=function(e,t){return S.w(c.toDate()[e].apply(c.toDate("s"),(u?[0,0,0,0]:[23,59,59,999]).slice(t)),c)},m=this.$W,p=this.$M,x=this.$D,g="set"+(this.$u?"UTC":"");switch(d){case l:return u?h(1,0):h(31,11);case i:return u?h(1,p):h(0,p+1);case n:var v=this.$locale().weekStart||0,y=(m<v?m+7:m)-v;return h(u?x-y:x+(6-y),p);case"day":case o:return f(g+"Hours",0);case s:return f(g+"Minutes",1);case r:return f(g+"Seconds",2);case t:return f(g+"Milliseconds",3);default:return this.clone()}},f.endOf=function(e){return this.startOf(e,!1)},f.$set=function(n,a){var c,u=S.p(n),d="set"+(this.$u?"UTC":""),h=((c={}).day=d+"Date",c[o]=d+"Date",c[i]=d+"Month",c[l]=d+"FullYear",c[s]=d+"Hours",c[r]=d+"Minutes",c[t]=d+"Seconds",c[e]=d+"Milliseconds",c)[u],f="day"===u?this.$D+(a-this.$W):a;if(u===i||u===l){var m=this.clone().set(o,1);m.$d[h](f),m.init(),this.$d=m.set(o,Math.min(this.$D,m.daysInMonth())).$d}else h&&this.$d[h](f);return this.init(),this},f.set=function(e,t){return this.clone().$set(e,t)},f.get=function(e){return this[S.p(e)]()},f.add=function(e,a){var o,c=this;e=Number(e);var u=S.p(a),d=function(t){var r=v(c);return S.w(r.date(r.date()+Math.round(t*e)),c)};if(u===i)return this.set(i,this.$M+e);if(u===l)return this.set(l,this.$y+e);if("day"===u)return d(1);if(u===n)return d(7);var h=((o={})[r]=6e4,o[s]=36e5,o[t]=1e3,o)[u]||1,f=this.$d.getTime()+e*h;return S.w(f,this)},f.subtract=function(e,t){return this.add(-1*e,t)},f.format=function(e){var t=this,r=this.$locale();if(!this.isValid())return r.invalidDate||c;var s=e||"YYYY-MM-DDTHH:mm:ssZ",n=S.z(this),i=this.$H,a=this.$m,l=this.$M,o=r.weekdays,u=r.months,h=r.meridiem,f=function(e,r,n,i){return e&&(e[r]||e(t,s))||n[r].slice(0,i)},m=function(e){return S.s(i%12||12,e,"0")},p=h||function(e,t,r){var s=e<12?"AM":"PM";return r?s.toLowerCase():s};return s.replace(d,function(e,s){return s||function(e){switch(e){case"YY":return String(t.$y).slice(-2);case"YYYY":return S.s(t.$y,4,"0");case"M":return l+1;case"MM":return S.s(l+1,2,"0");case"MMM":return f(r.monthsShort,l,u,3);case"MMMM":return f(u,l);case"D":return t.$D;case"DD":return S.s(t.$D,2,"0");case"d":return String(t.$W);case"dd":return f(r.weekdaysMin,t.$W,o,2);case"ddd":return f(r.weekdaysShort,t.$W,o,3);case"dddd":return o[t.$W];case"H":return String(i);case"HH":return S.s(i,2,"0");case"h":return m(1);case"hh":return m(2);case"a":return p(i,a,!0);case"A":return p(i,a,!1);case"m":return String(a);case"mm":return S.s(a,2,"0");case"s":return String(t.$s);case"ss":return S.s(t.$s,2,"0");case"SSS":return S.s(t.$ms,3,"0");case"Z":return n}return null}(e)||n.replace(":","")})},f.utcOffset=function(){return-(15*Math.round(this.$d.getTimezoneOffset()/15))},f.diff=function(e,o,c){var u,d=this,h=S.p(o),f=v(e),m=(f.utcOffset()-this.utcOffset())*6e4,p=this-f,x=function(){return S.m(d,f)};switch(h){case l:u=x()/12;break;case i:u=x();break;case a:u=x()/3;break;case n:u=(p-m)/6048e5;break;case"day":u=(p-m)/864e5;break;case s:u=p/36e5;break;case r:u=p/6e4;break;case t:u=p/1e3;break;default:u=p}return c?u:S.a(u)},f.daysInMonth=function(){return this.endOf(i).$D},f.$locale=function(){return m[this.$L]},f.locale=function(e,t){if(!e)return this.$L;var r=this.clone(),s=g(e,t,!0);return s&&(r.$L=s),r},f.clone=function(){return S.w(this.$d,this)},f.toDate=function(){return new Date(this.valueOf())},f.toJSON=function(){return this.isValid()?this.toISOString():null},f.toISOString=function(){return this.$d.toISOString()},f.toString=function(){return this.$d.toUTCString()},h}(),b=y.prototype;return v.prototype=b,[["$ms",e],["$s",t],["$m",r],["$H",s],["$W","day"],["$M",i],["$y",l],["$D",o]].forEach(function(e){b[e[1]]=function(t){return this.$g(t,e[0],e[1])}}),v.extend=function(e,t){return e.$i||(e(t,y,v),e.$i=!0),v},v.locale=g,v.isDayjs=x,v.unix=function(e){return v(1e3*e)},v.en=m[f],v.Ls=m,v.p={},v}()},12437,(e,t,r)=>{e.e,t.exports=function(e,t,r){e=e||{};var s=t.prototype,n={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function i(e,t,r,n){return s.fromToBase(e,t,r,n)}r.en.relativeTime=n,s.fromToBase=function(t,s,i,a,l){for(var o,c,u,d=i.$locale().relativeTime||n,h=e.thresholds||[{l:"s",r:44,d:"second"},{l:"m",r:89},{l:"mm",r:44,d:"minute"},{l:"h",r:89},{l:"hh",r:21,d:"hour"},{l:"d",r:35},{l:"dd",r:25,d:"day"},{l:"M",r:45},{l:"MM",r:10,d:"month"},{l:"y",r:17},{l:"yy",d:"year"}],f=h.length,m=0;m<f;m+=1){var p=h[m];p.d&&(o=a?r(t).diff(i,p.d,!0):i.diff(t,p.d,!0));var x=(e.rounding||Math.round)(Math.abs(o));if(u=o>0,x<=p.r||!p.r){x<=1&&m>0&&(p=h[m-1]);var g=d[p.l];l&&(x=l(""+x)),c="string"==typeof g?g.replace("%d",x):g(x,s,p.l,u);break}}if(s)return c;var v=u?d.future:d.past;return"function"==typeof v?v(c):v.replace("%s",c)},s.to=function(e,t){return i(e,t,this,!0)},s.from=function(e,t){return i(e,t,this)};var a=function(e){return e.$u?r.utc():r()};s.toNow=function(e){return this.to(a(this),e)},s.fromNow=function(e){return this.from(a(this),e)}}},3622,34153,12542,e=>{"use strict";var t=e.i(90022),r=e.i(31231),s=e.i(87985);let n="u">typeof window?r.useLayoutEffect:r.useEffect;function i(e){if(void 0!==e)switch(typeof e){case"number":return e;case"string":if(e.endsWith("px"))return parseFloat(e)}}let a=null;function l({containerElement:e,direction:t,isRtl:r,scrollOffset:s}){if("horizontal"===t&&r)switch(function(e=!1){if(null===a||e){let e=document.createElement("div"),t=e.style;t.width="50px",t.height="50px",t.overflow="scroll",t.direction="rtl";let r=document.createElement("div"),s=r.style;return s.width="100px",s.height="100px",e.appendChild(r),document.body.appendChild(e),e.scrollLeft>0?a="positive-descending":(e.scrollLeft=1,a=0===e.scrollLeft?"negative":"positive-ascending"),document.body.removeChild(e),a}return a}()){case"negative":return-s;case"positive-descending":if(e){let{clientWidth:t,scrollLeft:r,scrollWidth:s}=e;return s-t-r}}return s}function o(e,t="Assertion error"){if(!e)throw console.error(t),Error(t)}function c(e,t){if(e===t)return!0;if(!!e!=!!t||(o(void 0!==e),o(void 0!==t),Object.keys(e).length!==Object.keys(t).length))return!1;for(let r in e)if(!Object.is(t[r],e[r]))return!1;return!0}function u({cachedBounds:e,itemCount:t,itemSize:r}){if(0===t)return 0;if("number"==typeof r)return t*r;{let r=e.get(0===e.size?0:e.size-1);return o(void 0!==r,"Unexpected bounds cache miss"),t*((r.scrollOffset+r.size)/e.size)}}function d({cachedBounds:e,containerScrollOffset:t,containerSize:r,itemCount:s,overscanCount:n}){let i=s-1,a=0,l=-1,o=0,c=-1,u=0;for(;u<i;){let r=e.get(u);if(r.scrollOffset+r.size>t)break;u++}for(o=Math.max(0,(a=u)-n);u<i;){let s=e.get(u);if(s.scrollOffset+s.size>=t+r)break;u++}return c=Math.min(s-1,(l=Math.min(i,u))+n),a<0&&(a=0,l=-1,o=0,c=-1),{startIndexVisible:a,stopIndexVisible:l,startIndexOverscan:o,stopIndexOverscan:c}}function h(e,t){let{ariaAttributes:r,style:s,...n}=e,{ariaAttributes:i,style:a,...l}=t;return c(r,i)&&c(s,a)&&c(n,l)}function f({children:e,className:s,defaultHeight:a=0,listRef:f,onResize:m,onRowsRendered:p,overscanCount:x=3,rowComponent:g,rowCount:v,rowHeight:S,rowProps:y,tagName:b="div",style:w,...j}){let $=(0,r.useMemo)(()=>y,Object.values(y)),M=(0,r.useMemo)(()=>(0,r.memo)(g,h),[g]),[N,C]=(0,r.useState)(null),I=null!=S&&"object"==typeof S&&"getAverageRowHeight"in S&&"function"==typeof S.getAverageRowHeight,{getCellBounds:z,getEstimatedSize:O,scrollToIndex:T,startIndexOverscan:k,startIndexVisible:D,stopIndexOverscan:R,stopIndexVisible:E}=function({containerElement:e,containerStyle:t,defaultContainerSize:s=0,direction:a,isRtl:h=!1,itemCount:f,itemProps:m,itemSize:p,onResize:x,overscanCount:g}){var v;let S,[y,b]=(0,r.useState)({startIndexVisible:0,startIndexOverscan:0,stopIndexVisible:-1,stopIndexOverscan:-1}),{startIndexVisible:w,startIndexOverscan:j,stopIndexVisible:$,stopIndexOverscan:M}={startIndexVisible:Math.min(f-1,y.startIndexVisible),startIndexOverscan:Math.min(f-1,y.startIndexOverscan),stopIndexVisible:Math.min(f-1,y.stopIndexVisible),stopIndexOverscan:Math.min(f-1,y.stopIndexOverscan)},{height:N=s,width:C=s}=function({box:e,defaultHeight:t,defaultWidth:s,disabled:a,element:l,mode:o,style:c}){let{styleHeight:u,styleWidth:d}=(0,r.useMemo)(()=>({styleHeight:i(c?.height),styleWidth:i(c?.width)}),[c?.height,c?.width]),[h,f]=(0,r.useState)({height:t,width:s}),m=a||"only-height"===o&&void 0!==u||"only-width"===o&&void 0!==d||void 0!==u&&void 0!==d;return n(()=>{if(null===l||m)return;let t=new ResizeObserver(e=>{for(let t of e){let{contentRect:e,target:r}=t;l===r&&f(t=>t.height===e.height&&t.width===e.width?t:{height:e.height,width:e.width})}});return t.observe(l,{box:e}),()=>{t?.unobserve(l)}},[e,m,l,u,d]),(0,r.useMemo)(()=>({height:u??h.height,width:d??h.width}),[h,u,d])}({defaultHeight:"vertical"===a?s:void 0,defaultWidth:"horizontal"===a?s:void 0,element:e,mode:"vertical"===a?"only-height":"only-width",style:t}),I=(0,r.useRef)({height:0,width:0}),z="vertical"===a?N:C,O=function({containerSize:e,itemSize:t}){let r;return"string"==typeof t?(o(t.endsWith("%"),`Invalid item size: "${t}"; string values must be percentages (e.g. "100%")`),o(void 0!==e,"Container size must be defined if a percentage item size is specified"),r=e*parseInt(t)/100):r=t,r}({containerSize:z,itemSize:p});(0,r.useLayoutEffect)(()=>{if("function"==typeof x){let e=I.current;(e.height!==N||e.width!==C)&&(x({height:N,width:C},{...e}),e.height=N,e.width=C)}},[N,x,C]);let T=function({itemCount:e,itemProps:t,itemSize:s}){return(0,r.useMemo)(()=>(function({itemCount:e,itemProps:t,itemSize:r}){let s=new Map;return{get(n){for(o(n<e,`Invalid index ${n}`);s.size-1<n;){let e,i=s.size;switch(typeof r){case"function":e=r(i,t);break;case"number":e=r}if(0===i)s.set(i,{size:e,scrollOffset:0});else{let t=s.get(i-1);o(void 0!==t,`Unexpected bounds cache miss for index ${n}`),s.set(i,{scrollOffset:t.scrollOffset+t.size,size:e})}}let i=s.get(n);return o(void 0!==i,`Unexpected bounds cache miss for index ${n}`),i},set(e,t){s.set(e,t)},get size(){return s.size}}})({itemCount:e,itemProps:t,itemSize:s}),[e,t,s])}({itemCount:f,itemProps:m,itemSize:O}),k=(0,r.useCallback)(e=>T.get(e),[T]),D=(0,r.useCallback)(()=>u({cachedBounds:T,itemCount:f,itemSize:O}),[T,f,O]),R=(0,r.useCallback)(t=>d({cachedBounds:T,containerScrollOffset:l({containerElement:e,direction:a,isRtl:h,scrollOffset:t}),containerSize:z,itemCount:f,overscanCount:g}),[T,e,z,a,h,f,g]);return n(()=>{b(R(("vertical"===a?e?.scrollTop:e?.scrollLeft)??0))},[e,a,R]),n(()=>{if(!e)return;let t=()=>{b(t=>{let{scrollLeft:r,scrollTop:s}=e,n=d({cachedBounds:T,containerScrollOffset:l({containerElement:e,direction:a,isRtl:h,scrollOffset:"vertical"===a?s:r}),containerSize:z,itemCount:f,overscanCount:g});return c(n,t)?t:n})};return e.addEventListener("scroll",t),()=>{e.removeEventListener("scroll",t)}},[T,e,z,a,f,g]),{getCellBounds:k,getEstimatedSize:D,scrollToIndex:(v=({align:t="auto",containerScrollOffset:r,index:s})=>{let n=function({align:e,cachedBounds:t,index:r,itemCount:s,itemSize:n,containerScrollOffset:i,containerSize:a}){if(r<0||r>=s)throw RangeError(`Invalid index specified: ${r}`,{cause:`Index ${r} is not within the range of 0 - ${s-1}`});let l=u({cachedBounds:t,itemCount:s,itemSize:n}),o=t.get(r),c=Math.max(0,Math.min(l-a,o.scrollOffset)),d=Math.max(0,o.scrollOffset-a+o.size);switch("smart"===e&&(e=i>=d&&i<=c?"auto":"center"),e){case"start":return c;case"end":return d;case"center":return o.scrollOffset<=a/2?0:o.scrollOffset+o.size/2>=l-a/2?l-a:o.scrollOffset+o.size/2-a/2;default:return i>=d&&i<=c?i:i<d?d:c}}({align:t,cachedBounds:T,containerScrollOffset:r,containerSize:z,index:s,itemCount:f,itemSize:O});if(e){if(n=l({containerElement:e,direction:a,isRtl:h,scrollOffset:n}),"function"!=typeof e.scrollTo){let e=R(n);c(y,e)||b(e)}return n}},S=(0,r.useRef)(()=>{throw Error("Cannot call during render.")}),n(()=>{S.current=v},[v]),(0,r.useCallback)(e=>S.current?.(e),[S])),startIndexOverscan:j,startIndexVisible:w,stopIndexOverscan:M,stopIndexVisible:$}}({containerElement:N,containerStyle:w,defaultContainerSize:a,direction:"vertical",itemCount:v,itemProps:$,itemSize:(0,r.useMemo)(()=>I?e=>S.getRowHeight(e)??S.getAverageRowHeight():S,[I,S]),onResize:m,overscanCount:x});(0,r.useImperativeHandle)(f,()=>({get element(){return N},scrollToRow({align:e="auto",behavior:t="auto",index:r}){let s=T({align:e,containerScrollOffset:N?.scrollTop??0,index:r});"function"==typeof N?.scrollTo&&N.scrollTo({behavior:t,top:s})}}),[N,T]),n(()=>{if(!N)return;let e=Array.from(N.children).filter((e,t)=>{if(e.hasAttribute("aria-hidden"))return!1;let r=`${k+t}`;return e.setAttribute("data-react-window-index",r),!0});if(I)return S.observeRowElements(e)},[N,I,S,k,R]),(0,r.useEffect)(()=>{k>=0&&R>=0&&p&&p({startIndex:D,stopIndex:E},{startIndex:k,stopIndex:R})},[p,k,D,R,E]);let A=(0,r.useMemo)(()=>{let e=[];if(v>0)for(let t=k;t<=R;t++){let s=z(t);e.push((0,r.createElement)(M,{...$,ariaAttributes:{"aria-posinset":t+1,"aria-setsize":v,role:"listitem"},key:t,index:t,style:{position:"absolute",left:0,transform:`translateY(${s.scrollOffset}px)`,height:I?void 0:s.size,width:"100%"}}))}return e},[M,z,I,v,$,k,R]),H=(0,t.jsx)("div",{"aria-hidden":!0,style:{height:O(),width:"100%",zIndex:-1}});return(0,r.createElement)(b,{role:"list",...j,className:s,ref:C,style:{position:"relative",maxHeight:"100%",flexGrow:1,overflowY:"auto",...w}},A,e,H)}r.useState,r.useRef,r.useState,r.useRef;var m=e.i(329),p=e.i(58362),x=e.i(25761),g=e.i(44021),v=e.i(22764);let S=(0,e.i(22436).default)("funnel",[["path",{d:"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z",key:"sc7q7i"}]]);var y=e.i(81622),b=e.i(60218),w=e.i(71840),j=e.i(38322),$=e.i(46131),M=e.i(65458),N=e.i(35179),C=e.i(28954),I=e.i(12437);function z(e){return e?(0,C.default)(e).fromNow():"Unknown"}function O(e,t){if(!e||!t)return"";let r=(0,C.default)(e),s=(0,C.default)(t).diff(r);if(s<0)return"";let n=Math.floor(s/864e5),i=Math.floor(s%864e5/36e5);if(0===n&&0===i){let e=Math.floor(s%36e5/6e4);return 0===e?"< 1m":`${e}m`}if(0===n)return`${i}h`;if(n<30)return i>0?`${n}d ${i}h`:`${n}d`;let a=Math.floor(n/30),l=n%30;if(a<12)return l>0?`${a}mo ${l}d`:`${a}mo`;let o=Math.floor(a/12),c=a%12;return c>0?`${o}y ${c}mo`:`${o}y`}C.default.extend(I.default),e.s(["formatDuration",()=>O,"formatRelativeTime",()=>z],34153);let T={specs:[],signature:null,scrollTop:0,activeSpecId:null},k=new Set;function D(){for(let e of k)e()}function R(e){return k.add(e),()=>{k.delete(e)}}function E(){return T}function A(){return(0,r.useSyncExternalStore)(R,E,()=>T)}function H(e){if(0===e.length)return;let t=e.map(e=>[e.id,e.specNumber??"",e.title??"",e.status??"",e.priority??"",e.updatedAt?new Date(e.updatedAt).getTime():0].join(":")).join("|");t!==T.signature&&(T={...T,specs:e,signature:t},D())}function L(e){T.activeSpecId!==e&&(T={...T,activeSpecId:e},D())}function B(e){1>Math.abs(e-T.scrollTop)||(T={...T,scrollTop:e},D())}function V({initialSpecs:e=[],currentSpecId:n,currentSubSpec:i,onSpecHover:a}){let[l,o]=r.useState(""),[c,u]=r.useState("all"),[d,h]=r.useState("all"),[C,I]=r.useState("all"),[O,T]=r.useState(!1),[k,D]=r.useState(()=>"true"===localStorage.getItem("specs-nav-sidebar-collapsed")),[R,E]=r.useState(!1),[H,L]=r.useState(!1),V=r.useRef(null),P=r.useRef(null),_=r.useRef(null),W=A(),Y=W.specs.length>0?W.specs:e,U=n||W.activeSpecId||"",F=W.scrollTop;r.useEffect(()=>{L(!0)},[]),r.useEffect(()=>{document.documentElement.style.setProperty("--specs-nav-sidebar-width",k?"0px":"280px"),localStorage.setItem("specs-nav-sidebar-collapsed",String(k))},[k]),r.useEffect(()=>{E(!1)},[U,i]),r.useLayoutEffect(()=>{P.current&&Math.abs(P.current.scrollTop-F)>1&&(P.current.scrollTop=F)},[F]),r.useEffect(()=>(window.toggleSpecsSidebar=()=>E(e=>!e),()=>{window.toggleSpecsSidebar=void 0}),[]),r.useEffect(()=>{if(V.current){let e=V.current,t=e.closest(".overflow-y-auto");if(t){let r=e.getBoundingClientRect(),s=t.getBoundingClientRect();r.top>=s.top&&r.bottom<=s.bottom||e.scrollIntoView({behavior:"smooth",block:"center"})}}},[n,i]);let J=r.useMemo(()=>{let e=Y;if(l){let t=l.toLowerCase();e=e.filter(e=>e.title?.toLowerCase().includes(t)||e.specName.toLowerCase().includes(t)||e.specNumber?.toString().includes(t))}return"all"!==c&&(e=e.filter(e=>e.status===c)),"all"!==d&&(e=e.filter(e=>e.priority===d)),"all"!==C&&(e=e.filter(e=>e.tags?.includes(C))),e},[Y,l,c,d,C]),Z=r.useMemo(()=>{let e=new Set;return Y.forEach(t=>{t.tags?.forEach(t=>e.add(t))}),Array.from(e).sort()},[Y]),q="all"!==c||"all"!==d||"all"!==C,K=r.useMemo(()=>[...J].sort((e,t)=>(t.specNumber||0)-(e.specNumber||0)),[J]),G=r.useCallback(()=>{_.current||(_.current=window.requestAnimationFrame(()=>{_.current=null,P.current&&B(P.current.scrollTop)}))},[]),Q=r.useCallback(e=>{let{index:r,style:n}=e,l=K[r],o=l.id===U,c=(l.contentMd?(0,M.extractH1Title)(l.contentMd):null)||l.title||l.specName;return(0,t.jsx)("div",{style:n,className:"px-1",children:(0,t.jsx)("div",{className:"mb-0.5",children:(0,t.jsx)("div",{className:"flex items-center gap-0.5",children:(0,t.jsxs)(j.Tooltip,{children:[(0,t.jsx)(j.TooltipTrigger,{asChild:!0,children:(0,t.jsxs)(s.default,{ref:o&&!i?V:null,href:`/specs/${l.specNumber||l.id}`,onMouseEnter:()=>a?.(l.specNumber?.toString()||l.id),className:(0,M.cn)("w-full flex flex-col gap-1 p-1.5 rounded-md text-sm transition-colors",o?"bg-accent text-accent-foreground font-medium":"hover:bg-accent/50"),children:[(0,t.jsxs)("div",{className:"flex items-center gap-1.5",children:[l.specNumber&&(0,t.jsxs)("span",{className:"text-xs font-mono text-muted-foreground shrink-0",children:["#",l.specNumber.toString().padStart(3,"0")]}),(0,t.jsx)("span",{className:"truncate text-xs leading-relaxed",children:c})]}),(0,t.jsxs)("div",{className:"flex items-center gap-1.5 flex-wrap",children:[l.status&&(0,t.jsxs)(j.Tooltip,{children:[(0,t.jsx)(j.TooltipTrigger,{asChild:!0,children:(0,t.jsx)("div",{children:(0,t.jsx)(w.StatusBadge,{status:l.status,iconOnly:!0,className:"text-[10px] scale-90"})})}),(0,t.jsx)(j.TooltipContent,{side:"right",children:(0,w.getStatusLabel)(l.status)})]}),l.priority&&(0,t.jsxs)(j.Tooltip,{children:[(0,t.jsx)(j.TooltipTrigger,{asChild:!0,children:(0,t.jsx)("div",{children:(0,t.jsx)(N.PriorityBadge,{priority:l.priority,iconOnly:!0,className:"text-[10px] scale-90"})})}),(0,t.jsx)(j.TooltipContent,{side:"right",children:(0,N.getPriorityLabel)(l.priority)})]}),l.updatedAt&&(0,t.jsx)("span",{className:"text-[10px] text-muted-foreground",children:z(l.updatedAt)})]})]})}),(0,t.jsx)(j.TooltipContent,{side:"right",className:"max-w-[300px]",children:(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)("div",{className:"font-semibold",children:c}),(0,t.jsx)("div",{className:"text-xs text-muted-foreground",children:l.specName})]})})]})})})})},[K,U,i,a]),X=r.useMemo(()=>window.innerHeight-56-180,[]),ee=r.useMemo(()=>K.findIndex(e=>e.id===U),[K,U]),et=r.useRef(null);return r.useEffect(()=>{et.current&&ee>=0&&et.current.scrollToRow({index:ee,align:"center",behavior:"smooth"})},[ee]),(0,t.jsxs)(j.TooltipProvider,{delayDuration:700,children:[R&&(0,t.jsx)("div",{className:"fixed inset-0 bg-black/50 z-40 lg:hidden",onClick:()=>E(!1)}),(0,t.jsxs)("div",{className:"relative flex-shrink-0",children:[(0,t.jsxs)("aside",{className:(0,M.cn)("sticky top-14 h-[calc(100vh-3.5rem)] border-r border-border bg-background flex flex-col overflow-hidden transition-all duration-300","hidden lg:flex",H&&k?"lg:w-0 lg:border-r-0":"lg:w-[280px]",R&&"fixed left-0 top-14 z-50 flex w-[280px]"),children:[(0,t.jsxs)("div",{className:"p-4 border-b border-border",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-3",children:[(0,t.jsx)("h2",{className:"font-semibold text-sm",children:"Specifications"}),(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsxs)(j.Tooltip,{children:[(0,t.jsx)(j.TooltipTrigger,{asChild:!0,children:(0,t.jsx)(b.Button,{variant:O||q?"default":"ghost",size:"sm",onClick:()=>T(!O),className:"h-6 w-6 p-0",children:(0,t.jsx)(S,{className:"h-4 w-4"})})}),(0,t.jsx)(j.TooltipContent,{side:"bottom",children:O?"Hide filters":"Show filters"})]}),(0,t.jsx)(b.Button,{variant:"ghost",size:"sm",onClick:()=>E(!1),className:"h-6 w-6 p-0 lg:hidden",children:(0,t.jsx)(g.X,{className:"h-4 w-4"})}),(0,t.jsx)(b.Button,{variant:"ghost",size:"sm",onClick:()=>D(!0),className:"h-6 w-6 p-0 hidden lg:flex lg:items-center lg:justify-center",children:(0,t.jsx)(p.ChevronLeft,{className:"h-4 w-4"})})]})]}),O&&(0,t.jsxs)("div",{className:"space-y-2 mb-3 pb-3 border-b border-border",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-muted-foreground",children:"Filters"}),q&&(0,t.jsx)(b.Button,{variant:"ghost",size:"sm",onClick:()=>{u("all"),h("all"),I("all")},className:"h-5 text-xs px-2 py-0",children:"Clear"})]}),(0,t.jsxs)($.Select,{value:c,onValueChange:u,children:[(0,t.jsx)($.SelectTrigger,{className:"h-8 text-xs",children:(0,t.jsx)($.SelectValue,{placeholder:"Status"})}),(0,t.jsxs)($.SelectContent,{children:[(0,t.jsx)($.SelectItem,{value:"all",children:"All Status"}),(0,t.jsx)($.SelectItem,{value:"planned",children:"Planned"}),(0,t.jsx)($.SelectItem,{value:"in-progress",children:"In Progress"}),(0,t.jsx)($.SelectItem,{value:"complete",children:"Complete"}),(0,t.jsx)($.SelectItem,{value:"archived",children:"Archived"})]})]}),(0,t.jsxs)($.Select,{value:d,onValueChange:h,children:[(0,t.jsx)($.SelectTrigger,{className:"h-8 text-xs",children:(0,t.jsx)($.SelectValue,{placeholder:"Priority"})}),(0,t.jsxs)($.SelectContent,{children:[(0,t.jsx)($.SelectItem,{value:"all",children:"All Priority"}),(0,t.jsx)($.SelectItem,{value:"low",children:"Low"}),(0,t.jsx)($.SelectItem,{value:"medium",children:"Medium"}),(0,t.jsx)($.SelectItem,{value:"high",children:"High"}),(0,t.jsx)($.SelectItem,{value:"critical",children:"Critical"})]})]}),Z.length>0&&(0,t.jsxs)($.Select,{value:C,onValueChange:I,children:[(0,t.jsx)($.SelectTrigger,{className:"h-8 text-xs",children:(0,t.jsx)($.SelectValue,{placeholder:"Tag"})}),(0,t.jsxs)($.SelectContent,{children:[(0,t.jsx)($.SelectItem,{value:"all",children:"All Tags"}),Z.map(e=>(0,t.jsx)($.SelectItem,{value:e,children:e},e))]})]})]}),(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)(m.Search,{className:"absolute left-2 top-2.5 h-4 w-4 text-muted-foreground"}),(0,t.jsx)(y.Input,{placeholder:"Search specs...",value:l,onChange:e=>o(e.target.value),className:"pl-8 h-9 border-border"})]})]}),(0,t.jsx)("div",{ref:P,className:"flex-1 overflow-y-auto overflow-x-hidden",onScroll:G,children:0===K.length?(0,t.jsx)("div",{className:"text-center py-8 text-sm text-muted-foreground",children:"No specs found"}):(0,t.jsx)(f,{listRef:et,defaultHeight:X,rowCount:K.length,rowHeight:72,overscanCount:5,rowComponent:Q,rowProps:{}})})]}),H&&k&&(0,t.jsx)(b.Button,{variant:"ghost",size:"sm",onClick:()=>D(!1),className:"hidden lg:items-center lg:justify-center lg:flex h-6 w-6 p-0 fixed z-50 top-20 -translate-y-1 -translate-x-1/2 left-[calc(var(--main-sidebar-width,240px))] bg-background border",children:(0,t.jsx)(x.ChevronRight,{className:"h-4 w-4"})}),(0,t.jsx)(b.Button,{onClick:()=>E(!0),size:"icon",className:"lg:hidden fixed bottom-6 left-6 h-12 w-12 rounded-full shadow-lg z-40 hover:scale-110 transition-transform","aria-label":"Show specifications list",children:(0,t.jsx)(v.List,{className:"h-5 w-5"})})]})]})}e.s(["primeSpecsSidebar",()=>H,"setActiveSidebarSpec",()=>L,"updateSidebarScrollTop",()=>B,"useSpecsSidebarState",()=>A],12542),e.s(["SpecsNavSidebar",()=>V],3622)},56654,e=>{"use strict";var t=e.i(90022),r=e.i(3622),s=e.i(65458);function n({className:e,...r}){return(0,t.jsx)("div",{className:(0,s.cn)("animate-pulse rounded-md bg-muted",e),...r})}var i=e.i(12542);function a(){let e=(0,i.useSpecsSidebarState)(),s=e.specs,a=e.activeSpecId||"";return(0,t.jsxs)("div",{className:"flex min-h-[calc(100vh-3.5rem)] w-full min-w-0",children:[(0,t.jsx)(r.SpecsNavSidebar,{initialSpecs:s,currentSpecId:a}),(0,t.jsx)("div",{className:"flex-1 min-w-0 px-4 py-6 sm:px-8 sm:py-10",children:(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(n,{className:"h-7 w-56"}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-3",children:[(0,t.jsx)(n,{className:"h-6 w-24"}),(0,t.jsx)(n,{className:"h-6 w-24"}),(0,t.jsx)(n,{className:"h-6 w-20"})]}),(0,t.jsx)(n,{className:"h-4 w-64"})]}),(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(n,{className:"h-5 w-40"}),(0,t.jsx)(n,{className:"h-32 w-full"})]}),(0,t.jsx)("div",{className:"space-y-4",children:[...Array(6)].map((e,r)=>(0,t.jsx)(n,{className:"h-4 w-full"},r))})]})})]})}e.s(["SpecDetailLoadingShell",()=>a],56654)}]);