@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,738 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { Terminal, Layout, Monitor, Layers, FileText, Code, Play, CheckSquare, List, RefreshCw, ArrowRight, X, Loader2, Plus, Trash2, WalletCards, LayoutDashboard, Copy, Package } from 'lucide-react';
|
|
4
|
+
import { useToast } from './components/ui/ToastContext';
|
|
5
|
+
import { ThemeToggle, GuidanceCard } from '@antigravity/agent-os-ui';
|
|
6
|
+
import '@antigravity/agent-os-ui/style.css';
|
|
7
|
+
import ReactMarkdown from 'react-markdown';
|
|
8
|
+
import remarkGfm from 'remark-gfm';
|
|
9
|
+
import remarkBreaks from 'remark-breaks';
|
|
10
|
+
|
|
11
|
+
// Types
|
|
12
|
+
interface Status {
|
|
13
|
+
exists: boolean;
|
|
14
|
+
completed: number;
|
|
15
|
+
total: number;
|
|
16
|
+
nextItem?: string | null;
|
|
17
|
+
items?: { name: string; completed: boolean }[];
|
|
18
|
+
isBoilerplate?: boolean;
|
|
19
|
+
}
|
|
20
|
+
interface ProductStatus {
|
|
21
|
+
mission: Status;
|
|
22
|
+
roadmap: Status;
|
|
23
|
+
techStack: Status;
|
|
24
|
+
}
|
|
25
|
+
interface Spec {
|
|
26
|
+
name: string;
|
|
27
|
+
spec: Status;
|
|
28
|
+
tasks: Status;
|
|
29
|
+
}
|
|
30
|
+
interface ProjectState {
|
|
31
|
+
product: ProductStatus;
|
|
32
|
+
design: {
|
|
33
|
+
exists: boolean;
|
|
34
|
+
initialized: boolean;
|
|
35
|
+
tokens: boolean;
|
|
36
|
+
shell: boolean;
|
|
37
|
+
exported: boolean;
|
|
38
|
+
};
|
|
39
|
+
implementation: {
|
|
40
|
+
scaffolded: boolean;
|
|
41
|
+
};
|
|
42
|
+
specs: Spec[];
|
|
43
|
+
services?: {
|
|
44
|
+
api: boolean;
|
|
45
|
+
design: boolean;
|
|
46
|
+
app: boolean;
|
|
47
|
+
};
|
|
48
|
+
projectRoot: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const NextStepCard = ({ state, onOpenDesign, onCreateSpec }: { state: ProjectState, onOpenDesign: () => void, onCreateSpec: () => void }) => {
|
|
54
|
+
let step = { phase: "", title: "", description: "", prompt: "", link: "", actionLabel: "", action: () => { } };
|
|
55
|
+
|
|
56
|
+
const isProductComplete =
|
|
57
|
+
state?.product?.mission?.exists && !state?.product?.mission?.isBoilerplate &&
|
|
58
|
+
state?.product?.techStack?.exists && !state?.product?.techStack?.isBoilerplate &&
|
|
59
|
+
// Roadmap must exist AND have at least one valid item done, OR be non-boilerplate (if we relax strictness)
|
|
60
|
+
// But user specifically asked for step 1 to persist if roadmap is 0/4.
|
|
61
|
+
state?.product?.roadmap?.exists && (state?.product?.roadmap?.completed ?? 0) > 0;
|
|
62
|
+
|
|
63
|
+
if (!isProductComplete) {
|
|
64
|
+
step = {
|
|
65
|
+
phase: "Phase 1: Product Strategy",
|
|
66
|
+
title: "Plan Your Product",
|
|
67
|
+
description: "Define your Mission, Roadmap, and Tech Stack to build a solid foundation.",
|
|
68
|
+
prompt: "Antigravity, let's start Phase 1: Product Planning. Please read 'agent-os/commands/plan-product/plan-product.md' and guide me.",
|
|
69
|
+
link: "",
|
|
70
|
+
actionLabel: "",
|
|
71
|
+
action: () => { }
|
|
72
|
+
}
|
|
73
|
+
} else if (!state?.design?.initialized) {
|
|
74
|
+
step = {
|
|
75
|
+
phase: "Phase 2: Design System",
|
|
76
|
+
title: "Sync Product to Design OS",
|
|
77
|
+
description: "Transfer your Product Mission and Roadmap to Design OS to automate the setup.",
|
|
78
|
+
prompt: "Antigravity, please sync my product plan to Design OS. Read 'agent-os/commands/initialize-design/initialize-design.md'.",
|
|
79
|
+
link: "",
|
|
80
|
+
actionLabel: "",
|
|
81
|
+
action: () => { }
|
|
82
|
+
}
|
|
83
|
+
} else if (!state?.design?.exists) {
|
|
84
|
+
step = {
|
|
85
|
+
phase: "Phase 2: Design System",
|
|
86
|
+
title: "Define Your Visuals",
|
|
87
|
+
description: "Defining the visuals now prevents generic UI later. Export your system when ready.",
|
|
88
|
+
prompt: "",
|
|
89
|
+
link: "",
|
|
90
|
+
actionLabel: "Open Design OS",
|
|
91
|
+
action: onOpenDesign
|
|
92
|
+
};
|
|
93
|
+
} else if (!state?.implementation?.scaffolded) {
|
|
94
|
+
step = {
|
|
95
|
+
phase: "Phase 3: Implementation",
|
|
96
|
+
title: "Scaffold Application",
|
|
97
|
+
description: "Your design is exported. Now, scaffold the production app with the design system.",
|
|
98
|
+
prompt: "Antigravity, scaffold the implementation. Read 'agent-os/commands/scaffold-implementation/scaffold-implementation.md'.",
|
|
99
|
+
link: "",
|
|
100
|
+
actionLabel: "",
|
|
101
|
+
action: () => { }
|
|
102
|
+
};
|
|
103
|
+
} else if (state?.specs?.length === 0) {
|
|
104
|
+
step = {
|
|
105
|
+
phase: "Phase 4: Feature Specs",
|
|
106
|
+
title: "Shape Your First Spec",
|
|
107
|
+
description: "Your app is ready! Create a spec for the first feature in your roadmap.",
|
|
108
|
+
prompt: "Antigravity, let's shape the spec for a new feature. Please read 'agent-os/commands/shape-spec/shape-spec.md'.",
|
|
109
|
+
link: "",
|
|
110
|
+
actionLabel: "",
|
|
111
|
+
action: () => { }
|
|
112
|
+
};
|
|
113
|
+
} else {
|
|
114
|
+
// Find first incomplete spec
|
|
115
|
+
const incompleteSpec = state?.specs?.find(s => s.tasks.completed < s.tasks.total || !s.tasks.exists);
|
|
116
|
+
if (incompleteSpec) {
|
|
117
|
+
step = {
|
|
118
|
+
phase: "Phase 4: Feature Specs",
|
|
119
|
+
title: `Implement '${incompleteSpec.name}'`,
|
|
120
|
+
description: `Active spec detected. Write the code!`,
|
|
121
|
+
prompt: `Antigravity, implement the tasks for '${incompleteSpec.name}'. Read commands/implement-tasks/implement-tasks.md.`,
|
|
122
|
+
link: "",
|
|
123
|
+
actionLabel: "",
|
|
124
|
+
action: () => { }
|
|
125
|
+
};
|
|
126
|
+
} else if (state?.product?.roadmap?.nextItem && !state?.product?.roadmap?.isBoilerplate) {
|
|
127
|
+
// Clean up item name (remove bolding and numbering if present)
|
|
128
|
+
// e.g. "**2. Real-time Communication Layer**" -> "Real-time Communication Layer"
|
|
129
|
+
const rawName = state?.product?.roadmap?.nextItem;
|
|
130
|
+
const cleanName = rawName.replace(/\*\*/g, '').replace(/^\d+\.\s*/, '').split('\n')[0].trim();
|
|
131
|
+
|
|
132
|
+
step = {
|
|
133
|
+
phase: "Phase 4: Feature Specs",
|
|
134
|
+
title: `Shape '${cleanName}'`,
|
|
135
|
+
description: `Ready to start the next feature? Shape the spec now.`,
|
|
136
|
+
prompt: `Antigravity, let's shape the spec for '${cleanName}'. Please read 'agent-os/commands/shape-spec/shape-spec.md'.`,
|
|
137
|
+
link: "",
|
|
138
|
+
actionLabel: "",
|
|
139
|
+
action: () => { }
|
|
140
|
+
};
|
|
141
|
+
} else {
|
|
142
|
+
step = {
|
|
143
|
+
phase: "Phase 4: Feature Specs",
|
|
144
|
+
title: "Verify or Plan Next",
|
|
145
|
+
description: "Verify implementation or start a new feature.",
|
|
146
|
+
prompt: "Antigravity, let's verify the implementation. Read 'agent-os/commands/implement-tasks/3-verify-implementation.md'.",
|
|
147
|
+
link: "",
|
|
148
|
+
actionLabel: "",
|
|
149
|
+
action: () => { }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<GuidanceCard
|
|
156
|
+
phase={step.phase}
|
|
157
|
+
title={step.title}
|
|
158
|
+
description={step.description}
|
|
159
|
+
prompt={step.prompt}
|
|
160
|
+
actionLabel={step.actionLabel}
|
|
161
|
+
onAction={step.action}
|
|
162
|
+
className="mb-8"
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
function StatusItem({ label, status, icon, small, onClick }: any) {
|
|
168
|
+
if (!status) return null;
|
|
169
|
+
const isComplete = status.exists && (status.total > 0 ? status.completed === status.total : true);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div
|
|
173
|
+
onClick={onClick}
|
|
174
|
+
className={`flex items-center justify-between ${small ? 'text-xs' : 'text-sm'} ${onClick ? 'cursor-pointer hover:bg-secondary/50 p-1.5 -mx-1.5 rounded-md transition-colors group' : ''}`}
|
|
175
|
+
>
|
|
176
|
+
<div className="flex items-center gap-2 text-muted-foreground group-hover:text-foreground transition-colors">
|
|
177
|
+
{icon}
|
|
178
|
+
<span>{label}</span>
|
|
179
|
+
</div>
|
|
180
|
+
<div>
|
|
181
|
+
{status.exists && !status.isBoilerplate ? (
|
|
182
|
+
<span className={`px-2 py-0.5 rounded-full text-xs font-medium border ${isComplete
|
|
183
|
+
? 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-600 border-emerald-200 dark:border-emerald-800'
|
|
184
|
+
: 'bg-secondary text-muted-foreground border-border'
|
|
185
|
+
}`}>
|
|
186
|
+
{isComplete ? 'Done' : 'Pending'}
|
|
187
|
+
</span>
|
|
188
|
+
) : (
|
|
189
|
+
<span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">Pending</span>
|
|
190
|
+
)}
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function PromptButton({ label, prompt, onClick, small, primary }: any) {
|
|
197
|
+
return (
|
|
198
|
+
<button
|
|
199
|
+
onClick={() => onClick(prompt)}
|
|
200
|
+
className={`flex items-center justify-center gap-2 rounded-lg font-medium transition cursor-pointer
|
|
201
|
+
${small ? 'px-3 py-1.5 text-xs flex-1' : 'px-4 py-2 text-sm w-full'}
|
|
202
|
+
${primary
|
|
203
|
+
? 'bg-primary hover:bg-primary/90 text-primary-foreground shadow-sm'
|
|
204
|
+
: 'bg-background hover:bg-secondary border border-border text-foreground hover:text-foreground'}
|
|
205
|
+
`}
|
|
206
|
+
>
|
|
207
|
+
<Copy size={small ? 12 : 14} />
|
|
208
|
+
{label}
|
|
209
|
+
</button>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function App() {
|
|
214
|
+
const [state, setState] = useState<ProjectState | null>(null);
|
|
215
|
+
const [loading, setLoading] = useState(true);
|
|
216
|
+
const [showDesignOS, setShowDesignOS] = useState(false);
|
|
217
|
+
const { toast } = useToast();
|
|
218
|
+
const [runtimeConfig, setRuntimeConfig] = useState<any>(null);
|
|
219
|
+
|
|
220
|
+
// Fetch Runtime Config on Mount
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
fetch('/runtime-config.json')
|
|
223
|
+
.then(res => res.json())
|
|
224
|
+
.then(config => {
|
|
225
|
+
setRuntimeConfig(config);
|
|
226
|
+
})
|
|
227
|
+
.catch(err => {
|
|
228
|
+
console.error("Failed to load runtime config", err);
|
|
229
|
+
// Fallback for dev without orchestrator
|
|
230
|
+
setRuntimeConfig({
|
|
231
|
+
api: 'http://localhost:3003',
|
|
232
|
+
app: 'http://localhost:3002',
|
|
233
|
+
design: 'http://localhost:3000',
|
|
234
|
+
ports: { api: 3003, app: 3002, design: 3000 }
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}, []);
|
|
238
|
+
|
|
239
|
+
const fetchStatus = async () => {
|
|
240
|
+
if (!runtimeConfig) return;
|
|
241
|
+
try {
|
|
242
|
+
const res = await axios.get(`${runtimeConfig.api}/api/status`);
|
|
243
|
+
setState(res.data);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('Failed to fetch status', error);
|
|
246
|
+
// Optional: toast error
|
|
247
|
+
} finally {
|
|
248
|
+
setLoading(false);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
if (runtimeConfig) {
|
|
254
|
+
fetchStatus();
|
|
255
|
+
const interval = setInterval(fetchStatus, 2000);
|
|
256
|
+
return () => clearInterval(interval);
|
|
257
|
+
}
|
|
258
|
+
}, [runtimeConfig]);
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
const copyToClipboard = (text: string) => {
|
|
263
|
+
navigator.clipboard.writeText(text);
|
|
264
|
+
toast({ title: "Prompt Copied!", type: "success" });
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const [viewingFile, setViewingFile] = useState<{ path: string, title: string } | null>(null);
|
|
268
|
+
const [fileContent, setFileContent] = useState<string | null>(null);
|
|
269
|
+
const [creatingSpec, setCreatingSpec] = useState(false);
|
|
270
|
+
const [deletingSpec, setDeletingSpec] = useState<string | null>(null);
|
|
271
|
+
const [newSpecName, setNewSpecName] = useState("");
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
const openFile = async (path: string, title: string) => {
|
|
275
|
+
setViewingFile({ path, title });
|
|
276
|
+
setFileContent("Loading...");
|
|
277
|
+
try {
|
|
278
|
+
const res = await axios.get(`${runtimeConfig.api}/api/files?path=${encodeURIComponent(path)}`);
|
|
279
|
+
setFileContent(res.data.content);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
setFileContent("Error loading file.");
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
if (loading) return <div className="min-h-screen bg-background text-foreground flex items-center justify-center">Loading Control Center...</div>;
|
|
286
|
+
|
|
287
|
+
if (!state) {
|
|
288
|
+
return (
|
|
289
|
+
<div className="min-h-screen bg-background text-foreground flex flex-col items-center justify-center gap-4 p-8">
|
|
290
|
+
<h2 className="text-xl font-semibold text-red-500">Connection Failed</h2>
|
|
291
|
+
<p className="text-muted-foreground text-center max-w-md">
|
|
292
|
+
Could not connect to the Control Center API at <code>{runtimeConfig?.api || '...'}</code>.
|
|
293
|
+
<br />Please ensure the backend is running.
|
|
294
|
+
</p>
|
|
295
|
+
<button
|
|
296
|
+
onClick={() => { setLoading(true); fetchStatus(); }}
|
|
297
|
+
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors"
|
|
298
|
+
>
|
|
299
|
+
Retry Connection
|
|
300
|
+
</button>
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return (
|
|
306
|
+
<div className="min-h-screen bg-background text-foreground font-sans flex flex-col h-screen overflow-hidden">
|
|
307
|
+
{/* File Viewer Overlay */}
|
|
308
|
+
{[
|
|
309
|
+
viewingFile && (
|
|
310
|
+
<div className="fixed inset-0 z-[200] bg-black/50 backdrop-blur-sm flex items-center justify-center p-6 animate-in fade-in">
|
|
311
|
+
<div className="bg-card border border-border w-full max-w-4xl max-h-[90vh] rounded-xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200">
|
|
312
|
+
<div className="flex items-center justify-between px-6 py-4 border-b border-border bg-muted/30">
|
|
313
|
+
<div className="flex items-center gap-3">
|
|
314
|
+
<div className="p-2 bg-primary/10 text-primary rounded-md">
|
|
315
|
+
<FileText size={18} />
|
|
316
|
+
</div>
|
|
317
|
+
<div>
|
|
318
|
+
<h3 className="font-semibold text-lg">{viewingFile.title}</h3>
|
|
319
|
+
<code className="text-xs text-muted-foreground font-mono">{viewingFile.path}</code>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
<button onClick={() => setViewingFile(null)} className="p-2 hover:bg-secondary rounded-full transition-colors">
|
|
323
|
+
<X size={20} />
|
|
324
|
+
</button>
|
|
325
|
+
</div>
|
|
326
|
+
<div className="flex-1 overflow-y-auto p-6 bg-background">
|
|
327
|
+
{fileContent === "Loading..." || fileContent === "Error loading file." ? (
|
|
328
|
+
<div className="font-mono text-sm">{fileContent}</div>
|
|
329
|
+
) : (
|
|
330
|
+
<article className="prose dark:prose-invert max-w-none prose-headings:font-serif prose-headings:font-semibold prose-a:text-primary prose-code:text-primary prose-pre:bg-secondary/50 prose-pre:border prose-pre:border-border prose-p:leading-relaxed prose-p:mb-4">
|
|
331
|
+
<ReactMarkdown remarkPlugins={[remarkGfm, remarkBreaks]}>
|
|
332
|
+
{fileContent || ''}
|
|
333
|
+
</ReactMarkdown>
|
|
334
|
+
</article>
|
|
335
|
+
)}
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
),
|
|
340
|
+
creatingSpec && (
|
|
341
|
+
<div className="fixed inset-0 z-[200] bg-black/50 backdrop-blur-sm flex items-center justify-center p-6 animate-in fade-in">
|
|
342
|
+
<div className="bg-card border border-border w-full max-w-md rounded-xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200">
|
|
343
|
+
<div className="px-6 py-4 border-b border-border bg-muted/30">
|
|
344
|
+
<h3 className="font-semibold text-lg">New Feature Spec</h3>
|
|
345
|
+
<p className="text-sm text-muted-foreground">Shape a new feature for your project.</p>
|
|
346
|
+
</div>
|
|
347
|
+
<div className="p-6">
|
|
348
|
+
<div className="space-y-4">
|
|
349
|
+
<div>
|
|
350
|
+
<label className="text-sm font-medium mb-1.5 block">Feature Name</label>
|
|
351
|
+
<input
|
|
352
|
+
autoFocus
|
|
353
|
+
type="text"
|
|
354
|
+
className="w-full px-3 py-2 rounded-md border border-input bg-background text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
355
|
+
placeholder="e.g. user-profile"
|
|
356
|
+
value={newSpecName}
|
|
357
|
+
onChange={(e) => setNewSpecName(e.target.value)}
|
|
358
|
+
onKeyDown={async (e) => {
|
|
359
|
+
if (e.key === 'Enter' && newSpecName.trim()) {
|
|
360
|
+
const name = newSpecName.trim();
|
|
361
|
+
if (runtimeConfig?.api) {
|
|
362
|
+
await axios.post(`${runtimeConfig.api}/api/scaffold/spec`, { name });
|
|
363
|
+
|
|
364
|
+
// Auto-copy prompt
|
|
365
|
+
const prompt = `Antigravity, let's shape the spec for '${name}'. Read commands/shape-spec/shape-spec.md.`;
|
|
366
|
+
await copyToClipboard(prompt);
|
|
367
|
+
|
|
368
|
+
setNewSpecName("");
|
|
369
|
+
setCreatingSpec(false);
|
|
370
|
+
await fetchStatus();
|
|
371
|
+
|
|
372
|
+
// Open the spec file
|
|
373
|
+
openFile(`specs/${name}/spec.md`, `${name} Spec`);
|
|
374
|
+
toast({ title: "Spec created & Prompt copied!", type: 'success' });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}}
|
|
378
|
+
/>
|
|
379
|
+
<p className="text-xs text-muted-foreground mt-1.5">
|
|
380
|
+
This will create a new directory in <code>specs/</code> and copy the prompt to your clipboard.
|
|
381
|
+
</p>
|
|
382
|
+
</div>
|
|
383
|
+
<div className="flex justify-end gap-2 pt-2">
|
|
384
|
+
<button
|
|
385
|
+
onClick={() => { setCreatingSpec(false); setNewSpecName(""); }}
|
|
386
|
+
className="px-4 py-2 text-sm font-medium rounded-md hover:bg-secondary transition-colors"
|
|
387
|
+
>
|
|
388
|
+
Cancel
|
|
389
|
+
</button>
|
|
390
|
+
<button
|
|
391
|
+
disabled={!newSpecName.trim()}
|
|
392
|
+
onClick={async () => {
|
|
393
|
+
if (newSpecName.trim()) {
|
|
394
|
+
const name = newSpecName.trim();
|
|
395
|
+
if (runtimeConfig?.api) {
|
|
396
|
+
await axios.post(`${runtimeConfig.api}/api/scaffold/spec`, { name });
|
|
397
|
+
|
|
398
|
+
// Auto-copy prompt
|
|
399
|
+
const prompt = `Antigravity, let's shape the spec for '${name}'. Read commands/shape-spec/shape-spec.md.`;
|
|
400
|
+
await copyToClipboard(prompt);
|
|
401
|
+
|
|
402
|
+
setNewSpecName("");
|
|
403
|
+
setCreatingSpec(false);
|
|
404
|
+
await fetchStatus();
|
|
405
|
+
|
|
406
|
+
// Open the spec file
|
|
407
|
+
openFile(`specs/${name}/spec.md`, `${name} Spec`);
|
|
408
|
+
toast({ title: "Spec created & Prompt copied!", type: 'success' });
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}}
|
|
412
|
+
className="px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
|
413
|
+
>
|
|
414
|
+
Create Spec
|
|
415
|
+
</button>
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
),
|
|
422
|
+
deletingSpec && (
|
|
423
|
+
<div className="fixed inset-0 z-[200] bg-black/50 backdrop-blur-sm flex items-center justify-center p-6 animate-in fade-in">
|
|
424
|
+
<div className="bg-card border border-border w-full max-w-sm rounded-xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-200">
|
|
425
|
+
<div className="p-6">
|
|
426
|
+
<div className="flex items-center gap-3 mb-4 text-red-500">
|
|
427
|
+
<div className="p-2 bg-red-100 dark:bg-red-900/20 rounded-full">
|
|
428
|
+
<Trash2 size={24} />
|
|
429
|
+
</div>
|
|
430
|
+
<h3 className="font-semibold text-lg text-foreground">Delete Spec?</h3>
|
|
431
|
+
</div>
|
|
432
|
+
<p className="text-muted-foreground mb-6">
|
|
433
|
+
Are you sure you want to delete <strong>{deletingSpec}</strong>? This action cannot be undone and will permanently delete the spec files.
|
|
434
|
+
</p>
|
|
435
|
+
<div className="flex justify-end gap-2">
|
|
436
|
+
<button
|
|
437
|
+
onClick={() => setDeletingSpec(null)}
|
|
438
|
+
className="px-4 py-2 text-sm font-medium rounded-md hover:bg-secondary transition-colors"
|
|
439
|
+
>
|
|
440
|
+
Cancel
|
|
441
|
+
</button>
|
|
442
|
+
<button
|
|
443
|
+
onClick={async () => {
|
|
444
|
+
await axios.delete(`${runtimeConfig.api}/api/specs/${deletingSpec}`);
|
|
445
|
+
setDeletingSpec(null);
|
|
446
|
+
fetchStatus();
|
|
447
|
+
}}
|
|
448
|
+
className="px-4 py-2 text-sm font-medium rounded-md bg-red-500 hover:bg-red-600 text-white transition-colors"
|
|
449
|
+
>
|
|
450
|
+
Delete Spec
|
|
451
|
+
</button>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
)
|
|
457
|
+
]}
|
|
458
|
+
|
|
459
|
+
{/* Design OS Overlay */}
|
|
460
|
+
{showDesignOS && (
|
|
461
|
+
<div className="fixed inset-0 z-[100] bg-background flex flex-col animate-fade-in w-screen h-screen">
|
|
462
|
+
<div className="h-14 border-b border-border flex items-center justify-between px-6 bg-card shrink-0 shadow-sm z-50">
|
|
463
|
+
<div className="flex items-center gap-3">
|
|
464
|
+
<div className="p-1.5 bg-sidebar-primary/10 text-sidebar-primary rounded-md">
|
|
465
|
+
<Layers size={20} />
|
|
466
|
+
</div>
|
|
467
|
+
<h2 className="font-semibold text-lg text-foreground">Design OS</h2>
|
|
468
|
+
<span className="text-muted-foreground text-sm border-l border-border pl-3">Design System & Handoff</span>
|
|
469
|
+
</div>
|
|
470
|
+
{/* Window Controls */}
|
|
471
|
+
<div className="flex items-center gap-3">
|
|
472
|
+
<button
|
|
473
|
+
onClick={() => setShowDesignOS(false)}
|
|
474
|
+
className="p-2 text-muted-foreground hover:text-foreground hover:bg-secondary rounded-md transition-colors"
|
|
475
|
+
title="Close Design OS"
|
|
476
|
+
>
|
|
477
|
+
<X size={20} />
|
|
478
|
+
</button>
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
<div className="flex-1 bg-background relative">
|
|
482
|
+
<iframe
|
|
483
|
+
src={`http://localhost:3000?theme=${localStorage.getItem('theme') || 'system'}`}
|
|
484
|
+
className="absolute inset-0 w-full h-full border-none"
|
|
485
|
+
title="Design OS"
|
|
486
|
+
allow="clipboard-read; clipboard-write"
|
|
487
|
+
/>
|
|
488
|
+
</div>
|
|
489
|
+
</div >
|
|
490
|
+
)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
<header className="px-8 py-6 flex justify-between items-end border-b border-border bg-card/50 backdrop-blur-sm sticky top-0 z-10 shrink-0">
|
|
494
|
+
<div className="flex flex-col gap-4">
|
|
495
|
+
<h1 className="text-2xl font-semibold text-foreground tracking-tight flex items-center gap-3">
|
|
496
|
+
<div className="w-8 h-8 rounded-lg bg-[#E7E5E4] dark:bg-[#1A2E05] flex items-center justify-center text-[#1C1917] dark:text-[#84CC16]">
|
|
497
|
+
<Monitor size={18} />
|
|
498
|
+
</div>
|
|
499
|
+
Agent OS Control Center
|
|
500
|
+
</h1>
|
|
501
|
+
<p className="text-muted-foreground font-mono text-xs opacity-70">Project: {state?.projectRoot}</p>
|
|
502
|
+
</div>
|
|
503
|
+
<div className="flex gap-3 items-center">
|
|
504
|
+
<ThemeToggle onThemeChange={(theme: string) => {
|
|
505
|
+
const iframe = document.querySelector('iframe[title="Design OS"]') as HTMLIFrameElement;
|
|
506
|
+
if (iframe?.contentWindow) {
|
|
507
|
+
iframe.contentWindow.postMessage({ type: 'THEME_CHANGE', theme }, '*');
|
|
508
|
+
}
|
|
509
|
+
}} />
|
|
510
|
+
<button className={`px-4 py-2 border rounded-lg flex items-center gap-2 transition text-sm font-medium ${showDesignOS ? 'bg-primary text-primary-foreground border-primary' : 'bg-background hover:bg-secondary border-border'}`}
|
|
511
|
+
onClick={() => setShowDesignOS(!showDesignOS)}>
|
|
512
|
+
<Layers size={16} /> {showDesignOS ? 'Close Design OS' : 'Open Design OS'}
|
|
513
|
+
</button>
|
|
514
|
+
</div>
|
|
515
|
+
</header>
|
|
516
|
+
|
|
517
|
+
<div className="p-8 overflow-y-auto flex-1 bg-background/50">
|
|
518
|
+
<div className="max-w-7xl mx-auto">
|
|
519
|
+
{state && <NextStepCard state={state} onOpenDesign={() => setShowDesignOS(true)} onCreateSpec={() => setCreatingSpec(true)} />}
|
|
520
|
+
|
|
521
|
+
<main className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
522
|
+
{/* Phase 1: Product Strategy */}
|
|
523
|
+
<section className="bg-card border border-border rounded-xl p-5 shadow-sm h-full flex flex-col transition-all hover:shadow-md hover:border-border/80">
|
|
524
|
+
<div className="flex items-center gap-3 mb-5 pb-4 border-b border-border/50">
|
|
525
|
+
<div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
|
|
526
|
+
<LayoutDashboard size={20} />
|
|
527
|
+
</div>
|
|
528
|
+
<h2 className="text-lg font-semibold">1. Product Strategy</h2>
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
<div className="space-y-3 flex-1">
|
|
532
|
+
<StatusItem label="Mission" status={state?.product?.mission} icon={<FileText size={16} />} onClick={() => openFile('product/mission.md', 'Product Mission')} />
|
|
533
|
+
<StatusItem label="Roadmap" status={state?.product?.roadmap} icon={<CheckSquare size={16} />} onClick={() => openFile('product/roadmap.md', 'Product Roadmap')} />
|
|
534
|
+
<StatusItem label="Tech Stack" status={state?.product?.techStack} icon={<Code size={16} />} onClick={() => openFile('product/tech-stack.md', 'Tech Stack')} />
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
<div className="mt-6">
|
|
538
|
+
<PromptButton
|
|
539
|
+
label="Plan Product"
|
|
540
|
+
prompt="Antigravity, let's start Phase 1: Product Planning. Please read 'agent-os/commands/plan-product/plan-product.md' and guide me."
|
|
541
|
+
onClick={copyToClipboard}
|
|
542
|
+
/>
|
|
543
|
+
</div>
|
|
544
|
+
</section>
|
|
545
|
+
|
|
546
|
+
{/* Phase 2: Design */}
|
|
547
|
+
<section className="bg-card border border-border rounded-xl p-5 shadow-sm h-full flex flex-col transition-all hover:shadow-md hover:border-border/80">
|
|
548
|
+
<div className="flex items-center gap-3 mb-5 pb-4 border-b border-border/50">
|
|
549
|
+
<div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
|
|
550
|
+
<Layers size={20} />
|
|
551
|
+
</div>
|
|
552
|
+
<h2 className="text-lg font-semibold">2. Design System</h2>
|
|
553
|
+
</div>
|
|
554
|
+
|
|
555
|
+
<div className="space-y-4 flex-1">
|
|
556
|
+
<div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
|
|
557
|
+
<span className="text-foreground font-medium text-sm flex items-center gap-2"><RefreshCw size={16} className="text-muted-foreground" /> Data Sync</span>
|
|
558
|
+
{state?.design?.initialized ? (
|
|
559
|
+
<span className="text-emerald-600 bg-emerald-50 dark:bg-emerald-900/20 px-2 py-0.5 rounded text-xs font-medium border border-emerald-200 dark:border-emerald-800">Synced</span>
|
|
560
|
+
) : (
|
|
561
|
+
<span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">Pending</span>
|
|
562
|
+
)}
|
|
563
|
+
</div>
|
|
564
|
+
|
|
565
|
+
<div className="grid grid-cols-2 gap-2">
|
|
566
|
+
<div className={`p-2 rounded-lg border text-center ${state?.design?.tokens ? 'bg-emerald-50/50 border-emerald-200 text-emerald-700 dark:bg-emerald-900/20 dark:border-emerald-800 dark:text-emerald-300' : 'bg-secondary/20 border-border/50 text-muted-foreground'}`}>
|
|
567
|
+
<span className="text-xs font-medium block mb-1">Tokens</span>
|
|
568
|
+
{state?.design?.tokens ? <CheckSquare size={14} className="mx-auto" /> : <span className="block w-2 h-2 rounded-full bg-stone-300 mx-auto mt-1" />}
|
|
569
|
+
</div>
|
|
570
|
+
<div className={`p-2 rounded-lg border text-center ${state?.design?.shell ? 'bg-emerald-50/50 border-emerald-200 text-emerald-700 dark:bg-emerald-900/20 dark:border-emerald-800 dark:text-emerald-300' : 'bg-secondary/20 border-border/50 text-muted-foreground'}`}>
|
|
571
|
+
<span className="text-xs font-medium block mb-1">App Shell</span>
|
|
572
|
+
{state?.design?.shell ? <CheckSquare size={14} className="mx-auto" /> : <span className="block w-2 h-2 rounded-full bg-stone-300 mx-auto mt-1" />}
|
|
573
|
+
</div>
|
|
574
|
+
</div>
|
|
575
|
+
|
|
576
|
+
<div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
|
|
577
|
+
<span className="text-foreground font-medium text-sm flex items-center gap-2"><ArrowRight size={16} className="text-muted-foreground" /> Export</span>
|
|
578
|
+
{state?.design?.exists ? (
|
|
579
|
+
<span className="text-emerald-600 bg-emerald-50 dark:bg-emerald-900/20 px-2 py-0.5 rounded text-xs font-medium border border-emerald-200 dark:border-emerald-800">Ready</span>
|
|
580
|
+
) : (
|
|
581
|
+
<span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">Pending</span>
|
|
582
|
+
)}
|
|
583
|
+
</div>
|
|
584
|
+
</div>
|
|
585
|
+
|
|
586
|
+
<div className="mt-6 flex gap-2">
|
|
587
|
+
{!state?.design?.initialized && (
|
|
588
|
+
<PromptButton
|
|
589
|
+
label="Sync Data"
|
|
590
|
+
prompt="Antigravity, please sync my product plan to Design OS. Read 'agent-os/commands/initialize-design/initialize-design.md'."
|
|
591
|
+
onClick={copyToClipboard}
|
|
592
|
+
primary
|
|
593
|
+
/>
|
|
594
|
+
)}
|
|
595
|
+
</div>
|
|
596
|
+
</section>
|
|
597
|
+
|
|
598
|
+
{/* Phase 3: Implementation */}
|
|
599
|
+
<section className="bg-card border border-border rounded-xl p-5 shadow-sm h-full flex flex-col transition-all hover:shadow-md hover:border-border/80">
|
|
600
|
+
<div className="flex items-center gap-3 mb-5 pb-4 border-b border-border/50">
|
|
601
|
+
<div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
|
|
602
|
+
<Package size={20} />
|
|
603
|
+
</div>
|
|
604
|
+
<h2 className="text-lg font-semibold">3. Implementation</h2>
|
|
605
|
+
</div>
|
|
606
|
+
|
|
607
|
+
<div className="space-y-4 flex-1">
|
|
608
|
+
<div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
|
|
609
|
+
<span className="text-foreground font-medium text-sm flex items-center gap-2"><Layout size={16} className="text-muted-foreground" /> Scaffold</span>
|
|
610
|
+
{state?.implementation?.scaffolded ? (
|
|
611
|
+
<span className="text-emerald-600 bg-emerald-50 dark:bg-emerald-900/20 px-2 py-0.5 rounded text-xs font-medium border border-emerald-200 dark:border-emerald-800">Done</span>
|
|
612
|
+
) : (
|
|
613
|
+
<span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">Pending</span>
|
|
614
|
+
)}
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
|
|
618
|
+
<div className="mt-6">
|
|
619
|
+
<PromptButton
|
|
620
|
+
label="Scaffold App"
|
|
621
|
+
prompt="Antigravity, scaffold the implementation. Read 'agent-os/commands/scaffold-implementation/scaffold-implementation.md'."
|
|
622
|
+
onClick={copyToClipboard}
|
|
623
|
+
/>
|
|
624
|
+
</div>
|
|
625
|
+
</section>
|
|
626
|
+
|
|
627
|
+
{/* Phase 4: Specs & Implementation */}
|
|
628
|
+
<section className="bg-card border border-border rounded-xl p-5 shadow-sm col-span-1 md:col-span-2 lg:col-span-1 h-full flex flex-col transition-all hover:shadow-md hover:border-border/80">
|
|
629
|
+
<div className="flex items-center justify-between mb-5 pb-4 border-b border-border/50">
|
|
630
|
+
<div className="flex items-center gap-3">
|
|
631
|
+
<div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
|
|
632
|
+
<Code size={20} />
|
|
633
|
+
</div>
|
|
634
|
+
<h2 className="text-lg font-semibold">4. Feature Specs</h2>
|
|
635
|
+
</div>
|
|
636
|
+
<button className="text-xs bg-secondary hover:bg-secondary/80 border border-border px-3 py-2 rounded-md flex items-center gap-1.5 font-medium transition cursor-pointer"
|
|
637
|
+
onClick={() => setCreatingSpec(true)}>
|
|
638
|
+
<Plus size={14} /> New
|
|
639
|
+
</button>
|
|
640
|
+
</div>
|
|
641
|
+
|
|
642
|
+
<div className="space-y-3 flex-1 overflow-y-auto max-h-[300px] pr-1">
|
|
643
|
+
{state?.specs?.map(spec => (
|
|
644
|
+
<div key={spec.name} className="bg-secondary/20 p-4 rounded-lg border border-border/50 hover:border-border transition-colors group relative">
|
|
645
|
+
<button
|
|
646
|
+
onClick={(e) => {
|
|
647
|
+
e.stopPropagation();
|
|
648
|
+
setDeletingSpec(spec.name);
|
|
649
|
+
}}
|
|
650
|
+
className="absolute top-4 right-4 text-muted-foreground hover:text-red-500 opacity-0 group-hover:opacity-100 transition-all p-1"
|
|
651
|
+
title="Delete Spec"
|
|
652
|
+
>
|
|
653
|
+
<Trash2 size={16} />
|
|
654
|
+
</button>
|
|
655
|
+
<h3 className="font-medium text-base mb-3 flex items-center gap-2">
|
|
656
|
+
<WalletCards size={16} className="text-muted-foreground" />
|
|
657
|
+
{spec.name}
|
|
658
|
+
</h3>
|
|
659
|
+
<div className="space-y-2 mb-4">
|
|
660
|
+
<StatusItem label="Spec" status={spec.spec} icon={<FileText size={14} />} small onClick={() => openFile(`specs/${spec.name}/spec.md`, `${spec.name} Spec`)} />
|
|
661
|
+
<StatusItem label="Tasks" status={spec.tasks} icon={<CheckSquare size={14} />} small onClick={() => openFile(`specs/${spec.name}/tasks.md`, `${spec.name} Tasks`)} />
|
|
662
|
+
</div>
|
|
663
|
+
<div className="flex gap-2">
|
|
664
|
+
<PromptButton
|
|
665
|
+
label="Shape"
|
|
666
|
+
prompt={`Antigravity, let's shape the spec for '${spec.name}'. Read commands/shape-spec/shape-spec.md.`}
|
|
667
|
+
onClick={copyToClipboard}
|
|
668
|
+
small
|
|
669
|
+
/>
|
|
670
|
+
<PromptButton
|
|
671
|
+
label="Implement"
|
|
672
|
+
prompt={`Antigravity, implement the tasks for '${spec.name}'. Read commands/implement-tasks/implement-tasks.md.`}
|
|
673
|
+
onClick={copyToClipboard}
|
|
674
|
+
small
|
|
675
|
+
primary
|
|
676
|
+
/>
|
|
677
|
+
</div>
|
|
678
|
+
</div>
|
|
679
|
+
))}
|
|
680
|
+
|
|
681
|
+
{/* Pending Roadmap Items */}
|
|
682
|
+
{state?.product?.roadmap?.items?.filter(item =>
|
|
683
|
+
!item.completed &&
|
|
684
|
+
!state?.product?.roadmap?.isBoilerplate &&
|
|
685
|
+
!state?.specs?.some(s => s.name.toLowerCase() === item.name.toLowerCase().trim().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''))
|
|
686
|
+
).map(item => (
|
|
687
|
+
<div key={item.name} className="border border-dashed border-border/60 p-4 rounded-lg bg-secondary/5 hover:bg-secondary/10 transition-colors">
|
|
688
|
+
<h3 className="font-medium text-base mb-2 flex items-center gap-2 text-muted-foreground">
|
|
689
|
+
<div className="w-2 h-2 rounded-full bg-stone-300" />
|
|
690
|
+
{item.name}
|
|
691
|
+
</h3>
|
|
692
|
+
<p className="text-xs text-muted-foreground mb-4 pl-4">Pending in Roadmap</p>
|
|
693
|
+
<div className="pl-4">
|
|
694
|
+
<button
|
|
695
|
+
onClick={() => {
|
|
696
|
+
setNewSpecName(item.name.toLowerCase().replace(/\s+/g, '-'));
|
|
697
|
+
setCreatingSpec(true);
|
|
698
|
+
}}
|
|
699
|
+
className="text-xs bg-background hover:bg-secondary border border-border px-3 py-1.5 rounded-md flex items-center gap-1.5 font-medium transition cursor-pointer"
|
|
700
|
+
>
|
|
701
|
+
<Plus size={12} /> Shape Spec
|
|
702
|
+
</button>
|
|
703
|
+
</div>
|
|
704
|
+
</div>
|
|
705
|
+
))}
|
|
706
|
+
|
|
707
|
+
{state?.specs?.length === 0 && (!state?.product?.roadmap?.items || state?.product?.roadmap?.items?.length === 0) && (
|
|
708
|
+
<div className="text-muted-foreground italic p-8 text-center text-sm border border-dashed border-border rounded-lg bg-secondary/10">
|
|
709
|
+
No specs found yet.<br />Create one to start coding.
|
|
710
|
+
</div>
|
|
711
|
+
)}
|
|
712
|
+
</div>
|
|
713
|
+
</section>
|
|
714
|
+
</main>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
{/* Server Status Footer */}
|
|
718
|
+
<footer className="h-8 border-t border-border/40 bg-card px-4 flex items-center gap-6 text-[10px] font-medium text-muted-foreground fixed bottom-0 w-full z-50">
|
|
719
|
+
<div className="flex items-center gap-2">
|
|
720
|
+
<div className={`w-1.5 h-1.5 rounded-full ${state?.services?.api ? 'bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.4)]' : 'bg-red-500 animate-pulse'}`} />
|
|
721
|
+
<span>Control Center API ({runtimeConfig?.ports?.api || 3003})</span>
|
|
722
|
+
</div>
|
|
723
|
+
<div className="h-3 w-[1px] bg-border" />
|
|
724
|
+
<div className="flex items-center gap-2">
|
|
725
|
+
<div className={`w-1.5 h-1.5 rounded-full ${state?.services?.design ? 'bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.4)]' : 'bg-red-500'}`} />
|
|
726
|
+
<span>Design OS ({runtimeConfig?.ports?.design || 3000})</span>
|
|
727
|
+
</div>
|
|
728
|
+
<div className="h-3 w-[1px] bg-border" />
|
|
729
|
+
<div className="flex items-center gap-2">
|
|
730
|
+
<div className={`w-1.5 h-1.5 rounded-full ${state?.services?.app ? 'bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.4)]' : 'bg-red-500'}`} />
|
|
731
|
+
<span>App ({runtimeConfig?.ports?.app || 3002})</span>
|
|
732
|
+
</div>
|
|
733
|
+
</footer>
|
|
734
|
+
</div >
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
export default App;
|