@theproductguy/create-mission-control 1.0.3 → 1.0.5

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 (69) hide show
  1. package/bin/cli.js +63 -7
  2. package/package.json +2 -2
  3. package/src/template/.env.example +28 -0
  4. package/src/template/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  5. package/src/template/.github/ISSUE_TEMPLATE/feature_request.md +30 -0
  6. package/src/template/.github/PULL_REQUEST_TEMPLATE.md +33 -0
  7. package/src/template/.github/workflows/ci.yml +83 -0
  8. package/src/template/.husky/commit-msg +1 -0
  9. package/src/template/.husky/pre-commit +1 -0
  10. package/src/template/.prettierrc +11 -0
  11. package/src/template/README.md +78 -0
  12. package/src/template/agent-os/commands/create-constitution/create-constitution.md +89 -0
  13. package/src/template/agent-os/commands/export-product/export-product.md +24 -0
  14. package/src/template/agent-os/commands/initialize-design/initialize-design.md +10 -1
  15. package/src/template/agent-os/commands/research-tech/research-tech.md +93 -0
  16. package/src/template/agent-os/commands/shape-spec/shape-spec.md +2 -1
  17. package/src/template/agent-os/docs/context7.md +20 -0
  18. package/src/template/commitlint.config.js +25 -0
  19. package/src/template/control-center/backend/index.js +67 -4
  20. package/src/template/control-center/frontend/src/App.tsx +193 -64
  21. package/src/template/design-system/{.claude → .gemini}/commands/design-os/design-shell.md +95 -69
  22. package/src/template/design-system/.gemini/commands/design-os/design-tokens.md +211 -0
  23. package/src/template/design-system/.gemini/commands/impeccable/WORKFLOW.md +163 -0
  24. package/src/template/design-system/.gemini/commands/impeccable/adapt.md +189 -0
  25. package/src/template/design-system/.gemini/commands/impeccable/animate.md +184 -0
  26. package/src/template/design-system/.gemini/commands/impeccable/audit.md +123 -0
  27. package/src/template/design-system/.gemini/commands/impeccable/bolder.md +126 -0
  28. package/src/template/design-system/.gemini/commands/impeccable/clarify.md +173 -0
  29. package/src/template/design-system/.gemini/commands/impeccable/colorize.md +152 -0
  30. package/src/template/design-system/.gemini/commands/impeccable/critique.md +112 -0
  31. package/src/template/design-system/.gemini/commands/impeccable/delight.md +311 -0
  32. package/src/template/design-system/.gemini/commands/impeccable/extract.md +88 -0
  33. package/src/template/design-system/.gemini/commands/impeccable/harden.md +351 -0
  34. package/src/template/design-system/.gemini/commands/impeccable/normalize.md +61 -0
  35. package/src/template/design-system/.gemini/commands/impeccable/onboard.md +236 -0
  36. package/src/template/design-system/.gemini/commands/impeccable/optimize.md +262 -0
  37. package/src/template/design-system/.gemini/commands/impeccable/polish.md +196 -0
  38. package/src/template/design-system/.gemini/commands/impeccable/quieter.md +112 -0
  39. package/src/template/design-system/.gemini/commands/impeccable/simplify.md +131 -0
  40. package/src/template/design-system/.gemini/commands/impeccable/teach-impeccable.md +67 -0
  41. package/src/template/design-system/.gemini/hooks/ai-slop-guard.md +80 -0
  42. package/src/template/design-system/.gemini/hooks/on-design-complete.md +63 -0
  43. package/src/template/design-system/.gemini/skills/frontend-design/SKILL.md +126 -0
  44. package/src/template/design-system/.gemini/skills/frontend-design/reference/color-and-contrast.md +132 -0
  45. package/src/template/design-system/.gemini/skills/frontend-design/reference/interaction-design.md +123 -0
  46. package/src/template/design-system/.gemini/skills/frontend-design/reference/motion-design.md +99 -0
  47. package/src/template/design-system/.gemini/skills/frontend-design/reference/responsive-design.md +114 -0
  48. package/src/template/design-system/.gemini/skills/frontend-design/reference/spatial-design.md +100 -0
  49. package/src/template/design-system/.gemini/skills/frontend-design/reference/typography.md +131 -0
  50. package/src/template/design-system/.gemini/skills/frontend-design/reference/ux-writing.md +107 -0
  51. package/src/template/design-system/src/components/DesignPage.tsx +104 -0
  52. package/src/template/eslint.config.js +37 -0
  53. package/src/template/lint-staged.config.js +6 -0
  54. package/src/template/package-lock.json +10308 -0
  55. package/src/template/package.json +25 -2
  56. package/src/template/src/__tests__/example.test.ts +17 -0
  57. package/src/template/src/__tests__/setup.ts +14 -0
  58. package/src/template/vitest.config.ts +25 -0
  59. package/src/template/design-system/.claude/commands/design-os/design-tokens.md +0 -166
  60. package/src/template/design-system/.claude/skills/frontend-design/SKILL.md +0 -42
  61. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/data-model.md +0 -0
  62. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/design-screen.md +0 -0
  63. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/export-product.md +0 -0
  64. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/product-roadmap.md +0 -0
  65. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/product-vision.md +0 -0
  66. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/sample-data.md +0 -0
  67. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/screenshot-design.md +0 -0
  68. /package/src/template/design-system/{.claude → .gemini}/commands/design-os/shape-section.md +0 -0
  69. /package/src/template/design-system/{claude.md → gemini.md} +0 -0
@@ -0,0 +1,25 @@
1
+ export default {
2
+ extends: ['@commitlint/config-conventional'],
3
+ rules: {
4
+ 'type-enum': [
5
+ 2,
6
+ 'always',
7
+ [
8
+ 'feat', // New feature
9
+ 'fix', // Bug fix
10
+ 'docs', // Documentation
11
+ 'style', // Formatting, missing semicolons, etc.
12
+ 'refactor', // Code restructuring without changing behavior
13
+ 'perf', // Performance improvements
14
+ 'test', // Adding or updating tests
15
+ 'build', // Build system or dependencies
16
+ 'ci', // CI configuration
17
+ 'chore', // Maintenance tasks
18
+ 'revert', // Reverting changes
19
+ ],
20
+ ],
21
+ 'subject-case': [2, 'always', 'lower-case'],
22
+ 'subject-empty': [2, 'never'],
23
+ 'type-empty': [2, 'never'],
24
+ },
25
+ }
@@ -125,15 +125,64 @@ app.get('/api/status', async (req, res) => {
125
125
 
126
126
  // Check for Design OS export and steps
127
127
  const designDir = path.join(PROJECT_ROOT, 'design-system');
128
- // Note: In dev, these files are in design/public/product. In prod, injected elsewhere.
129
- // But for this local dev setup, we check where the initialize-design command puts them?
130
- // Actually, initialize-design puts them in `design/public/product`.
128
+
129
+ // QA Check
130
+ const qaDir = path.join(designDir, 'QA');
131
+ const auditReport = path.join(qaDir, 'audit-report.md');
132
+ const polishReport = path.join(qaDir, 'polish-report.md');
131
133
 
132
134
  const hasDesignExport = fs.existsSync(path.join(PROJECT_ROOT, 'product-plan'));
133
135
  const hasDesignInit = fs.existsSync(path.join(designDir, 'product/product-overview.md'));
134
136
  const hasTokens = fs.existsSync(path.join(designDir, 'product/design-system/colors.json'));
135
137
  const hasShell = fs.existsSync(path.join(designDir, 'product/shell/spec.md'));
136
138
 
139
+ // Implementation tracking
140
+ const appDir = path.join(PROJECT_ROOT, 'app');
141
+ const hasScaffold = fs.existsSync(path.join(APP_DIR, 'src/lib/utils.ts'));
142
+
143
+ // Check for test files
144
+ const testFiles = glob.sync('**/*.{test,spec}.{ts,tsx,js,jsx}', { cwd: appDir, ignore: ['node_modules/**'] });
145
+ const hasTests = testFiles.length > 0;
146
+
147
+ // Check for coverage report
148
+ const coverageDir = path.join(PROJECT_ROOT, 'coverage');
149
+ const coverageSummary = path.join(coverageDir, 'coverage-summary.json');
150
+ let coveragePercent = null;
151
+ if (fs.existsSync(coverageSummary)) {
152
+ try {
153
+ const coverage = JSON.parse(fs.readFileSync(coverageSummary, 'utf-8'));
154
+ if (coverage.total && coverage.total.lines) {
155
+ coveragePercent = Math.round(coverage.total.lines.pct);
156
+ }
157
+ } catch (e) {
158
+ // Ignore parsing errors
159
+ }
160
+ }
161
+
162
+ // Check git status
163
+ let gitInfo = { initialized: false, branch: null, uncommitted: 0, lastCommit: null };
164
+ const gitDir = path.join(PROJECT_ROOT, '.git');
165
+ if (fs.existsSync(gitDir)) {
166
+ gitInfo.initialized = true;
167
+ try {
168
+ const { execSync } = require('child_process');
169
+ gitInfo.branch = execSync('git rev-parse --abbrev-ref HEAD', { cwd: PROJECT_ROOT, encoding: 'utf-8' }).trim();
170
+ const status = execSync('git status --porcelain', { cwd: PROJECT_ROOT, encoding: 'utf-8' });
171
+ gitInfo.uncommitted = status.split('\n').filter(l => l.trim()).length;
172
+ try {
173
+ gitInfo.lastCommit = execSync('git log -1 --pretty=format:"%s"', { cwd: PROJECT_ROOT, encoding: 'utf-8' }).trim();
174
+ } catch (e) {
175
+ // No commits yet
176
+ }
177
+ } catch (e) {
178
+ // Git commands failed
179
+ }
180
+ }
181
+
182
+ // Check for linked specs
183
+ const specsWithTasks = specs.filter(s => s.tasks.exists && s.tasks.total > 0);
184
+ const specsCompleted = specs.filter(s => s.tasks.exists && s.tasks.completed === s.tasks.total && s.tasks.total > 0);
185
+
137
186
  res.json({
138
187
  product: productFiles,
139
188
  services,
@@ -146,10 +195,24 @@ app.get('/api/status', async (req, res) => {
146
195
  exportPrompts: {
147
196
  oneShot: fs.existsSync(path.join(PROJECT_ROOT, 'product-plan/prompts/one-shot-prompt.md')),
148
197
  section: fs.existsSync(path.join(PROJECT_ROOT, 'product-plan/prompts/section-prompt.md'))
198
+ },
199
+ qa: {
200
+ audit: fs.existsSync(auditReport),
201
+ polish: fs.existsSync(polishReport)
149
202
  }
150
203
  },
151
204
  implementation: {
152
- scaffolded: fs.existsSync(path.join(APP_DIR, 'src/lib/utils.ts'))
205
+ scaffolded: hasScaffold,
206
+ tests: {
207
+ count: testFiles.length,
208
+ hasTests
209
+ },
210
+ coverage: coveragePercent,
211
+ specs: {
212
+ total: specsWithTasks.length,
213
+ completed: specsCompleted.length
214
+ },
215
+ git: gitInfo
153
216
  },
154
217
  specs,
155
218
  projectRoot: PROJECT_ROOT
@@ -39,9 +39,28 @@ interface ProjectState {
39
39
  oneShot: boolean;
40
40
  section: boolean;
41
41
  };
42
+ qa?: {
43
+ audit: boolean;
44
+ polish: boolean;
45
+ };
42
46
  };
43
47
  implementation: {
44
48
  scaffolded: boolean;
49
+ tests?: {
50
+ count: number;
51
+ hasTests: boolean;
52
+ };
53
+ coverage?: number | null;
54
+ specs?: {
55
+ total: number;
56
+ completed: number;
57
+ };
58
+ git?: {
59
+ initialized: boolean;
60
+ branch: string | null;
61
+ uncommitted: number;
62
+ lastCommit: string | null;
63
+ };
45
64
  };
46
65
  specs: Spec[];
47
66
  services?: {
@@ -646,6 +665,17 @@ function App() {
646
665
  </div>
647
666
  </div>
648
667
 
668
+ <div className="grid grid-cols-2 gap-2">
669
+ <div className={`p-2 rounded-lg border text-center ${state?.design?.qa?.audit ? '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'}`}>
670
+ <span className="text-xs font-medium block mb-1">Audit</span>
671
+ {state?.design?.qa?.audit ? <CheckSquare size={14} className="mx-auto" /> : <span className="block w-2 h-2 rounded-full bg-stone-300 mx-auto mt-1" />}
672
+ </div>
673
+ <div className={`p-2 rounded-lg border text-center ${state?.design?.qa?.polish ? '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'}`}>
674
+ <span className="text-xs font-medium block mb-1">Polish</span>
675
+ {state?.design?.qa?.polish ? <CheckSquare size={14} className="mx-auto" /> : <span className="block w-2 h-2 rounded-full bg-stone-300 mx-auto mt-1" />}
676
+ </div>
677
+ </div>
678
+
649
679
  <div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
650
680
  <span className="text-foreground font-medium text-sm flex items-center gap-2"><ArrowRight size={16} className="text-muted-foreground" /> Export</span>
651
681
  {state?.design?.exported ? (
@@ -658,7 +688,7 @@ function App() {
658
688
  </div>
659
689
  </div>
660
690
 
661
- <div className="mt-6 flex gap-2">
691
+ <div className="mt-6 flex flex-col gap-2">
662
692
  {!state?.design?.initialized && (
663
693
  <PromptButton
664
694
  label="Sync Data"
@@ -667,80 +697,33 @@ function App() {
667
697
  primary
668
698
  />
669
699
  )}
670
- </div>
671
- </section>
672
-
673
- {/* Phase 3: Implementation */}
674
- <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">
675
- <div className="flex items-center gap-3 mb-5 pb-4 border-b border-border/50">
676
- <div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
677
- <Package size={20} />
678
- </div>
679
- <h2 className="text-lg font-semibold">3. Implementation</h2>
680
- </div>
681
-
682
- <div className="space-y-4 flex-1">
683
- <div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
684
- <span className="text-foreground font-medium text-sm flex items-center gap-2"><Layout size={16} className="text-muted-foreground" /> Scaffold</span>
685
- {state?.implementation?.scaffolded ? (
686
- <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>
687
- ) : (
688
- <span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">Pending</span>
689
- )}
690
- </div>
691
- </div>
692
-
693
- <div className="mt-6">
694
- {!state?.implementation?.scaffolded ? (
695
- <PromptButton
696
- label="Scaffold App"
697
- prompt="Antigravity, scaffold the implementation. Read 'agent-os/commands/scaffold-implementation/scaffold-implementation.md'."
698
- onClick={copyToClipboard}
699
- />
700
- ) : (
701
- <div className="p-3 bg-secondary/30 rounded-lg border border-border/50 text-sm text-muted-foreground text-center italic mb-4">
702
- App scaffolded. Ready for implementation.
703
- </div>
704
- )}
705
-
706
- {state?.implementation?.scaffolded && state?.design?.exportPrompts?.oneShot && (
707
- <div className="pt-3 border-t border-border/50">
708
- <p className="text-xs text-muted-foreground mb-2 font-medium">Implementation Options:</p>
709
- <div className="space-y-2">
710
- <PromptButton
711
- label="Option A: One-Shot (All)"
712
- prompt={`Antigravity, implement the app. Read 'product-plan/prompts/one-shot-prompt.md'.`}
713
- onClick={copyToClipboard}
714
- small
715
- primary
716
- />
717
- {state?.design?.exportPrompts?.section && (
718
- <div className="relative">
719
- <PromptButton
720
- label="Option B: Incremental (Section)"
721
- prompt={`Antigravity, implement a section. Read 'product-plan/prompts/section-prompt.md'.`}
722
- onClick={copyToClipboard}
723
- small
724
- />
725
- <p className="text-[10px] text-muted-foreground mt-1.5 text-center leading-tight">
726
- Build feature-by-feature using the <strong>Feature Specs</strong> list &rarr;
727
- </p>
728
- </div>
729
- )}
730
- </div>
700
+ {state?.design?.initialized && !state?.design?.exported && (
701
+ <div className="flex gap-2">
702
+ <PromptButton
703
+ label="Run Audit"
704
+ prompt="Antigravity, run an audit on the design system. Read 'design-system/.gemini/commands/impeccable/audit.md'."
705
+ onClick={copyToClipboard}
706
+ small
707
+ />
708
+ <PromptButton
709
+ label="Run Polish"
710
+ prompt="Antigravity, run a polish pass. Read 'design-system/.gemini/commands/impeccable/polish.md'."
711
+ onClick={copyToClipboard}
712
+ small
713
+ />
731
714
  </div>
732
715
  )}
733
716
  </div>
734
717
  </section>
735
718
 
736
- {/* Phase 4: Specs & Implementation */}
719
+ {/* Phase 3: Feature Specs */}
737
720
  <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">
738
721
  <div className="flex items-center justify-between mb-5 pb-4 border-b border-border/50">
739
722
  <div className="flex items-center gap-3">
740
723
  <div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
741
724
  <Code size={20} />
742
725
  </div>
743
- <h2 className="text-lg font-semibold">4. Feature Specs</h2>
726
+ <h2 className="text-lg font-semibold">3. Feature Specs</h2>
744
727
  </div>
745
728
  <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"
746
729
  onClick={() => setCreatingSpec(true)}>
@@ -749,6 +732,24 @@ function App() {
749
732
  </div>
750
733
 
751
734
  <div className="space-y-3 flex-1 overflow-y-auto max-h-[300px] pr-1">
735
+ {/* Auto-generate from Roadmap after Design Export */}
736
+ {(state?.product?.roadmap?.items?.filter(item =>
737
+ !item.completed &&
738
+ !state?.product?.roadmap?.isBoilerplate
739
+ ) ?? []).length > 0 && !state?.specs?.length && (
740
+ <div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 p-4 rounded-lg mb-3">
741
+ <p className="text-sm text-blue-700 dark:text-blue-300 mb-2">
742
+ Ready to generate specs from roadmap items?
743
+ </p>
744
+ <PromptButton
745
+ label="Generate All Specs"
746
+ prompt={`Antigravity, generate feature specs from the roadmap items. For each item in 'agent-os/product/roadmap.md' that is not yet completed, create a spec folder in 'agent-os/specs/[feature-name]/' with spec.md and tasks.md files. Context: 1. Read 'product-plan/product-overview.md' for data model/flows. 2. Read 'design-system/design-tokens.md' and 'design-system/app-shell.md' for UI/UX constraints. 3. Use the shape-spec command: Read 'agent-os/commands/shape-spec/shape-spec.md'.`}
747
+ onClick={copyToClipboard}
748
+ small
749
+ primary
750
+ />
751
+ </div>
752
+ )}
752
753
  {state?.specs?.map(spec => (
753
754
  <div key={spec.name} className="bg-secondary/20 p-4 rounded-lg border border-border/50 hover:border-border transition-colors group relative">
754
755
  <button
@@ -835,6 +836,134 @@ function App() {
835
836
 
836
837
  </div>
837
838
  </section>
839
+
840
+ {/* Phase 4: Implementation */}
841
+ <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">
842
+ <div className="flex items-center gap-3 mb-5 pb-4 border-b border-border/50">
843
+ <div className="p-2 bg-sidebar-primary/10 text-sidebar-primary rounded-lg">
844
+ <Package size={20} />
845
+ </div>
846
+ <h2 className="text-lg font-semibold">4. Implementation</h2>
847
+ </div>
848
+
849
+ <div className="space-y-3 flex-1">
850
+ {/* Scaffold Status */}
851
+ <div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
852
+ <span className="text-foreground font-medium text-sm flex items-center gap-2"><Layout size={16} className="text-muted-foreground" /> Scaffold</span>
853
+ {state?.implementation?.scaffolded ? (
854
+ <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>
855
+ ) : (
856
+ <span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">Pending</span>
857
+ )}
858
+ </div>
859
+
860
+ {/* Git Status */}
861
+ {state?.implementation?.git?.initialized && (
862
+ <div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
863
+ <span className="text-foreground font-medium text-sm flex items-center gap-2">
864
+ <svg className="w-4 h-4 text-muted-foreground" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" /></svg>
865
+ {state.implementation.git.branch || 'main'}
866
+ </span>
867
+ <div className="flex items-center gap-2">
868
+ {state.implementation.git.uncommitted > 0 && (
869
+ <span className="text-amber-600 bg-amber-50 dark:bg-amber-900/20 px-2 py-0.5 rounded text-xs font-medium border border-amber-200 dark:border-amber-800">
870
+ {state.implementation.git.uncommitted} uncommitted
871
+ </span>
872
+ )}
873
+ {state.implementation.git.uncommitted === 0 && (
874
+ <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">Clean</span>
875
+ )}
876
+ </div>
877
+ </div>
878
+ )}
879
+
880
+ {/* Tests & Coverage */}
881
+ {state?.implementation?.scaffolded && (
882
+ <div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
883
+ <span className="text-foreground font-medium text-sm flex items-center gap-2">
884
+ <CheckSquare size={16} className="text-muted-foreground" /> Tests
885
+ </span>
886
+ <div className="flex items-center gap-2">
887
+ {state?.implementation?.tests?.hasTests ? (
888
+ <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">
889
+ {state.implementation.tests.count} files
890
+ </span>
891
+ ) : (
892
+ <span className="text-muted-foreground bg-secondary px-2 py-0.5 rounded text-xs font-medium border border-border">No tests</span>
893
+ )}
894
+ {state?.implementation?.coverage !== null && state?.implementation?.coverage !== undefined && (
895
+ <span className={`px-2 py-0.5 rounded text-xs font-medium border ${state.implementation.coverage >= 80
896
+ ? 'text-emerald-600 bg-emerald-50 dark:bg-emerald-900/20 border-emerald-200 dark:border-emerald-800'
897
+ : state.implementation.coverage >= 50
898
+ ? 'text-amber-600 bg-amber-50 dark:bg-amber-900/20 border-amber-200 dark:border-amber-800'
899
+ : 'text-red-600 bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800'
900
+ }`}>
901
+ {state.implementation.coverage}% coverage
902
+ </span>
903
+ )}
904
+ </div>
905
+ </div>
906
+ )}
907
+
908
+ {/* Spec Progress */}
909
+ {state?.implementation?.specs && state.implementation.specs.total > 0 && (
910
+ <div className="flex items-center justify-between p-3 bg-secondary/30 rounded-lg border border-border/50">
911
+ <span className="text-foreground font-medium text-sm flex items-center gap-2">
912
+ <FileText size={16} className="text-muted-foreground" /> Specs
913
+ </span>
914
+ <span className={`px-2 py-0.5 rounded text-xs font-medium border ${state.implementation.specs.completed === state.implementation.specs.total
915
+ ? 'text-emerald-600 bg-emerald-50 dark:bg-emerald-900/20 border-emerald-200 dark:border-emerald-800'
916
+ : 'text-blue-600 bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800'
917
+ }`}>
918
+ {state.implementation.specs.completed}/{state.implementation.specs.total} complete
919
+ </span>
920
+ </div>
921
+ )}
922
+ </div>
923
+
924
+ <div className="mt-6">
925
+ {!state?.implementation?.scaffolded ? (
926
+ <PromptButton
927
+ label="Scaffold App"
928
+ prompt="Antigravity, scaffold the implementation. Read 'agent-os/commands/scaffold-implementation/scaffold-implementation.md'."
929
+ onClick={copyToClipboard}
930
+ />
931
+ ) : (
932
+ <div className="p-3 bg-secondary/30 rounded-lg border border-border/50 text-sm text-muted-foreground text-center italic mb-4">
933
+ App scaffolded. Ready for implementation.
934
+ </div>
935
+ )}
936
+
937
+ {state?.implementation?.scaffolded && state?.design?.exportPrompts?.oneShot && (
938
+ <div className="pt-3 border-t border-border/50">
939
+ <p className="text-xs text-muted-foreground mb-2 font-medium">Implementation Options:</p>
940
+ <div className="space-y-2">
941
+ <PromptButton
942
+ label="Option A: One-Shot (All)"
943
+ prompt={`Antigravity, implement the app. Read 'product-plan/prompts/one-shot-prompt.md'. If Context7 is configured, use it to verify library documentation.`}
944
+ onClick={copyToClipboard}
945
+ small
946
+ primary
947
+ />
948
+ {state?.design?.exportPrompts?.section && (
949
+ <div className="relative">
950
+ <PromptButton
951
+ label="Option B: Incremental (Section)"
952
+ prompt={`Antigravity, implement a section. Read 'product-plan/prompts/section-prompt.md'. Use Context7 for latest docs if available.`}
953
+ onClick={copyToClipboard}
954
+ small
955
+ />
956
+ <p className="text-[10px] text-muted-foreground mt-1.5 text-center leading-tight">
957
+ Build by spec from <strong>Feature Specs</strong> &larr;
958
+ </p>
959
+ </div>
960
+ )}
961
+ </div>
962
+ </div>
963
+ )}
964
+ </div>
965
+ </section>
966
+
838
967
  </main>
839
968
  </div>
840
969
  </div>