@builderos/create-agent-os 0.0.2
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/README.md +39 -0
- package/bin/cli.js +133 -0
- package/package.json +40 -0
- package/src/template/App.tsx +68 -0
- package/src/template/agent-os/commands/create-tasks/1-get-spec-requirements.md +19 -0
- package/src/template/agent-os/commands/create-tasks/2-create-tasks-list.md +234 -0
- package/src/template/agent-os/commands/create-tasks/create-tasks.md +254 -0
- package/src/template/agent-os/commands/design-screen/design-screen.md +32 -0
- package/src/template/agent-os/commands/design-shell/design-shell.md +34 -0
- package/src/template/agent-os/commands/design-tokens/design-tokens.md +36 -0
- package/src/template/agent-os/commands/export-product/export-product.md +44 -0
- package/src/template/agent-os/commands/implement-tasks/1-determine-tasks.md +13 -0
- package/src/template/agent-os/commands/implement-tasks/2-implement-tasks.md +63 -0
- package/src/template/agent-os/commands/implement-tasks/3-verify-implementation.md +113 -0
- package/src/template/agent-os/commands/implement-tasks/implement-tasks.md +207 -0
- package/src/template/agent-os/commands/initialize-design/initialize-design.md +54 -0
- package/src/template/agent-os/commands/orchestrate-tasks/orchestrate-tasks.md +180 -0
- package/src/template/agent-os/commands/plan-product/1-product-concept.md +53 -0
- package/src/template/agent-os/commands/plan-product/2-create-mission.md +78 -0
- package/src/template/agent-os/commands/plan-product/3-create-roadmap.md +73 -0
- package/src/template/agent-os/commands/plan-product/4-create-tech-stack.md +46 -0
- package/src/template/agent-os/commands/plan-product/plan-product.md +241 -0
- package/src/template/agent-os/commands/sample-data/sample-data.md +51 -0
- package/src/template/agent-os/commands/scaffold-implementation/scaffold-implementation.md +36 -0
- package/src/template/agent-os/commands/screenshot-design/screenshot-design.md +21 -0
- package/src/template/agent-os/commands/shape-spec/1-initialize-spec.md +95 -0
- package/src/template/agent-os/commands/shape-spec/2-shape-spec.md +300 -0
- package/src/template/agent-os/commands/shape-spec/shape-spec.md +40 -0
- package/src/template/agent-os/commands/write-spec/write-spec.md +134 -0
- package/src/template/agent-os/config.yml +13 -0
- package/src/template/agent-os/product/mission.md +29 -0
- package/src/template/agent-os/product/roadmap.md +9 -0
- package/src/template/agent-os/product/tech-stack.md +14 -0
- package/src/template/agent-os/specs/README.md +1 -0
- package/src/template/agent-os/standards/backend/api.md +10 -0
- package/src/template/agent-os/standards/backend/migrations.md +9 -0
- package/src/template/agent-os/standards/backend/models.md +10 -0
- package/src/template/agent-os/standards/backend/queries.md +9 -0
- package/src/template/agent-os/standards/frontend/accessibility.md +10 -0
- package/src/template/agent-os/standards/frontend/components.md +11 -0
- package/src/template/agent-os/standards/frontend/css.md +7 -0
- package/src/template/agent-os/standards/frontend/responsive.md +11 -0
- package/src/template/agent-os/standards/global/coding-style.md +10 -0
- package/src/template/agent-os/standards/global/commenting.md +5 -0
- package/src/template/agent-os/standards/global/conventions.md +11 -0
- package/src/template/agent-os/standards/global/error-handling.md +9 -0
- package/src/template/agent-os/standards/global/tech-stack.md +31 -0
- package/src/template/agent-os/standards/global/validation.md +11 -0
- package/src/template/agent-os/standards/testing/test-writing.md +9 -0
- package/src/template/agent-os-ui/README.md +73 -0
- package/src/template/agent-os-ui/package-lock.json +5028 -0
- package/src/template/agent-os-ui/package.json +52 -0
- package/src/template/agent-os-ui/postcss.config.js +6 -0
- package/src/template/agent-os-ui/src/components/AgentShell.tsx +31 -0
- package/src/template/agent-os-ui/src/components/AgentSidebar.tsx +65 -0
- package/src/template/agent-os-ui/src/components/GuidanceCard.tsx +75 -0
- package/src/template/agent-os-ui/src/components/MarkdownViewer.tsx +25 -0
- package/src/template/agent-os-ui/src/components/PromptButton.tsx +28 -0
- package/src/template/agent-os-ui/src/components/StatusItem.tsx +45 -0
- package/src/template/agent-os-ui/src/components/ThemeToggle.tsx +72 -0
- package/src/template/agent-os-ui/src/index.ts +11 -0
- package/src/template/agent-os-ui/src/style.css +3 -0
- package/src/template/agent-os-ui/tailwind.config.js +50 -0
- package/src/template/agent-os-ui/tsconfig.json +33 -0
- package/src/template/agent-os-ui/vite.config.ts +32 -0
- package/src/template/control-center/backend/backend.log +2 -0
- package/src/template/control-center/backend/index.js +228 -0
- package/src/template/control-center/backend/package-lock.json +951 -0
- package/src/template/control-center/backend/package.json +19 -0
- package/src/template/control-center/frontend/README.md +73 -0
- package/src/template/control-center/frontend/eslint.config.js +23 -0
- package/src/template/control-center/frontend/index.html +21 -0
- package/src/template/control-center/frontend/package-lock.json +5752 -0
- package/src/template/control-center/frontend/package.json +42 -0
- package/src/template/control-center/frontend/public/runtime-config.json +11 -0
- package/src/template/control-center/frontend/public/vite.svg +1 -0
- package/src/template/control-center/frontend/src/App.css +42 -0
- package/src/template/control-center/frontend/src/App.tsx +738 -0
- package/src/template/control-center/frontend/src/assets/react.svg +1 -0
- package/src/template/control-center/frontend/src/components/ThemeToggle.tsx +64 -0
- package/src/template/control-center/frontend/src/components/ui/ToastContext.tsx +81 -0
- package/src/template/control-center/frontend/src/index.css +194 -0
- package/src/template/control-center/frontend/src/main.tsx +14 -0
- package/src/template/control-center/frontend/src/vite-env.d.ts +1 -0
- package/src/template/control-center/frontend/tsconfig.app.json +28 -0
- package/src/template/control-center/frontend/tsconfig.json +7 -0
- package/src/template/control-center/frontend/tsconfig.node.json +26 -0
- package/src/template/control-center/frontend/vite.config.ts +22 -0
- package/src/template/design/.claude/commands/design-os/data-model.md +122 -0
- package/src/template/design/.claude/commands/design-os/design-screen.md +309 -0
- package/src/template/design/.claude/commands/design-os/design-shell.md +238 -0
- package/src/template/design/.claude/commands/design-os/design-tokens.md +166 -0
- package/src/template/design/.claude/commands/design-os/export-product.md +1105 -0
- package/src/template/design/.claude/commands/design-os/product-roadmap.md +121 -0
- package/src/template/design/.claude/commands/design-os/product-vision.md +99 -0
- package/src/template/design/.claude/commands/design-os/sample-data.md +263 -0
- package/src/template/design/.claude/commands/design-os/screenshot-design.md +112 -0
- package/src/template/design/.claude/commands/design-os/shape-section.md +138 -0
- package/src/template/design/.claude/skills/frontend-design/SKILL.md +42 -0
- package/src/template/design/.github/CODE_OF_CONDUCT.md +5 -0
- package/src/template/design/.github/CONTRIBUTING.md +51 -0
- package/src/template/design/.github/ISSUE_TEMPLATE/config.yml +22 -0
- package/src/template/design/.github/PULL_REQUEST_TEMPLATE.md +20 -0
- package/src/template/design/.github/SECURITY.yml +5 -0
- package/src/template/design/.github/SUPPORT.md +19 -0
- package/src/template/design/.github/workflows/pr-decline.yml +135 -0
- package/src/template/design/.github/workflows/stale.yml +25 -0
- package/src/template/design/CHANGELOG.md +13 -0
- package/src/template/design/LICENSE +21 -0
- package/src/template/design/README.md +54 -0
- package/src/template/design/agents.md +218 -0
- package/src/template/design/claude.md +1 -0
- package/src/template/design/components.json +22 -0
- package/src/template/design/docs/codebase-implementation.md +153 -0
- package/src/template/design/docs/design-section.md +135 -0
- package/src/template/design/docs/export.md +149 -0
- package/src/template/design/docs/getting-started.md +59 -0
- package/src/template/design/docs/index.md +56 -0
- package/src/template/design/docs/product-planning.md +113 -0
- package/src/template/design/docs/requirements.md +22 -0
- package/src/template/design/docs/usage.md +62 -0
- package/src/template/design/eslint.config.js +23 -0
- package/src/template/design/index.html +21 -0
- package/src/template/design/package-lock.json +5473 -0
- package/src/template/design/package.json +47 -0
- package/src/template/design/product-plan.zip +0 -0
- package/src/template/design/public/vite.svg +1 -0
- package/src/template/design/src/assets/react.svg +1 -0
- package/src/template/design/src/components/AppLayout.tsx +95 -0
- package/src/template/design/src/components/DataCard.tsx +139 -0
- package/src/template/design/src/components/DataModelPage.tsx +120 -0
- package/src/template/design/src/components/DesignPage.tsx +284 -0
- package/src/template/design/src/components/EmptyState.tsx +155 -0
- package/src/template/design/src/components/ExportPage.tsx +344 -0
- package/src/template/design/src/components/NextPhaseButton.tsx +33 -0
- package/src/template/design/src/components/PhaseNav.tsx +152 -0
- package/src/template/design/src/components/PhaseWarningBanner.tsx +81 -0
- package/src/template/design/src/components/ProductOverviewCard.tsx +102 -0
- package/src/template/design/src/components/ProductPage.tsx +97 -0
- package/src/template/design/src/components/ScreenDesignPage.tsx +370 -0
- package/src/template/design/src/components/ScreenDesignsCard.tsx +49 -0
- package/src/template/design/src/components/SectionPage.tsx +256 -0
- package/src/template/design/src/components/SectionsCard.tsx +47 -0
- package/src/template/design/src/components/SectionsPage.tsx +181 -0
- package/src/template/design/src/components/ShellCard.tsx +85 -0
- package/src/template/design/src/components/ShellDesignPage.tsx +242 -0
- package/src/template/design/src/components/SpecCard.tsx +121 -0
- package/src/template/design/src/components/StepIndicator.tsx +75 -0
- package/src/template/design/src/components/ThemeToggle.tsx +86 -0
- package/src/template/design/src/components/ui/ToastContext.tsx +81 -0
- package/src/template/design/src/components/ui/avatar.tsx +53 -0
- package/src/template/design/src/components/ui/badge.tsx +46 -0
- package/src/template/design/src/components/ui/button.tsx +60 -0
- package/src/template/design/src/components/ui/card.tsx +92 -0
- package/src/template/design/src/components/ui/collapsible.tsx +48 -0
- package/src/template/design/src/components/ui/dialog.tsx +143 -0
- package/src/template/design/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/template/design/src/components/ui/input.tsx +21 -0
- package/src/template/design/src/components/ui/label.tsx +22 -0
- package/src/template/design/src/components/ui/progress.tsx +24 -0
- package/src/template/design/src/components/ui/scroll-area.tsx +18 -0
- package/src/template/design/src/components/ui/select.tsx +67 -0
- package/src/template/design/src/components/ui/separator.tsx +28 -0
- package/src/template/design/src/components/ui/sheet.tsx +137 -0
- package/src/template/design/src/components/ui/skeleton.tsx +13 -0
- package/src/template/design/src/components/ui/switch.tsx +46 -0
- package/src/template/design/src/components/ui/table.tsx +116 -0
- package/src/template/design/src/components/ui/tabs.tsx +64 -0
- package/src/template/design/src/index.css +284 -0
- package/src/template/design/src/lib/data-model-loader.ts +91 -0
- package/src/template/design/src/lib/design-system-loader.ts +101 -0
- package/src/template/design/src/lib/product-loader.ts +221 -0
- package/src/template/design/src/lib/router.tsx +52 -0
- package/src/template/design/src/lib/section-loader.ts +272 -0
- package/src/template/design/src/lib/shell-loader.ts +175 -0
- package/src/template/design/src/lib/utils.ts +6 -0
- package/src/template/design/src/main.tsx +15 -0
- package/src/template/design/src/sections/.gitkeep +0 -0
- package/src/template/design/src/sections/ai-orchestration-engine-oai/OrchestrationEngine.tsx +348 -0
- package/src/template/design/src/sections/core-platform-shell/AppShell.tsx +403 -0
- package/src/template/design/src/sections/gemini-live-integration/GeminiIntegration.tsx +332 -0
- package/src/template/design/src/sections/interactive-2d-canvas/WhiteboardCanvas.tsx +334 -0
- package/src/template/design/src/sections/participation-equity-tracker/EquityTracker.tsx +383 -0
- package/src/template/design/src/sections/persistent-memory-system/PersistentMemory.tsx +308 -0
- package/src/template/design/src/sections/real-time-communication-layer/VideoSession.tsx +342 -0
- package/src/template/design/src/sections/visual-intelligence-agents/VisualAgents.tsx +311 -0
- package/src/template/design/src/types/product.ts +97 -0
- package/src/template/design/src/types/section.ts +33 -0
- package/src/template/design/tsconfig.app.json +34 -0
- package/src/template/design/tsconfig.json +13 -0
- package/src/template/design/tsconfig.node.json +26 -0
- package/src/template/design/vite.config.ts +18 -0
- package/src/template/package.json +27 -0
- package/src/template/vite.config.ts +16 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
|
|
4
|
+
@custom-variant dark (&:is(.dark *));
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
Design OS - Refined Utility Design System
|
|
8
|
+
A professional, editorial-inspired aesthetic with warm neutrals
|
|
9
|
+
Using Tailwind's stone palette for warmth
|
|
10
|
+
*/
|
|
11
|
+
@theme {
|
|
12
|
+
/* Font families - DM Sans for clean, geometric type */
|
|
13
|
+
--font-display: "DM Sans", system-ui, sans-serif;
|
|
14
|
+
--font-body: "DM Sans", system-ui, sans-serif;
|
|
15
|
+
--font-sans: "DM Sans", system-ui, sans-serif;
|
|
16
|
+
--font-mono: "IBM Plex Mono", ui-monospace, monospace;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Shadcn theme integration */
|
|
20
|
+
@theme inline {
|
|
21
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
22
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
23
|
+
--radius-lg: var(--radius);
|
|
24
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
25
|
+
--color-background: var(--background);
|
|
26
|
+
--color-foreground: var(--foreground);
|
|
27
|
+
--color-card: var(--card);
|
|
28
|
+
--color-card-foreground: var(--card-foreground);
|
|
29
|
+
--color-popover: var(--popover);
|
|
30
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
31
|
+
--color-primary: var(--primary);
|
|
32
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
33
|
+
--color-secondary: var(--secondary);
|
|
34
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
35
|
+
--color-muted: var(--muted);
|
|
36
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
37
|
+
--color-accent: var(--accent);
|
|
38
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
39
|
+
--color-destructive: var(--destructive);
|
|
40
|
+
--color-border: var(--border);
|
|
41
|
+
--color-input: var(--input);
|
|
42
|
+
--color-ring: var(--ring);
|
|
43
|
+
--color-chart-1: var(--chart-1);
|
|
44
|
+
--color-chart-2: var(--chart-2);
|
|
45
|
+
--color-chart-3: var(--chart-3);
|
|
46
|
+
--color-chart-4: var(--chart-4);
|
|
47
|
+
--color-chart-5: var(--chart-5);
|
|
48
|
+
--color-sidebar: var(--sidebar);
|
|
49
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
50
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
51
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
52
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
53
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
54
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
55
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
Light theme - Warm Stone palette
|
|
60
|
+
Professional, editorial aesthetic with warmth
|
|
61
|
+
*/
|
|
62
|
+
:root {
|
|
63
|
+
--radius: 0.5rem;
|
|
64
|
+
/* Backgrounds & Foregrounds - Stone palette for warmth */
|
|
65
|
+
--background: oklch(0.985 0.001 106.424);
|
|
66
|
+
/* stone-50 #FAFAF9 */
|
|
67
|
+
--foreground: oklch(0.216 0.006 56.043);
|
|
68
|
+
/* stone-900 #1C1917 */
|
|
69
|
+
--card: oklch(1 0 0);
|
|
70
|
+
/* white */
|
|
71
|
+
--card-foreground: oklch(0.216 0.006 56.043);
|
|
72
|
+
/* stone-900 */
|
|
73
|
+
--popover: oklch(1 0 0);
|
|
74
|
+
/* white */
|
|
75
|
+
--popover-foreground: oklch(0.216 0.006 56.043);
|
|
76
|
+
/* stone-900 */
|
|
77
|
+
/* Primary - Stone dark */
|
|
78
|
+
--primary: oklch(0.216 0.006 56.043);
|
|
79
|
+
/* stone-900 */
|
|
80
|
+
--primary-foreground: oklch(0.985 0.001 106.424);
|
|
81
|
+
/* stone-50 */
|
|
82
|
+
/* Secondary - Stone light */
|
|
83
|
+
--secondary: oklch(0.970 0.001 106.424);
|
|
84
|
+
/* stone-100 */
|
|
85
|
+
--secondary-foreground: oklch(0.216 0.006 56.043);
|
|
86
|
+
/* stone-900 */
|
|
87
|
+
/* Muted - Stone for subdued text */
|
|
88
|
+
--muted: oklch(0.970 0.001 106.424);
|
|
89
|
+
/* stone-100 */
|
|
90
|
+
--muted-foreground: oklch(0.370 0.010 67.558);
|
|
91
|
+
/* stone-700 variant */
|
|
92
|
+
/* Accent - Lime green for subtle pops */
|
|
93
|
+
--accent: oklch(0.970 0.001 106.424);
|
|
94
|
+
/* stone-100 */
|
|
95
|
+
--accent-foreground: oklch(0.216 0.006 56.043);
|
|
96
|
+
/* stone-900 */
|
|
97
|
+
/* Destructive - Rose */
|
|
98
|
+
--destructive: oklch(0.586 0.253 17.585);
|
|
99
|
+
/* rose-600 */
|
|
100
|
+
/* Borders & Inputs - Stone very light */
|
|
101
|
+
--border: oklch(0.923 0.003 48.717);
|
|
102
|
+
/* stone-200 #E7E5E4 */
|
|
103
|
+
--input: oklch(0.923 0.003 48.717);
|
|
104
|
+
/* stone-200 */
|
|
105
|
+
--ring: oklch(0.553 0.013 58.071);
|
|
106
|
+
/* stone-500 */
|
|
107
|
+
/* Chart colors */
|
|
108
|
+
--chart-1: oklch(0.532 0.157 131.589);
|
|
109
|
+
/* lime-600 #65A30D */
|
|
110
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
111
|
+
/* teal-600 */
|
|
112
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
113
|
+
/* cyan-800 */
|
|
114
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
115
|
+
/* yellow-400 */
|
|
116
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
117
|
+
/* amber-400 */
|
|
118
|
+
/* Sidebar - Stone */
|
|
119
|
+
--sidebar: oklch(0.985 0.001 106.424);
|
|
120
|
+
/* stone-50 */
|
|
121
|
+
--sidebar-foreground: oklch(0.216 0.006 56.043);
|
|
122
|
+
/* stone-900 */
|
|
123
|
+
--sidebar-primary: oklch(0.216 0.006 56.043);
|
|
124
|
+
/* stone-900 */
|
|
125
|
+
--sidebar-primary-foreground: oklch(0.985 0.001 106.424);
|
|
126
|
+
/* stone-50 */
|
|
127
|
+
--sidebar-accent: oklch(0.970 0.001 106.424);
|
|
128
|
+
/* stone-100 */
|
|
129
|
+
--sidebar-accent-foreground: oklch(0.216 0.006 56.043);
|
|
130
|
+
/* stone-900 */
|
|
131
|
+
--sidebar-border: oklch(0.923 0.003 48.717);
|
|
132
|
+
/* stone-200 */
|
|
133
|
+
--sidebar-ring: oklch(0.553 0.013 58.071);
|
|
134
|
+
/* stone-500 */
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/*
|
|
138
|
+
Dark theme - Warm Stone dark palette
|
|
139
|
+
*/
|
|
140
|
+
.dark {
|
|
141
|
+
/* Backgrounds & Foregrounds - Stone dark */
|
|
142
|
+
--background: oklch(0.216 0.006 56.043);
|
|
143
|
+
/* stone-900 #1C1917 */
|
|
144
|
+
--foreground: oklch(0.985 0.001 106.424);
|
|
145
|
+
/* stone-50 */
|
|
146
|
+
--card: oklch(0.268 0.007 34.298);
|
|
147
|
+
/* stone-800 #292524 */
|
|
148
|
+
--card-foreground: oklch(0.985 0.001 106.424);
|
|
149
|
+
/* stone-50 */
|
|
150
|
+
--popover: oklch(0.268 0.007 34.298);
|
|
151
|
+
/* stone-800 */
|
|
152
|
+
--popover-foreground: oklch(0.985 0.001 106.424);
|
|
153
|
+
/* stone-50 */
|
|
154
|
+
/* Primary - Stone light */
|
|
155
|
+
--primary: oklch(0.923 0.003 48.717);
|
|
156
|
+
/* stone-200 */
|
|
157
|
+
--primary-foreground: oklch(0.216 0.006 56.043);
|
|
158
|
+
/* stone-900 */
|
|
159
|
+
/* Secondary - Stone dark */
|
|
160
|
+
--secondary: oklch(0.318 0.008 43.185);
|
|
161
|
+
/* stone-700 */
|
|
162
|
+
--secondary-foreground: oklch(0.985 0.001 106.424);
|
|
163
|
+
/* stone-50 */
|
|
164
|
+
/* Muted - Stone dark */
|
|
165
|
+
--muted: oklch(0.318 0.008 43.185);
|
|
166
|
+
/* stone-700 */
|
|
167
|
+
--muted-foreground: oklch(0.709 0.01 56.259);
|
|
168
|
+
/* stone-400 #A8A29E */
|
|
169
|
+
/* Accent - Stone dark */
|
|
170
|
+
--accent: oklch(0.318 0.008 43.185);
|
|
171
|
+
/* stone-700 */
|
|
172
|
+
--accent-foreground: oklch(0.985 0.001 106.424);
|
|
173
|
+
/* stone-50 */
|
|
174
|
+
/* Destructive - Rose lighter for dark mode */
|
|
175
|
+
--destructive: oklch(0.712 0.194 13.428);
|
|
176
|
+
/* rose-400 */
|
|
177
|
+
/* Borders & Inputs - Stone dark */
|
|
178
|
+
--border: oklch(0.370 0.010 67.558);
|
|
179
|
+
/* stone-600 */
|
|
180
|
+
--input: oklch(0.370 0.010 67.558);
|
|
181
|
+
/* stone-600 */
|
|
182
|
+
--ring: oklch(0.553 0.013 58.071);
|
|
183
|
+
/* stone-500 */
|
|
184
|
+
/* Chart colors - brighter for dark mode */
|
|
185
|
+
--chart-1: oklch(0.648 0.2 131.684);
|
|
186
|
+
/* lime-500 */
|
|
187
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
188
|
+
/* emerald-400 */
|
|
189
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
190
|
+
/* amber-400 */
|
|
191
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
192
|
+
/* purple-500 */
|
|
193
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
194
|
+
/* rose-500 */
|
|
195
|
+
/* Sidebar - Stone dark */
|
|
196
|
+
--sidebar: oklch(0.268 0.007 34.298);
|
|
197
|
+
/* stone-800 */
|
|
198
|
+
--sidebar-foreground: oklch(0.985 0.001 106.424);
|
|
199
|
+
/* stone-50 */
|
|
200
|
+
--sidebar-primary: oklch(0.648 0.2 131.684);
|
|
201
|
+
/* lime-500 */
|
|
202
|
+
--sidebar-primary-foreground: oklch(0.216 0.006 56.043);
|
|
203
|
+
/* stone-900 */
|
|
204
|
+
--sidebar-accent: oklch(0.318 0.008 43.185);
|
|
205
|
+
/* stone-700 */
|
|
206
|
+
--sidebar-accent-foreground: oklch(0.985 0.001 106.424);
|
|
207
|
+
/* stone-50 */
|
|
208
|
+
--sidebar-border: oklch(0.370 0.010 67.558);
|
|
209
|
+
/* stone-600 */
|
|
210
|
+
--sidebar-ring: oklch(0.553 0.013 58.071);
|
|
211
|
+
/* stone-500 */
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Base layer styles */
|
|
215
|
+
@layer base {
|
|
216
|
+
* {
|
|
217
|
+
@apply border-border outline-ring/50;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
body {
|
|
221
|
+
@apply bg-background text-foreground font-sans antialiased;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
h1,
|
|
225
|
+
h2,
|
|
226
|
+
h3,
|
|
227
|
+
h4,
|
|
228
|
+
h5,
|
|
229
|
+
h6 {
|
|
230
|
+
font-family: var(--font-display);
|
|
231
|
+
@apply font-semibold tracking-tight;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
code,
|
|
235
|
+
pre,
|
|
236
|
+
kbd {
|
|
237
|
+
font-family: var(--font-mono);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Subtle page fade-in animation */
|
|
242
|
+
@layer utilities {
|
|
243
|
+
.animate-fade-in {
|
|
244
|
+
animation: fade-in 200ms ease-out;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@keyframes fade-in {
|
|
248
|
+
from {
|
|
249
|
+
opacity: 0;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
to {
|
|
253
|
+
opacity: 1;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.animate-collapse-down {
|
|
258
|
+
animation: collapse-down 200ms ease-out;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.animate-collapse-up {
|
|
262
|
+
animation: collapse-up 200ms ease-out;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@keyframes collapse-down {
|
|
266
|
+
from {
|
|
267
|
+
height: 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
to {
|
|
271
|
+
height: var(--radix-collapsible-content-height);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@keyframes collapse-up {
|
|
276
|
+
from {
|
|
277
|
+
height: var(--radix-collapsible-content-height);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
to {
|
|
281
|
+
height: 0;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data model loading and parsing utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { DataModel, Entity } from '@/types/product'
|
|
6
|
+
|
|
7
|
+
// Load data model markdown file at build time
|
|
8
|
+
const dataModelFiles = import.meta.glob('/product/data-model/*.md', {
|
|
9
|
+
query: '?raw',
|
|
10
|
+
import: 'default',
|
|
11
|
+
eager: true,
|
|
12
|
+
}) as Record<string, string>
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse data-model.md content into DataModel structure
|
|
16
|
+
*
|
|
17
|
+
* Expected format:
|
|
18
|
+
* # Data Model
|
|
19
|
+
*
|
|
20
|
+
* ## Entities
|
|
21
|
+
*
|
|
22
|
+
* ### EntityName
|
|
23
|
+
* Description of what this entity represents.
|
|
24
|
+
*
|
|
25
|
+
* ### AnotherEntity
|
|
26
|
+
* Description of this entity.
|
|
27
|
+
*
|
|
28
|
+
* ## Relationships
|
|
29
|
+
*
|
|
30
|
+
* - Entity has many OtherEntity
|
|
31
|
+
* - OtherEntity belongs to Entity
|
|
32
|
+
*/
|
|
33
|
+
export function parseDataModel(md: string): DataModel | null {
|
|
34
|
+
if (!md || !md.trim()) return null
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const entities: Entity[] = []
|
|
38
|
+
const relationships: string[] = []
|
|
39
|
+
|
|
40
|
+
// Extract entities section
|
|
41
|
+
const entitiesSection = md.match(/## Entities\s*\n+([\s\S]*?)(?=\n## |\n#[^#]|$)/)
|
|
42
|
+
|
|
43
|
+
if (entitiesSection?.[1]) {
|
|
44
|
+
// Match ### EntityName followed by description
|
|
45
|
+
const entityMatches = [...entitiesSection[1].matchAll(/### ([^\n]+)\n+([\s\S]*?)(?=\n### |\n## |$)/g)]
|
|
46
|
+
for (const match of entityMatches) {
|
|
47
|
+
entities.push({
|
|
48
|
+
name: match[1].trim(),
|
|
49
|
+
description: match[2].trim(),
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Extract relationships section
|
|
55
|
+
const relationshipsSection = md.match(/## Relationships\s*\n+([\s\S]*?)(?=\n## |\n#[^#]|$)/)
|
|
56
|
+
|
|
57
|
+
if (relationshipsSection?.[1]) {
|
|
58
|
+
const lines = relationshipsSection[1].split('\n')
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
const trimmed = line.trim()
|
|
61
|
+
if (trimmed.startsWith('- ')) {
|
|
62
|
+
relationships.push(trimmed.slice(2).trim())
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Return null if we couldn't parse anything meaningful
|
|
68
|
+
if (entities.length === 0 && relationships.length === 0) {
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { entities, relationships }
|
|
73
|
+
} catch {
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Load the data model from markdown file
|
|
80
|
+
*/
|
|
81
|
+
export function loadDataModel(): DataModel | null {
|
|
82
|
+
const content = dataModelFiles['/product/data-model/data-model.md']
|
|
83
|
+
return content ? parseDataModel(content) : null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if data model has been defined
|
|
88
|
+
*/
|
|
89
|
+
export function hasDataModel(): boolean {
|
|
90
|
+
return '/product/data-model/data-model.md' in dataModelFiles
|
|
91
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design system loading utilities for colors and typography
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { DesignSystem, ColorTokens, TypographyTokens } from '@/types/product'
|
|
6
|
+
|
|
7
|
+
// Load JSON files from product/design-system at build time
|
|
8
|
+
const designSystemFiles = import.meta.glob('/product/design-system/*.json', {
|
|
9
|
+
eager: true,
|
|
10
|
+
}) as Record<string, { default: Record<string, string> }>
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Load color tokens from colors.json
|
|
14
|
+
*
|
|
15
|
+
* Expected format:
|
|
16
|
+
* {
|
|
17
|
+
* "primary": "lime",
|
|
18
|
+
* "secondary": "teal",
|
|
19
|
+
* "neutral": "stone"
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export function loadColorTokens(): ColorTokens | null {
|
|
23
|
+
const colorsModule = designSystemFiles['/product/design-system/colors.json']
|
|
24
|
+
if (!colorsModule?.default) return null
|
|
25
|
+
|
|
26
|
+
const colors = colorsModule.default
|
|
27
|
+
if (!colors.primary || !colors.secondary || !colors.neutral) {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
primary: colors.primary,
|
|
33
|
+
secondary: colors.secondary,
|
|
34
|
+
neutral: colors.neutral,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Load typography tokens from typography.json
|
|
40
|
+
*
|
|
41
|
+
* Expected format:
|
|
42
|
+
* {
|
|
43
|
+
* "heading": "DM Sans",
|
|
44
|
+
* "body": "DM Sans",
|
|
45
|
+
* "mono": "IBM Plex Mono"
|
|
46
|
+
* }
|
|
47
|
+
*/
|
|
48
|
+
export function loadTypographyTokens(): TypographyTokens | null {
|
|
49
|
+
const typographyModule = designSystemFiles['/product/design-system/typography.json']
|
|
50
|
+
if (!typographyModule?.default) return null
|
|
51
|
+
|
|
52
|
+
const typography = typographyModule.default
|
|
53
|
+
if (!typography.heading || !typography.body) {
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
heading: typography.heading,
|
|
59
|
+
body: typography.body,
|
|
60
|
+
mono: typography.mono || 'IBM Plex Mono',
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Load the complete design system
|
|
66
|
+
*/
|
|
67
|
+
export function loadDesignSystem(): DesignSystem | null {
|
|
68
|
+
const colors = loadColorTokens()
|
|
69
|
+
const typography = loadTypographyTokens()
|
|
70
|
+
|
|
71
|
+
// Return null if neither colors nor typography are defined
|
|
72
|
+
if (!colors && !typography) {
|
|
73
|
+
return null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return { colors, typography }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if design system has been defined (at least colors or typography)
|
|
81
|
+
*/
|
|
82
|
+
export function hasDesignSystem(): boolean {
|
|
83
|
+
return (
|
|
84
|
+
'/product/design-system/colors.json' in designSystemFiles ||
|
|
85
|
+
'/product/design-system/typography.json' in designSystemFiles
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if colors have been defined
|
|
91
|
+
*/
|
|
92
|
+
export function hasColors(): boolean {
|
|
93
|
+
return '/product/design-system/colors.json' in designSystemFiles
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Check if typography has been defined
|
|
98
|
+
*/
|
|
99
|
+
export function hasTypography(): boolean {
|
|
100
|
+
return '/product/design-system/typography.json' in designSystemFiles
|
|
101
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product data loading and markdown parsing utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ProductOverview, ProductRoadmap, Problem, Section, ProductData } from '@/types/product'
|
|
6
|
+
import { loadDataModel, hasDataModel } from './data-model-loader'
|
|
7
|
+
import { loadDesignSystem, hasDesignSystem } from './design-system-loader'
|
|
8
|
+
import { loadShellInfo, hasShell } from './shell-loader'
|
|
9
|
+
|
|
10
|
+
// Load markdown files from /product/ directory at build time
|
|
11
|
+
const productFiles = import.meta.glob('/product/*.md', {
|
|
12
|
+
query: '?raw',
|
|
13
|
+
import: 'default',
|
|
14
|
+
eager: true,
|
|
15
|
+
}) as Record<string, string>
|
|
16
|
+
|
|
17
|
+
// Load zip files from root directory at build time
|
|
18
|
+
const exportZipFiles = import.meta.glob('/product-plan.zip', {
|
|
19
|
+
query: '?url',
|
|
20
|
+
import: 'default',
|
|
21
|
+
eager: true,
|
|
22
|
+
}) as Record<string, string>
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Slugify a string for use as an ID
|
|
26
|
+
*/
|
|
27
|
+
function slugify(str: string): string {
|
|
28
|
+
return str
|
|
29
|
+
.toLowerCase()
|
|
30
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
31
|
+
.replace(/(^-|-$)/g, '')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parse product-overview.md content into ProductOverview structure
|
|
36
|
+
*
|
|
37
|
+
* Expected format:
|
|
38
|
+
* # [Product Name]
|
|
39
|
+
*
|
|
40
|
+
* ## Description
|
|
41
|
+
* [1-3 sentence product description]
|
|
42
|
+
*
|
|
43
|
+
* ## Problems & Solutions
|
|
44
|
+
*
|
|
45
|
+
* ### Problem 1: [Problem Title]
|
|
46
|
+
* [How the product solves it]
|
|
47
|
+
*
|
|
48
|
+
* ## Key Features
|
|
49
|
+
* - Feature 1
|
|
50
|
+
* - Feature 2
|
|
51
|
+
*/
|
|
52
|
+
export function parseProductOverview(md: string): ProductOverview | null {
|
|
53
|
+
if (!md || !md.trim()) return null
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
// Extract product name from first # heading
|
|
57
|
+
const nameMatch = md.match(/^#\s+(.+)$/m)
|
|
58
|
+
const name = nameMatch?.[1]?.trim() || 'Product Overview'
|
|
59
|
+
|
|
60
|
+
// Extract description - content between ## Description and next ##
|
|
61
|
+
const descMatch = md.match(/## Description\s*\n+([\s\S]*?)(?=\n## |\n#[^#]|$)/)
|
|
62
|
+
const description = descMatch?.[1]?.trim() || ''
|
|
63
|
+
|
|
64
|
+
// Extract problems - ### Problem N: Title pattern
|
|
65
|
+
const problemsSection = md.match(/## Problems & Solutions\s*\n+([\s\S]*?)(?=\n## |\n#[^#]|$)/)
|
|
66
|
+
const problems: Problem[] = []
|
|
67
|
+
|
|
68
|
+
if (problemsSection?.[1]) {
|
|
69
|
+
const problemMatches = [...problemsSection[1].matchAll(/### Problem \d+:\s*(.+)\n+([\s\S]*?)(?=\n### |\n## |$)/g)]
|
|
70
|
+
for (const match of problemMatches) {
|
|
71
|
+
problems.push({
|
|
72
|
+
title: match[1].trim(),
|
|
73
|
+
solution: match[2].trim(),
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Extract features - bullet list after ## Key Features
|
|
79
|
+
const featuresSection = md.match(/## Key Features\s*\n+([\s\S]*?)(?=\n## |\n#[^#]|$)/)
|
|
80
|
+
const features: string[] = []
|
|
81
|
+
|
|
82
|
+
if (featuresSection?.[1]) {
|
|
83
|
+
const lines = featuresSection[1].split('\n')
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
const trimmed = line.trim()
|
|
86
|
+
if (trimmed.startsWith('- ')) {
|
|
87
|
+
features.push(trimmed.slice(2).trim())
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Return null if we couldn't parse anything meaningful
|
|
93
|
+
if (!description && problems.length === 0 && features.length === 0) {
|
|
94
|
+
return null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { name, description, problems, features }
|
|
98
|
+
} catch {
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Parse product-roadmap.md content into ProductRoadmap structure
|
|
105
|
+
*
|
|
106
|
+
* Expected format:
|
|
107
|
+
* # Product Roadmap
|
|
108
|
+
*
|
|
109
|
+
* ## Sections
|
|
110
|
+
*
|
|
111
|
+
* ### 1. [Section Title]
|
|
112
|
+
* [One sentence description]
|
|
113
|
+
*
|
|
114
|
+
* ### 2. [Section Title]
|
|
115
|
+
* [One sentence description]
|
|
116
|
+
*/
|
|
117
|
+
export function parseProductRoadmap(md: string): ProductRoadmap | null {
|
|
118
|
+
if (!md || !md.trim()) return null
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const sections: Section[] = []
|
|
122
|
+
|
|
123
|
+
// Match sections with pattern: - [ ] **1. Title** \n Description
|
|
124
|
+
// OR pattern: ### 1. Title \n Description (legacy)
|
|
125
|
+
|
|
126
|
+
// Try Legacy Header format first
|
|
127
|
+
let sectionMatches = [...md.matchAll(/### (\d+)\.\s*(.+)\n+([\s\S]*?)(?=\n### |\n## |\n#[^#]|$)/g)]
|
|
128
|
+
|
|
129
|
+
if (sectionMatches.length === 0) {
|
|
130
|
+
// Try Bullet format: - [ ] **N. Title**
|
|
131
|
+
// Regex: - [x] **1. Title**
|
|
132
|
+
const bulletMatches = [...md.matchAll(/-\s+\[([ x])\]\s+\*\*(?:(\d+)\.)?\s*(.+?)\*\*\n\s+([\s\S]+?)(?=\n- |\n### |\n## |$)/g)];
|
|
133
|
+
for (const match of bulletMatches) {
|
|
134
|
+
const numberStr = match[2];
|
|
135
|
+
const title = match[3].trim();
|
|
136
|
+
const description = match[4].trim();
|
|
137
|
+
// Use parsed number or auto-increment if missing
|
|
138
|
+
const order = numberStr ? parseInt(numberStr, 10) : sections.length + 1;
|
|
139
|
+
|
|
140
|
+
sections.push({
|
|
141
|
+
id: slugify(title),
|
|
142
|
+
title,
|
|
143
|
+
description,
|
|
144
|
+
order,
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
// Legacy Loop
|
|
149
|
+
for (const match of sectionMatches) {
|
|
150
|
+
const order = parseInt(match[1], 10)
|
|
151
|
+
const title = match[2].trim()
|
|
152
|
+
const description = match[3].trim()
|
|
153
|
+
|
|
154
|
+
sections.push({
|
|
155
|
+
id: slugify(title),
|
|
156
|
+
title,
|
|
157
|
+
description,
|
|
158
|
+
order,
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Sort by order
|
|
164
|
+
sections.sort((a, b) => a.order - b.order)
|
|
165
|
+
|
|
166
|
+
if (sections.length === 0) {
|
|
167
|
+
return null
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { sections }
|
|
171
|
+
} catch {
|
|
172
|
+
return null
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Load all product data from markdown files and other sources
|
|
178
|
+
*/
|
|
179
|
+
export function loadProductData(): ProductData {
|
|
180
|
+
const overviewContent = productFiles['/product/product-overview.md']
|
|
181
|
+
const roadmapContent = productFiles['/product/product-roadmap.md']
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
overview: overviewContent ? parseProductOverview(overviewContent) : null,
|
|
185
|
+
roadmap: roadmapContent ? parseProductRoadmap(roadmapContent) : null,
|
|
186
|
+
dataModel: loadDataModel(),
|
|
187
|
+
designSystem: loadDesignSystem(),
|
|
188
|
+
shell: loadShellInfo(),
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Check if product overview has been defined
|
|
194
|
+
*/
|
|
195
|
+
export function hasProductOverview(): boolean {
|
|
196
|
+
return '/product/product-overview.md' in productFiles
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Check if product roadmap has been defined
|
|
201
|
+
*/
|
|
202
|
+
export function hasProductRoadmap(): boolean {
|
|
203
|
+
return '/product/product-roadmap.md' in productFiles
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check if export zip file exists
|
|
208
|
+
*/
|
|
209
|
+
export function hasExportZip(): boolean {
|
|
210
|
+
return '/product-plan.zip' in exportZipFiles
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get the URL of the export zip file (if it exists)
|
|
215
|
+
*/
|
|
216
|
+
export function getExportZipUrl(): string | null {
|
|
217
|
+
return exportZipFiles['/product-plan.zip'] || null
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Re-export utility functions for checking individual pieces
|
|
221
|
+
export { hasDataModel, hasDesignSystem, hasShell }
|