@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.
Files changed (194) hide show
  1. package/README.md +39 -0
  2. package/bin/cli.js +133 -0
  3. package/package.json +40 -0
  4. package/src/template/App.tsx +68 -0
  5. package/src/template/agent-os/commands/create-tasks/1-get-spec-requirements.md +19 -0
  6. package/src/template/agent-os/commands/create-tasks/2-create-tasks-list.md +234 -0
  7. package/src/template/agent-os/commands/create-tasks/create-tasks.md +254 -0
  8. package/src/template/agent-os/commands/design-screen/design-screen.md +32 -0
  9. package/src/template/agent-os/commands/design-shell/design-shell.md +34 -0
  10. package/src/template/agent-os/commands/design-tokens/design-tokens.md +36 -0
  11. package/src/template/agent-os/commands/export-product/export-product.md +44 -0
  12. package/src/template/agent-os/commands/implement-tasks/1-determine-tasks.md +13 -0
  13. package/src/template/agent-os/commands/implement-tasks/2-implement-tasks.md +63 -0
  14. package/src/template/agent-os/commands/implement-tasks/3-verify-implementation.md +113 -0
  15. package/src/template/agent-os/commands/implement-tasks/implement-tasks.md +207 -0
  16. package/src/template/agent-os/commands/initialize-design/initialize-design.md +54 -0
  17. package/src/template/agent-os/commands/orchestrate-tasks/orchestrate-tasks.md +180 -0
  18. package/src/template/agent-os/commands/plan-product/1-product-concept.md +53 -0
  19. package/src/template/agent-os/commands/plan-product/2-create-mission.md +78 -0
  20. package/src/template/agent-os/commands/plan-product/3-create-roadmap.md +73 -0
  21. package/src/template/agent-os/commands/plan-product/4-create-tech-stack.md +46 -0
  22. package/src/template/agent-os/commands/plan-product/plan-product.md +241 -0
  23. package/src/template/agent-os/commands/sample-data/sample-data.md +51 -0
  24. package/src/template/agent-os/commands/scaffold-implementation/scaffold-implementation.md +36 -0
  25. package/src/template/agent-os/commands/screenshot-design/screenshot-design.md +21 -0
  26. package/src/template/agent-os/commands/shape-spec/1-initialize-spec.md +95 -0
  27. package/src/template/agent-os/commands/shape-spec/2-shape-spec.md +300 -0
  28. package/src/template/agent-os/commands/shape-spec/shape-spec.md +40 -0
  29. package/src/template/agent-os/commands/write-spec/write-spec.md +134 -0
  30. package/src/template/agent-os/config.yml +13 -0
  31. package/src/template/agent-os/product/mission.md +29 -0
  32. package/src/template/agent-os/product/roadmap.md +9 -0
  33. package/src/template/agent-os/product/tech-stack.md +14 -0
  34. package/src/template/agent-os/specs/README.md +1 -0
  35. package/src/template/agent-os/standards/backend/api.md +10 -0
  36. package/src/template/agent-os/standards/backend/migrations.md +9 -0
  37. package/src/template/agent-os/standards/backend/models.md +10 -0
  38. package/src/template/agent-os/standards/backend/queries.md +9 -0
  39. package/src/template/agent-os/standards/frontend/accessibility.md +10 -0
  40. package/src/template/agent-os/standards/frontend/components.md +11 -0
  41. package/src/template/agent-os/standards/frontend/css.md +7 -0
  42. package/src/template/agent-os/standards/frontend/responsive.md +11 -0
  43. package/src/template/agent-os/standards/global/coding-style.md +10 -0
  44. package/src/template/agent-os/standards/global/commenting.md +5 -0
  45. package/src/template/agent-os/standards/global/conventions.md +11 -0
  46. package/src/template/agent-os/standards/global/error-handling.md +9 -0
  47. package/src/template/agent-os/standards/global/tech-stack.md +31 -0
  48. package/src/template/agent-os/standards/global/validation.md +11 -0
  49. package/src/template/agent-os/standards/testing/test-writing.md +9 -0
  50. package/src/template/agent-os-ui/README.md +73 -0
  51. package/src/template/agent-os-ui/package-lock.json +5028 -0
  52. package/src/template/agent-os-ui/package.json +52 -0
  53. package/src/template/agent-os-ui/postcss.config.js +6 -0
  54. package/src/template/agent-os-ui/src/components/AgentShell.tsx +31 -0
  55. package/src/template/agent-os-ui/src/components/AgentSidebar.tsx +65 -0
  56. package/src/template/agent-os-ui/src/components/GuidanceCard.tsx +75 -0
  57. package/src/template/agent-os-ui/src/components/MarkdownViewer.tsx +25 -0
  58. package/src/template/agent-os-ui/src/components/PromptButton.tsx +28 -0
  59. package/src/template/agent-os-ui/src/components/StatusItem.tsx +45 -0
  60. package/src/template/agent-os-ui/src/components/ThemeToggle.tsx +72 -0
  61. package/src/template/agent-os-ui/src/index.ts +11 -0
  62. package/src/template/agent-os-ui/src/style.css +3 -0
  63. package/src/template/agent-os-ui/tailwind.config.js +50 -0
  64. package/src/template/agent-os-ui/tsconfig.json +33 -0
  65. package/src/template/agent-os-ui/vite.config.ts +32 -0
  66. package/src/template/control-center/backend/backend.log +2 -0
  67. package/src/template/control-center/backend/index.js +228 -0
  68. package/src/template/control-center/backend/package-lock.json +951 -0
  69. package/src/template/control-center/backend/package.json +19 -0
  70. package/src/template/control-center/frontend/README.md +73 -0
  71. package/src/template/control-center/frontend/eslint.config.js +23 -0
  72. package/src/template/control-center/frontend/index.html +21 -0
  73. package/src/template/control-center/frontend/package-lock.json +5752 -0
  74. package/src/template/control-center/frontend/package.json +42 -0
  75. package/src/template/control-center/frontend/public/runtime-config.json +11 -0
  76. package/src/template/control-center/frontend/public/vite.svg +1 -0
  77. package/src/template/control-center/frontend/src/App.css +42 -0
  78. package/src/template/control-center/frontend/src/App.tsx +738 -0
  79. package/src/template/control-center/frontend/src/assets/react.svg +1 -0
  80. package/src/template/control-center/frontend/src/components/ThemeToggle.tsx +64 -0
  81. package/src/template/control-center/frontend/src/components/ui/ToastContext.tsx +81 -0
  82. package/src/template/control-center/frontend/src/index.css +194 -0
  83. package/src/template/control-center/frontend/src/main.tsx +14 -0
  84. package/src/template/control-center/frontend/src/vite-env.d.ts +1 -0
  85. package/src/template/control-center/frontend/tsconfig.app.json +28 -0
  86. package/src/template/control-center/frontend/tsconfig.json +7 -0
  87. package/src/template/control-center/frontend/tsconfig.node.json +26 -0
  88. package/src/template/control-center/frontend/vite.config.ts +22 -0
  89. package/src/template/design/.claude/commands/design-os/data-model.md +122 -0
  90. package/src/template/design/.claude/commands/design-os/design-screen.md +309 -0
  91. package/src/template/design/.claude/commands/design-os/design-shell.md +238 -0
  92. package/src/template/design/.claude/commands/design-os/design-tokens.md +166 -0
  93. package/src/template/design/.claude/commands/design-os/export-product.md +1105 -0
  94. package/src/template/design/.claude/commands/design-os/product-roadmap.md +121 -0
  95. package/src/template/design/.claude/commands/design-os/product-vision.md +99 -0
  96. package/src/template/design/.claude/commands/design-os/sample-data.md +263 -0
  97. package/src/template/design/.claude/commands/design-os/screenshot-design.md +112 -0
  98. package/src/template/design/.claude/commands/design-os/shape-section.md +138 -0
  99. package/src/template/design/.claude/skills/frontend-design/SKILL.md +42 -0
  100. package/src/template/design/.github/CODE_OF_CONDUCT.md +5 -0
  101. package/src/template/design/.github/CONTRIBUTING.md +51 -0
  102. package/src/template/design/.github/ISSUE_TEMPLATE/config.yml +22 -0
  103. package/src/template/design/.github/PULL_REQUEST_TEMPLATE.md +20 -0
  104. package/src/template/design/.github/SECURITY.yml +5 -0
  105. package/src/template/design/.github/SUPPORT.md +19 -0
  106. package/src/template/design/.github/workflows/pr-decline.yml +135 -0
  107. package/src/template/design/.github/workflows/stale.yml +25 -0
  108. package/src/template/design/CHANGELOG.md +13 -0
  109. package/src/template/design/LICENSE +21 -0
  110. package/src/template/design/README.md +54 -0
  111. package/src/template/design/agents.md +218 -0
  112. package/src/template/design/claude.md +1 -0
  113. package/src/template/design/components.json +22 -0
  114. package/src/template/design/docs/codebase-implementation.md +153 -0
  115. package/src/template/design/docs/design-section.md +135 -0
  116. package/src/template/design/docs/export.md +149 -0
  117. package/src/template/design/docs/getting-started.md +59 -0
  118. package/src/template/design/docs/index.md +56 -0
  119. package/src/template/design/docs/product-planning.md +113 -0
  120. package/src/template/design/docs/requirements.md +22 -0
  121. package/src/template/design/docs/usage.md +62 -0
  122. package/src/template/design/eslint.config.js +23 -0
  123. package/src/template/design/index.html +21 -0
  124. package/src/template/design/package-lock.json +5473 -0
  125. package/src/template/design/package.json +47 -0
  126. package/src/template/design/product-plan.zip +0 -0
  127. package/src/template/design/public/vite.svg +1 -0
  128. package/src/template/design/src/assets/react.svg +1 -0
  129. package/src/template/design/src/components/AppLayout.tsx +95 -0
  130. package/src/template/design/src/components/DataCard.tsx +139 -0
  131. package/src/template/design/src/components/DataModelPage.tsx +120 -0
  132. package/src/template/design/src/components/DesignPage.tsx +284 -0
  133. package/src/template/design/src/components/EmptyState.tsx +155 -0
  134. package/src/template/design/src/components/ExportPage.tsx +344 -0
  135. package/src/template/design/src/components/NextPhaseButton.tsx +33 -0
  136. package/src/template/design/src/components/PhaseNav.tsx +152 -0
  137. package/src/template/design/src/components/PhaseWarningBanner.tsx +81 -0
  138. package/src/template/design/src/components/ProductOverviewCard.tsx +102 -0
  139. package/src/template/design/src/components/ProductPage.tsx +97 -0
  140. package/src/template/design/src/components/ScreenDesignPage.tsx +370 -0
  141. package/src/template/design/src/components/ScreenDesignsCard.tsx +49 -0
  142. package/src/template/design/src/components/SectionPage.tsx +256 -0
  143. package/src/template/design/src/components/SectionsCard.tsx +47 -0
  144. package/src/template/design/src/components/SectionsPage.tsx +181 -0
  145. package/src/template/design/src/components/ShellCard.tsx +85 -0
  146. package/src/template/design/src/components/ShellDesignPage.tsx +242 -0
  147. package/src/template/design/src/components/SpecCard.tsx +121 -0
  148. package/src/template/design/src/components/StepIndicator.tsx +75 -0
  149. package/src/template/design/src/components/ThemeToggle.tsx +86 -0
  150. package/src/template/design/src/components/ui/ToastContext.tsx +81 -0
  151. package/src/template/design/src/components/ui/avatar.tsx +53 -0
  152. package/src/template/design/src/components/ui/badge.tsx +46 -0
  153. package/src/template/design/src/components/ui/button.tsx +60 -0
  154. package/src/template/design/src/components/ui/card.tsx +92 -0
  155. package/src/template/design/src/components/ui/collapsible.tsx +48 -0
  156. package/src/template/design/src/components/ui/dialog.tsx +143 -0
  157. package/src/template/design/src/components/ui/dropdown-menu.tsx +255 -0
  158. package/src/template/design/src/components/ui/input.tsx +21 -0
  159. package/src/template/design/src/components/ui/label.tsx +22 -0
  160. package/src/template/design/src/components/ui/progress.tsx +24 -0
  161. package/src/template/design/src/components/ui/scroll-area.tsx +18 -0
  162. package/src/template/design/src/components/ui/select.tsx +67 -0
  163. package/src/template/design/src/components/ui/separator.tsx +28 -0
  164. package/src/template/design/src/components/ui/sheet.tsx +137 -0
  165. package/src/template/design/src/components/ui/skeleton.tsx +13 -0
  166. package/src/template/design/src/components/ui/switch.tsx +46 -0
  167. package/src/template/design/src/components/ui/table.tsx +116 -0
  168. package/src/template/design/src/components/ui/tabs.tsx +64 -0
  169. package/src/template/design/src/index.css +284 -0
  170. package/src/template/design/src/lib/data-model-loader.ts +91 -0
  171. package/src/template/design/src/lib/design-system-loader.ts +101 -0
  172. package/src/template/design/src/lib/product-loader.ts +221 -0
  173. package/src/template/design/src/lib/router.tsx +52 -0
  174. package/src/template/design/src/lib/section-loader.ts +272 -0
  175. package/src/template/design/src/lib/shell-loader.ts +175 -0
  176. package/src/template/design/src/lib/utils.ts +6 -0
  177. package/src/template/design/src/main.tsx +15 -0
  178. package/src/template/design/src/sections/.gitkeep +0 -0
  179. package/src/template/design/src/sections/ai-orchestration-engine-oai/OrchestrationEngine.tsx +348 -0
  180. package/src/template/design/src/sections/core-platform-shell/AppShell.tsx +403 -0
  181. package/src/template/design/src/sections/gemini-live-integration/GeminiIntegration.tsx +332 -0
  182. package/src/template/design/src/sections/interactive-2d-canvas/WhiteboardCanvas.tsx +334 -0
  183. package/src/template/design/src/sections/participation-equity-tracker/EquityTracker.tsx +383 -0
  184. package/src/template/design/src/sections/persistent-memory-system/PersistentMemory.tsx +308 -0
  185. package/src/template/design/src/sections/real-time-communication-layer/VideoSession.tsx +342 -0
  186. package/src/template/design/src/sections/visual-intelligence-agents/VisualAgents.tsx +311 -0
  187. package/src/template/design/src/types/product.ts +97 -0
  188. package/src/template/design/src/types/section.ts +33 -0
  189. package/src/template/design/tsconfig.app.json +34 -0
  190. package/src/template/design/tsconfig.json +13 -0
  191. package/src/template/design/tsconfig.node.json +26 -0
  192. package/src/template/design/vite.config.ts +18 -0
  193. package/src/template/package.json +27 -0
  194. package/src/template/vite.config.ts +16 -0
@@ -0,0 +1,308 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ History,
4
+ Search,
5
+ Filter,
6
+ Play,
7
+ Pause,
8
+ FileText,
9
+ Tag,
10
+ Calendar,
11
+ ChevronRight,
12
+ GitCommit,
13
+ Quote,
14
+ Database,
15
+ ShieldAlert,
16
+ Clock
17
+ } from 'lucide-react';
18
+ import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from '@/components/ui/card';
19
+ import { Button } from '@/components/ui/button';
20
+ import { Badge } from '@/components/ui/badge';
21
+ import { Input } from '@/components/ui/input';
22
+ import { ScrollArea } from '@/components/ui/scroll-area';
23
+ import { Separator } from '@/components/ui/separator';
24
+ import { cn } from '@/lib/utils';
25
+ import { Progress } from '@/components/ui/progress';
26
+
27
+ // Mock Data Types
28
+ interface ContextSnippet {
29
+ id: string;
30
+ type: string;
31
+ start?: string;
32
+ duration?: string;
33
+ speaker?: string;
34
+ transcript: string;
35
+ }
36
+
37
+ interface Decision {
38
+ id: string;
39
+ title: string;
40
+ summary: string;
41
+ outcome: string;
42
+ createdAt: string;
43
+ tags: string[];
44
+ contextSnippets: ContextSnippet[];
45
+ impact: 'high' | 'medium' | 'low' | 'critical';
46
+ }
47
+
48
+ const MOCK_DATA = {
49
+ "decisions": [
50
+ {
51
+ "id": "d_1",
52
+ "title": "Adopt PostgreSQL for primary data store",
53
+ "summary": "We chose Postgres over MongoDB due to strict relational data requirements and better ACID compliance for financial transactions.",
54
+ "outcome": "approved",
55
+ "createdAt": "2023-11-15T10:00:00Z",
56
+ "tags": ["Architecture", "Database", "Backend"],
57
+ "contextSnippets": [
58
+ {
59
+ "id": "ctx_1",
60
+ "type": "audio",
61
+ "start": "14:20",
62
+ "duration": "45s",
63
+ "speaker": "Sarah Chen",
64
+ "transcript": "Look, if we lose a single transaction record, we're liable. Mongo's flexibility is nice, but we need rigid schemas here."
65
+ }
66
+ ],
67
+ "impact": "high"
68
+ },
69
+ {
70
+ "id": "d_2",
71
+ "title": "Delay Q4 Launch by 2 weeks",
72
+ "summary": "To address critical security vulnerabilities found in the penetration test.",
73
+ "outcome": "approved",
74
+ "createdAt": "2023-10-01T15:30:00Z",
75
+ "tags": ["Schedule", "Security", "Risk"],
76
+ "contextSnippets": [
77
+ {
78
+ "id": "ctx_2",
79
+ "type": "transcript",
80
+ "speaker": "David Kim",
81
+ "transcript": "I'd rather be late than hacked. It's a non-negotiable for me."
82
+ }
83
+ ],
84
+ "impact": "critical"
85
+ },
86
+ {
87
+ "id": "d_3",
88
+ "title": "Use 'Inter' font family",
89
+ "summary": "Standardizing on a Google Font for better load times and legibility.",
90
+ "outcome": "consensus",
91
+ "createdAt": "2023-09-20T09:12:00Z",
92
+ "tags": ["Design", "UI", "Performance"],
93
+ "contextSnippets": [],
94
+ "impact": "low"
95
+ }
96
+ ] as Decision[],
97
+ "tags": [
98
+ "Architecture", "Database", "Backend", "Schedule", "Security", "Risk", "Design", "UI", "Performance"
99
+ ]
100
+ };
101
+
102
+ const ImpactBadge = ({ impact }: { impact: Decision['impact'] }) => {
103
+ const styles = {
104
+ critical: "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800",
105
+ high: "bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-900/30 dark:text-orange-400 dark:border-orange-800",
106
+ medium: "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:border-blue-800",
107
+ low: "bg-stone-100 text-stone-700 border-stone-200 dark:bg-stone-800 dark:text-stone-400 dark:border-stone-700",
108
+ };
109
+
110
+ return (
111
+ <span className={cn("text-[10px] font-bold uppercase px-1.5 py-0.5 rounded border", styles[impact])}>
112
+ {impact} Impact
113
+ </span>
114
+ );
115
+ };
116
+
117
+ export default function PersistentMemory() {
118
+ const [selectedDecision, setSelectedDecision] = useState<Decision | null>(MOCK_DATA.decisions[0]);
119
+ const [isPlaying, setIsPlaying] = useState(false);
120
+
121
+ return (
122
+ <div className="flex h-screen w-full bg-stone-50 dark:bg-stone-950 font-sans overflow-hidden">
123
+
124
+ {/* Sidebar: Filters & Graph Nav */}
125
+ <aside className="w-64 bg-white dark:bg-stone-900 border-r border-stone-200 dark:border-stone-800 flex flex-col p-4 z-20">
126
+ <div className="mb-6">
127
+ <h2 className="text-lg font-bold text-stone-800 dark:text-stone-100 flex items-center gap-2">
128
+ <Database size={20} className="text-indigo-600" />
129
+ Memory Bank
130
+ </h2>
131
+ <p className="text-xs text-stone-500 mt-1">Organizational Wisdom Graph</p>
132
+ </div>
133
+
134
+ <div className="relative mb-4">
135
+ <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-stone-400" />
136
+ <Input placeholder="Search decisions..." className="pl-9 bg-stone-50 dark:bg-stone-800 border-stone-200 dark:border-stone-700" />
137
+ </div>
138
+
139
+ <div className="space-y-4 flex-1">
140
+ <div>
141
+ <h3 className="text-xs font-semibold uppercase text-stone-400 mb-2">Filters</h3>
142
+ <div className="flex flex-wrap gap-1.5">
143
+ {MOCK_DATA.tags.slice(0, 6).map(tag => (
144
+ <Badge key={tag} variant="outline" className="cursor-pointer hover:bg-stone-100 dark:hover:bg-stone-800">
145
+ {tag}
146
+ </Badge>
147
+ ))}
148
+ </div>
149
+ </div>
150
+
151
+ <Separator />
152
+
153
+ <div className="bg-indigo-50 dark:bg-indigo-900/10 p-3 rounded-lg border border-indigo-100 dark:border-indigo-900/30">
154
+ <h3 className="text-xs font-semibold text-indigo-700 dark:text-indigo-400 mb-1 flex items-center gap-1">
155
+ <History size={12} /> Insight of the Day
156
+ </h3>
157
+ <p className="text-xs text-indigo-900 dark:text-indigo-300 italic">
158
+ "Most security delays happened in Q4. Consider shifting penetration tests to Q3."
159
+ </p>
160
+ </div>
161
+ </div>
162
+ </aside>
163
+
164
+ {/* Main Content: Split View */}
165
+ <div className="flex-1 flex overflow-hidden">
166
+
167
+ {/* Left: Decision Timeline */}
168
+ <div className="w-1/3 border-r border-stone-200 dark:border-stone-800 bg-white/50 dark:bg-stone-900/50 flex flex-col">
169
+ <div className="p-4 border-b border-stone-200 dark:border-stone-800 bg-white dark:bg-stone-900">
170
+ <h3 className="font-semibold text-sm">Decision Timeline</h3>
171
+ </div>
172
+ <ScrollArea className="flex-1 p-4">
173
+ <div className="relative border-l-2 border-stone-200 dark:border-stone-800 ml-3 space-y-6">
174
+ {MOCK_DATA.decisions.map(decision => (
175
+ <div
176
+ key={decision.id}
177
+ className={cn(
178
+ "relative pl-6 cursor-pointer group transition-all",
179
+ selectedDecision?.id === decision.id ? "opacity-100 scale-100" : "opacity-70 hover:opacity-100"
180
+ )}
181
+ onClick={() => setSelectedDecision(decision)}
182
+ >
183
+ <div className={cn(
184
+ "absolute -left-[9px] top-1 h-4 w-4 rounded-full border-2 transition-colors",
185
+ selectedDecision?.id === decision.id
186
+ ? "bg-white border-indigo-600 dark:bg-stone-900 dark:border-indigo-500"
187
+ : "bg-stone-200 border-white dark:bg-stone-700 dark:border-stone-900 group-hover:bg-indigo-200"
188
+ )} />
189
+
190
+ <div className={cn(
191
+ "p-3 rounded-lg border shadow-sm transition-all",
192
+ selectedDecision?.id === decision.id
193
+ ? "bg-white dark:bg-stone-900 border-indigo-200 dark:border-indigo-800 shadow-md ring-1 ring-indigo-50 dark:ring-indigo-900/20"
194
+ : "bg-white dark:bg-stone-900 border-stone-200 dark:border-stone-800 hover:border-indigo-200 dark:hover:border-indigo-800"
195
+ )}>
196
+ <div className="flex justify-between items-start mb-1">
197
+ <span className="text-[10px] text-stone-500 font-mono">
198
+ {new Date(decision.createdAt).toLocaleDateString()}
199
+ </span>
200
+ <ImpactBadge impact={decision.impact} />
201
+ </div>
202
+ <h4 className="font-medium text-stone-900 dark:text-stone-100 text-sm leading-tight mb-2">
203
+ {decision.title}
204
+ </h4>
205
+ <div className="flex gap-1 flex-wrap">
206
+ {decision.tags.slice(0, 2).map(tag => (
207
+ <span key={tag} className="text-[10px] text-stone-500 bg-stone-50 dark:bg-stone-800 px-1 py-0.5 rounded">
208
+ #{tag}
209
+ </span>
210
+ ))}
211
+ </div>
212
+ </div>
213
+ </div>
214
+ ))}
215
+ </div>
216
+ </ScrollArea>
217
+ </div>
218
+
219
+ {/* Right: Detail View ("The Why") */}
220
+ <div className="flex-1 bg-stone-50 dark:bg-stone-950 flex flex-col h-full overflow-hidden">
221
+ {selectedDecision ? (
222
+ <div className="flex-1 overflow-y-auto">
223
+ {/* Header */}
224
+ <div className="p-8 pb-4">
225
+ <div className="flex items-center gap-3 mb-4">
226
+ <div className="h-10 w-10 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg flex items-center justify-center text-indigo-600 dark:text-indigo-400">
227
+ <GitCommit size={20} />
228
+ </div>
229
+ <div>
230
+ <h1 className="text-2xl font-bold text-stone-900 dark:text-stone-50">{selectedDecision.title}</h1>
231
+ <p className="text-stone-500 text-sm flex items-center gap-2">
232
+ Status: <span className="text-emerald-600 font-medium capitalize">{selectedDecision.outcome}</span>
233
+ </p>
234
+ </div>
235
+ </div>
236
+
237
+ <div className="flex gap-2 mb-6">
238
+ {selectedDecision.tags.map(tag => (
239
+ <Badge key={tag} variant="secondary">
240
+ {tag}
241
+ </Badge>
242
+ ))}
243
+ </div>
244
+
245
+ <Card className="mb-6">
246
+ <CardHeader className="bg-stone-50/50 dark:bg-stone-900/50 border-b border-stone-100 dark:border-stone-800 py-3">
247
+ <CardTitle className="text-sm font-semibold flex items-center gap-2">
248
+ <FileText size={16} /> The Rationale
249
+ </CardTitle>
250
+ </CardHeader>
251
+ <CardContent className="p-4">
252
+ <p className="text-stone-700 dark:text-stone-300 leading-relaxed">
253
+ {selectedDecision.summary}
254
+ </p>
255
+ </CardContent>
256
+ </Card>
257
+
258
+ {/* Context / Media Player */}
259
+ {selectedDecision.contextSnippets.length > 0 && (
260
+ <div className="space-y-4">
261
+ <h3 className="text-sm font-semibold text-stone-500 uppercase tracking-wider">Historical Context</h3>
262
+ {selectedDecision.contextSnippets.map(snippet => (
263
+ <Card key={snippet.id} className="overflow-hidden border-indigo-100 dark:border-indigo-900/50">
264
+ <div className="bg-indigo-50/50 dark:bg-indigo-900/10 p-3 flex items-center gap-3 border-b border-indigo-100 dark:border-indigo-900/20">
265
+ <Button
266
+ size="icon"
267
+ className="h-8 w-8 rounded-full bg-indigo-600 hover:bg-indigo-700 text-white shadow-sm shrink-0"
268
+ onClick={() => setIsPlaying(!isPlaying)}
269
+ >
270
+ {isPlaying ? <Pause size={14} /> : <Play size={14} className="ml-0.5" />}
271
+ </Button>
272
+ <div className="flex-1">
273
+ <div className="flex justify-between items-center text-xs mb-1">
274
+ <span className="font-semibold text-indigo-900 dark:text-indigo-300">
275
+ {snippet.speaker}
276
+ </span>
277
+ <span className="font-mono text-stone-400">
278
+ {snippet.start} ({snippet.duration})
279
+ </span>
280
+ </div>
281
+ <Progress value={isPlaying ? 45 : 0} className="h-1 bg-indigo-200 dark:bg-indigo-900/50" />
282
+ </div>
283
+ </div>
284
+ <div className="p-4 bg-white dark:bg-stone-900">
285
+ <div className="flex gap-3">
286
+ <Quote size={16} className="text-stone-300 shrink-0 mt-1" />
287
+ <p className="text-stone-600 dark:text-stone-400 italic text-sm">
288
+ "{snippet.transcript}"
289
+ </p>
290
+ </div>
291
+ </div>
292
+ </Card>
293
+ ))}
294
+ </div>
295
+ )}
296
+ </div>
297
+ </div>
298
+ ) : (
299
+ <div className="flex-1 flex items-center justify-center text-stone-400">
300
+ Select a decision to view details
301
+ </div>
302
+ )}
303
+ </div>
304
+
305
+ </div>
306
+ </div>
307
+ );
308
+ }
@@ -0,0 +1,342 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ Mic,
4
+ MicOff,
5
+ Video,
6
+ VideoOff,
7
+ Monitor,
8
+ MoreVertical,
9
+ PhoneOff,
10
+ Settings,
11
+ Users,
12
+ MessageSquare,
13
+ Wifi,
14
+ WifiOff,
15
+ Activity,
16
+ Maximize2
17
+ } from 'lucide-react';
18
+ import { Button } from '@/components/ui/button';
19
+ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
20
+ import { Badge } from '@/components/ui/badge';
21
+ import { ScrollArea } from '@/components/ui/scroll-area';
22
+ import {
23
+ DropdownMenu,
24
+ DropdownMenuContent,
25
+ DropdownMenuItem,
26
+ DropdownMenuLabel,
27
+ DropdownMenuSeparator,
28
+ DropdownMenuTrigger,
29
+ } from "@/components/ui/dropdown-menu"
30
+ import {
31
+ Dialog,
32
+ DialogContent,
33
+ DialogDescription,
34
+ DialogHeader,
35
+ DialogTitle,
36
+ DialogTrigger,
37
+ } from "@/components/ui/dialog"
38
+ import {
39
+ Select,
40
+ SelectContent,
41
+ SelectItem,
42
+ SelectTrigger,
43
+ SelectValue,
44
+ } from "@/components/ui/select"
45
+ import { Label } from '@/components/ui/label';
46
+
47
+ // Mock Data Types
48
+ interface Participant {
49
+ id: string;
50
+ name: string;
51
+ isLocal: boolean;
52
+ isMuted: boolean;
53
+ isVideoOff: boolean;
54
+ volume: number;
55
+ avatarUrl: string;
56
+ connectionQuality: 'excellent' | 'good' | 'poor';
57
+ }
58
+
59
+ interface NetworkStats {
60
+ latency: number;
61
+ packetLoss: number;
62
+ bandwidth: string;
63
+ serverRegion: string;
64
+ }
65
+
66
+ const MOCK_DATA = {
67
+ "session": {
68
+ "id": "sess_rtc_live_01",
69
+ "startTime": "2023-11-20T14:00:00Z",
70
+ "duration": "15:30",
71
+ "status": "connected"
72
+ },
73
+ "participants": [
74
+ {
75
+ "id": "p_1",
76
+ "name": "You",
77
+ "isLocal": true,
78
+ "isMuted": false,
79
+ "isVideoOff": false,
80
+ "volume": 0,
81
+ "avatarUrl": "https://api.dicebear.com/7.x/avataaars/svg?seed=Sarah",
82
+ "connectionQuality": "excellent"
83
+ },
84
+ {
85
+ "id": "p_2",
86
+ "name": "David Kim",
87
+ "isLocal": false,
88
+ "isMuted": false,
89
+ "isVideoOff": false,
90
+ "volume": 65,
91
+ "avatarUrl": "https://api.dicebear.com/7.x/avataaars/svg?seed=David",
92
+ "connectionQuality": "good"
93
+ },
94
+ {
95
+ "id": "p_3",
96
+ "name": "Maria Garcia",
97
+ "isLocal": false,
98
+ "isMuted": true,
99
+ "isVideoOff": true,
100
+ "volume": 0,
101
+ "avatarUrl": "https://api.dicebear.com/7.x/avataaars/svg?seed=Maria",
102
+ "connectionQuality": "excellent"
103
+ },
104
+ {
105
+ "id": "p_4",
106
+ "name": "James Wilson",
107
+ "isLocal": false,
108
+ "isMuted": false,
109
+ "isVideoOff": false,
110
+ "volume": 12,
111
+ "avatarUrl": "https://api.dicebear.com/7.x/avataaars/svg?seed=James",
112
+ "connectionQuality": "poor"
113
+ }
114
+ ] as Participant[],
115
+ "networkStats": {
116
+ "latency": 45,
117
+ "packetLoss": 0.1,
118
+ "bandwidth": "2.4 Mbps",
119
+ "serverRegion": "us-east-1"
120
+ } as NetworkStats,
121
+ "devices": {
122
+ "audioInputs": ["MacBook Pro Microphone", "AirPods Pro"],
123
+ "audioOutputs": ["MacBook Pro Speakers", "AirPods Pro"],
124
+ "videoInputs": ["FaceTime HD Camera", "Logitech Brio"]
125
+ }
126
+ };
127
+
128
+ const ConnectionBadge = ({ quality, latency }: { quality: string, latency: number }) => {
129
+ const getColor = () => {
130
+ switch (quality) {
131
+ case 'excellent': return 'text-emerald-500 bg-emerald-50 border-emerald-200 dark:bg-emerald-900/20 dark:border-emerald-800';
132
+ case 'good': return 'text-yellow-500 bg-yellow-50 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800';
133
+ case 'poor': return 'text-red-500 bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-800';
134
+ default: return 'text-stone-500 bg-stone-50 border-stone-200';
135
+ }
136
+ };
137
+
138
+ return (
139
+ <div className={`flex items-center gap-2 px-2 py-1 rounded-full border text-xs font-medium ${getColor()}`}>
140
+ {quality === 'poor' ? <WifiOff size={14} /> : <Wifi size={14} />}
141
+ <span>{latency}ms</span>
142
+ </div>
143
+ );
144
+ };
145
+
146
+ const ParticipantTile = ({ participant }: { participant: Participant }) => {
147
+ return (
148
+ <div className="relative aspect-video bg-stone-900 rounded-xl overflow-hidden shadow-sm border border-stone-800 group">
149
+ {/* Video Placeholder or Avatar */}
150
+ <div className="absolute inset-0 flex items-center justify-center">
151
+ {participant.isVideoOff ? (
152
+ <Avatar className="w-24 h-24 border-2 border-stone-700">
153
+ <AvatarImage src={participant.avatarUrl} />
154
+ <AvatarFallback>{participant.name[0]}</AvatarFallback>
155
+ </Avatar>
156
+ ) : (
157
+ <div className="w-full h-full bg-stone-800 flex items-center justify-center text-stone-600">
158
+ {/* Simulated Video Stream Gradient */}
159
+ <div className="w-full h-full bg-gradient-to-br from-stone-800 to-stone-900 opacity-50" />
160
+ </div>
161
+ )}
162
+ </div>
163
+
164
+ {/* Overlay Info */}
165
+ <div className="absolute bottom-0 left-0 right-0 p-3 bg-gradient-to-t from-black/80 to-transparent flex items-end justify-between">
166
+ <div className="flex items-center gap-2">
167
+ <span className="text-white text-sm font-medium drop-shadow-md">
168
+ {participant.name} {participant.isLocal && "(You)"}
169
+ </span>
170
+ {participant.isMuted && <MicOff size={14} className="text-red-400" />}
171
+ </div>
172
+ <ConnectionBadge quality={participant.connectionQuality} latency={30 + Math.random() * 50} />
173
+ </div>
174
+
175
+ {/* Audio Visualizer (Active Speaker) */}
176
+ {!participant.isMuted && participant.volume > 0 && (
177
+ <div className="absolute top-3 right-3 flex items-end gap-0.5 h-4">
178
+ {[...Array(4)].map((_, i) => (
179
+ <div
180
+ key={i}
181
+ className="w-1 bg-emerald-500 rounded-full animate-pulse"
182
+ style={{
183
+ height: `${Math.random() * 100}%`,
184
+ animationDuration: `${0.2 + Math.random() * 0.3}s`
185
+ }}
186
+ />
187
+ ))}
188
+ </div>
189
+ )}
190
+
191
+ {/* Speaking border */}
192
+ {!participant.isMuted && participant.volume > 20 && (
193
+ <div className="absolute inset-0 border-2 border-emerald-500 rounded-xl pointer-events-none" />
194
+ )}
195
+ </div>
196
+ );
197
+ };
198
+
199
+ export default function VideoSession() {
200
+ const [micOn, setMicOn] = useState(true);
201
+ const [videoOn, setVideoOn] = useState(true);
202
+
203
+ // Update local participant state based on controls
204
+ const participants = MOCK_DATA.participants.map(p =>
205
+ p.isLocal ? { ...p, isMuted: !micOn, isVideoOff: !videoOn } : p
206
+ );
207
+
208
+ return (
209
+ <div className="flex flex-col h-screen bg-stone-950 text-stone-100 overflow-hidden font-sans">
210
+
211
+ {/* Top Bar */}
212
+ <header className="h-16 flex items-center justify-between px-6 border-b border-stone-900 bg-stone-950/90 backdrop-blur">
213
+ <div className="flex items-center gap-4">
214
+ <div className="flex flex-col">
215
+ <h1 className="font-semibold text-sm">Product Strategy Sync</h1>
216
+ <div className="flex items-center gap-2 text-xs text-stone-400">
217
+ <span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
218
+ {MOCK_DATA.session.duration}
219
+ </div>
220
+ </div>
221
+ </div>
222
+
223
+ <div className="flex items-center gap-3">
224
+ <div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-stone-900 border border-stone-800">
225
+ <Activity size={14} className="text-emerald-500" />
226
+ <span className="text-xs text-stone-400">Region: {MOCK_DATA.networkStats.serverRegion}</span>
227
+ <span className="w-px h-3 bg-stone-800 mx-1" />
228
+ <span className="text-xs text-stone-400">{MOCK_DATA.networkStats.bandwidth}</span>
229
+ </div>
230
+
231
+ <Dialog>
232
+ <DialogTrigger asChild>
233
+ <Button variant="ghost" size="icon" className="text-stone-400 hover:text-white hover:bg-stone-800">
234
+ <Settings size={20} />
235
+ </Button>
236
+ </DialogTrigger>
237
+ <DialogContent className="sm:max-w-[425px] bg-stone-900 border-stone-800 text-stone-100">
238
+ <DialogHeader>
239
+ <DialogTitle>Audio & Video Settings</DialogTitle>
240
+ <DialogDescription className="text-stone-400">
241
+ Configure your devices for the session.
242
+ </DialogDescription>
243
+ </DialogHeader>
244
+ <div className="grid gap-4 py-4">
245
+ <div className="grid gap-2">
246
+ <Label htmlFor="audio-input">Microphone</Label>
247
+ <Select defaultValue={MOCK_DATA.devices.audioInputs[0]}>
248
+ <SelectTrigger id="audio-input" className="bg-stone-800 border-stone-700">
249
+ <SelectValue />
250
+ </SelectTrigger>
251
+ <SelectContent className="bg-stone-800 border-stone-700 text-stone-100">
252
+ {MOCK_DATA.devices.audioInputs.map(d => <SelectItem key={d} value={d}>{d}</SelectItem>)}
253
+ </SelectContent>
254
+ </Select>
255
+ </div>
256
+ <div className="grid gap-2">
257
+ <Label htmlFor="audio-output">Speakers</Label>
258
+ <Select defaultValue={MOCK_DATA.devices.audioOutputs[0]}>
259
+ <SelectTrigger id="audio-output" className="bg-stone-800 border-stone-700">
260
+ <SelectValue />
261
+ </SelectTrigger>
262
+ <SelectContent className="bg-stone-800 border-stone-700 text-stone-100">
263
+ {MOCK_DATA.devices.audioOutputs.map(d => <SelectItem key={d} value={d}>{d}</SelectItem>)}
264
+ </SelectContent>
265
+ </Select>
266
+ </div>
267
+ <div className="grid gap-2">
268
+ <Label htmlFor="video-input">Camera</Label>
269
+ <Select defaultValue={MOCK_DATA.devices.videoInputs[0]}>
270
+ <SelectTrigger id="video-input" className="bg-stone-800 border-stone-700">
271
+ <SelectValue />
272
+ </SelectTrigger>
273
+ <SelectContent className="bg-stone-800 border-stone-700 text-stone-100">
274
+ {MOCK_DATA.devices.videoInputs.map(d => <SelectItem key={d} value={d}>{d}</SelectItem>)}
275
+ </SelectContent>
276
+ </Select>
277
+ </div>
278
+ </div>
279
+ </DialogContent>
280
+ </Dialog>
281
+ </div>
282
+ </header>
283
+
284
+ {/* Main Grid */}
285
+ <main className="flex-1 p-4 overflow-hidden">
286
+ <div className="h-full grid grid-cols-2 gap-4 auto-rows-fr max-w-6xl mx-auto items-center justify-center">
287
+ {participants.map(p => (
288
+ <ParticipantTile key={p.id} participant={p} />
289
+ ))}
290
+ </div>
291
+ </main>
292
+
293
+ {/* Control Bar */}
294
+ <footer className="h-20 shrink-0 flex items-center justify-center gap-4 px-6 pb-6 mt-auto">
295
+ <div className="flex items-center gap-2 p-2 rounded-2xl bg-stone-900 border border-stone-800 shadow-2xl">
296
+ <Button
297
+ size="icon"
298
+ variant={micOn ? "secondary" : "destructive"}
299
+ className={`rounded-xl h-12 w-12 ${micOn ? 'bg-stone-800 text-white hover:bg-stone-700' : ''}`}
300
+ onClick={() => setMicOn(!micOn)}
301
+ >
302
+ {micOn ? <Mic /> : <MicOff />}
303
+ </Button>
304
+
305
+ <Button
306
+ size="icon"
307
+ variant={videoOn ? "secondary" : "destructive"}
308
+ className={`rounded-xl h-12 w-12 ${videoOn ? 'bg-stone-800 text-white hover:bg-stone-700' : ''}`}
309
+ onClick={() => setVideoOn(!videoOn)}
310
+ >
311
+ {videoOn ? <Video /> : <VideoOff />}
312
+ </Button>
313
+
314
+ <div className="w-px h-8 bg-stone-800 mx-2" />
315
+
316
+ <Button size="icon" variant="ghost" className="rounded-xl h-12 w-12 text-stone-400 hover:text-white hover:bg-stone-800">
317
+ <Monitor />
318
+ </Button>
319
+ <Button size="icon" variant="ghost" className="rounded-xl h-12 w-12 text-stone-400 hover:text-white hover:bg-stone-800">
320
+ <Users />
321
+ </Button>
322
+ <Button size="icon" variant="ghost" className="rounded-xl h-12 w-12 text-stone-400 hover:text-white hover:bg-stone-800">
323
+ <MessageSquare />
324
+ </Button>
325
+ <Button size="icon" variant="ghost" className="rounded-xl h-12 w-12 text-stone-400 hover:text-white hover:bg-stone-800">
326
+ <MoreVertical />
327
+ </Button>
328
+
329
+ <div className="w-px h-8 bg-stone-800 mx-2" />
330
+
331
+ <Button
332
+ variant="destructive"
333
+ className="rounded-xl h-12 px-6 bg-red-600 hover:bg-red-700"
334
+ >
335
+ <PhoneOff className="mr-2 h-5 w-5" />
336
+ End
337
+ </Button>
338
+ </div>
339
+ </footer>
340
+ </div>
341
+ );
342
+ }