stitch-forge 0.3.1

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 (145) hide show
  1. package/.claude/skills/forge-build/SKILL.md +79 -0
  2. package/.claude/skills/forge-design/SKILL.md +64 -0
  3. package/.claude/skills/forge-discover/SKILL.md +139 -0
  4. package/.claude/skills/forge-generate/SKILL.md +77 -0
  5. package/.claude/skills/forge-preview/SKILL.md +26 -0
  6. package/.claude/skills/forge-research/SKILL.md +42 -0
  7. package/.claude/skills/forge-sync/SKILL.md +45 -0
  8. package/DESIGN.md +113 -0
  9. package/LICENSE +21 -0
  10. package/README.es.md +242 -0
  11. package/README.md +242 -0
  12. package/dist/adapters/astro.d.ts +8 -0
  13. package/dist/adapters/astro.js +24 -0
  14. package/dist/adapters/astro.js.map +1 -0
  15. package/dist/adapters/index.d.ts +3 -0
  16. package/dist/adapters/index.js +9 -0
  17. package/dist/adapters/index.js.map +1 -0
  18. package/dist/adapters/nextjs.d.ts +7 -0
  19. package/dist/adapters/nextjs.js +136 -0
  20. package/dist/adapters/nextjs.js.map +1 -0
  21. package/dist/adapters/static.d.ts +7 -0
  22. package/dist/adapters/static.js +43 -0
  23. package/dist/adapters/static.js.map +1 -0
  24. package/dist/adapters/types.d.ts +22 -0
  25. package/dist/adapters/types.js +6 -0
  26. package/dist/adapters/types.js.map +1 -0
  27. package/dist/commands/build.d.ts +7 -0
  28. package/dist/commands/build.js +98 -0
  29. package/dist/commands/build.js.map +1 -0
  30. package/dist/commands/design.d.ts +3 -0
  31. package/dist/commands/design.js +39 -0
  32. package/dist/commands/design.js.map +1 -0
  33. package/dist/commands/discover.d.ts +9 -0
  34. package/dist/commands/discover.js +91 -0
  35. package/dist/commands/discover.js.map +1 -0
  36. package/dist/commands/generate.d.ts +7 -0
  37. package/dist/commands/generate.js +105 -0
  38. package/dist/commands/generate.js.map +1 -0
  39. package/dist/commands/init.d.ts +1 -0
  40. package/dist/commands/init.js +99 -0
  41. package/dist/commands/init.js.map +1 -0
  42. package/dist/commands/preview.d.ts +5 -0
  43. package/dist/commands/preview.js +41 -0
  44. package/dist/commands/preview.js.map +1 -0
  45. package/dist/commands/research.d.ts +1 -0
  46. package/dist/commands/research.js +38 -0
  47. package/dist/commands/research.js.map +1 -0
  48. package/dist/commands/sync.d.ts +1 -0
  49. package/dist/commands/sync.js +53 -0
  50. package/dist/commands/sync.js.map +1 -0
  51. package/dist/commands/workflow.d.ts +1 -0
  52. package/dist/commands/workflow.js +38 -0
  53. package/dist/commands/workflow.js.map +1 -0
  54. package/dist/index.d.ts +2 -0
  55. package/dist/index.js +113 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/mcp/auth.d.ts +15 -0
  58. package/dist/mcp/auth.js +56 -0
  59. package/dist/mcp/auth.js.map +1 -0
  60. package/dist/mcp/client.d.ts +65 -0
  61. package/dist/mcp/client.js +302 -0
  62. package/dist/mcp/client.js.map +1 -0
  63. package/dist/mcp/tools.d.ts +26 -0
  64. package/dist/mcp/tools.js +46 -0
  65. package/dist/mcp/tools.js.map +1 -0
  66. package/dist/research/business-researcher.d.ts +41 -0
  67. package/dist/research/business-researcher.js +888 -0
  68. package/dist/research/business-researcher.js.map +1 -0
  69. package/dist/research/crawler.d.ts +11 -0
  70. package/dist/research/crawler.js +56 -0
  71. package/dist/research/crawler.js.map +1 -0
  72. package/dist/research/design-synthesizer.d.ts +46 -0
  73. package/dist/research/design-synthesizer.js +628 -0
  74. package/dist/research/design-synthesizer.js.map +1 -0
  75. package/dist/research/differ.d.ts +19 -0
  76. package/dist/research/differ.js +58 -0
  77. package/dist/research/differ.js.map +1 -0
  78. package/dist/research/known-state.json +68 -0
  79. package/dist/research/research-cache.d.ts +6 -0
  80. package/dist/research/research-cache.js +62 -0
  81. package/dist/research/research-cache.js.map +1 -0
  82. package/dist/research/types.d.ts +98 -0
  83. package/dist/research/types.js +6 -0
  84. package/dist/research/types.js.map +1 -0
  85. package/dist/research/updater.d.ts +5 -0
  86. package/dist/research/updater.js +43 -0
  87. package/dist/research/updater.js.map +1 -0
  88. package/dist/templates/design-md.d.ts +52 -0
  89. package/dist/templates/design-md.js +315 -0
  90. package/dist/templates/design-md.js.map +1 -0
  91. package/dist/templates/prompts.d.ts +31 -0
  92. package/dist/templates/prompts.js +39 -0
  93. package/dist/templates/prompts.js.map +1 -0
  94. package/dist/templates/workflows.d.ts +9 -0
  95. package/dist/templates/workflows.js +21 -0
  96. package/dist/templates/workflows.js.map +1 -0
  97. package/dist/tui/App.d.ts +1 -0
  98. package/dist/tui/App.js +87 -0
  99. package/dist/tui/App.js.map +1 -0
  100. package/dist/tui/Dashboard.d.ts +5 -0
  101. package/dist/tui/Dashboard.js +23 -0
  102. package/dist/tui/Dashboard.js.map +1 -0
  103. package/dist/tui/DesignEditor.d.ts +6 -0
  104. package/dist/tui/DesignEditor.js +76 -0
  105. package/dist/tui/DesignEditor.js.map +1 -0
  106. package/dist/tui/PromptBuilder.d.ts +5 -0
  107. package/dist/tui/PromptBuilder.js +102 -0
  108. package/dist/tui/PromptBuilder.js.map +1 -0
  109. package/dist/tui/components/QuotaMeter.d.ts +8 -0
  110. package/dist/tui/components/QuotaMeter.js +10 -0
  111. package/dist/tui/components/QuotaMeter.js.map +1 -0
  112. package/dist/tui/components/ScreenCard.d.ts +7 -0
  113. package/dist/tui/components/ScreenCard.js +6 -0
  114. package/dist/tui/components/ScreenCard.js.map +1 -0
  115. package/dist/tui/components/Spinner.d.ts +5 -0
  116. package/dist/tui/components/Spinner.js +7 -0
  117. package/dist/tui/components/Spinner.js.map +1 -0
  118. package/dist/tui/components/StatusBar.d.ts +7 -0
  119. package/dist/tui/components/StatusBar.js +6 -0
  120. package/dist/tui/components/StatusBar.js.map +1 -0
  121. package/dist/utils/config.d.ts +26 -0
  122. package/dist/utils/config.js +66 -0
  123. package/dist/utils/config.js.map +1 -0
  124. package/dist/utils/design-validator.d.ts +44 -0
  125. package/dist/utils/design-validator.js +396 -0
  126. package/dist/utils/design-validator.js.map +1 -0
  127. package/dist/utils/logger.d.ts +8 -0
  128. package/dist/utils/logger.js +10 -0
  129. package/dist/utils/logger.js.map +1 -0
  130. package/dist/utils/output-validator.d.ts +18 -0
  131. package/dist/utils/output-validator.js +194 -0
  132. package/dist/utils/output-validator.js.map +1 -0
  133. package/dist/utils/preview.d.ts +4 -0
  134. package/dist/utils/preview.js +49 -0
  135. package/dist/utils/preview.js.map +1 -0
  136. package/dist/utils/prompt-enhancer.d.ts +21 -0
  137. package/dist/utils/prompt-enhancer.js +104 -0
  138. package/dist/utils/prompt-enhancer.js.map +1 -0
  139. package/dist/utils/quota.d.ts +18 -0
  140. package/dist/utils/quota.js +49 -0
  141. package/dist/utils/quota.js.map +1 -0
  142. package/dist/utils/validators.d.ts +125 -0
  143. package/dist/utils/validators.js +110 -0
  144. package/dist/utils/validators.js.map +1 -0
  145. package/package.json +77 -0
@@ -0,0 +1,76 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import SelectInput from 'ink-select-input';
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+ import { StatusBar } from './components/StatusBar.js';
7
+ const SECTION_NAMES = [
8
+ '1. Visual Theme & Atmosphere',
9
+ '2. Color Palette & Roles',
10
+ '3. Typography',
11
+ '4. Spacing & Layout',
12
+ '5. Component Patterns',
13
+ '6. Iconography',
14
+ '7. Imagery Guidelines',
15
+ '8. Do\'s and Don\'ts',
16
+ ];
17
+ function parseDesignMd(content) {
18
+ const sections = new Map();
19
+ const lines = content.split('\n');
20
+ let currentSection = '';
21
+ let currentContent = [];
22
+ for (const line of lines) {
23
+ const match = line.match(/^## (\d+\..+)/);
24
+ if (match) {
25
+ if (currentSection) {
26
+ sections.set(currentSection, currentContent.join('\n').trim());
27
+ }
28
+ currentSection = match[1];
29
+ currentContent = [];
30
+ }
31
+ else if (currentSection) {
32
+ currentContent.push(line);
33
+ }
34
+ }
35
+ if (currentSection) {
36
+ sections.set(currentSection, currentContent.join('\n').trim());
37
+ }
38
+ return sections;
39
+ }
40
+ export function DesignEditor({ onBack, onGenerate }) {
41
+ const hasDesignMd = existsSync('DESIGN.md');
42
+ const [selectedSection, setSelectedSection] = useState(null);
43
+ useInput((input) => {
44
+ if (input === 'q') {
45
+ if (selectedSection) {
46
+ setSelectedSection(null);
47
+ }
48
+ else {
49
+ onBack?.();
50
+ }
51
+ }
52
+ });
53
+ if (!hasDesignMd) {
54
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Design System Editor" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "No DESIGN.md found in this project." }), _jsx(Text, { children: "A DESIGN.md defines your visual language \u2014 colors, fonts, spacing, and patterns." }), _jsx(Text, { children: "Stitch uses it to keep all generated screens consistent." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "To create one:" }) }), _jsxs(Text, { dimColor: true, children: [" Run: ", _jsx(Text, { bold: true, children: "forge design \"Company, Industry, Audience, Style\"" })] }), _jsxs(Text, { dimColor: true, children: [" Or use: ", _jsx(Text, { bold: true, children: "/forge-design" }), " in Claude Code"] })] }), _jsx(StatusBar, { hint: "q: back" })] }));
55
+ }
56
+ const content = readFileSync('DESIGN.md', 'utf-8');
57
+ const sections = parseDesignMd(content);
58
+ if (selectedSection) {
59
+ const sectionContent = sections.get(selectedSection) || '(empty)';
60
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: ["DESIGN.md \u2014 ", selectedSection] }), _jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, flexDirection: "column", children: _jsx(Text, { children: sectionContent }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "To edit this section, modify DESIGN.md directly or use /forge-design in Claude Code." }) }), _jsx(StatusBar, { hint: "q: back to sections" })] }));
61
+ }
62
+ const sectionItems = SECTION_NAMES.map((name) => {
63
+ const key = name.replace(/^\d+\.\s*/, '');
64
+ const hasContent = Array.from(sections.keys()).some(k => k.toLowerCase().includes(key.toLowerCase().substring(0, 10)));
65
+ return {
66
+ label: `${hasContent ? '✓' : '○'} ${name}`,
67
+ value: name,
68
+ };
69
+ });
70
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Design System Editor" }), _jsxs(Text, { dimColor: true, children: ["Your DESIGN.md has ", sections.size, " sections. Select one to view:"] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: sectionItems, onSelect: (item) => {
71
+ const matchKey = item.value.replace(/^\d+\.\s*/, '').toLowerCase();
72
+ const found = Array.from(sections.keys()).find(k => k.toLowerCase().includes(matchKey.substring(0, 10)));
73
+ setSelectedSection(found || item.value);
74
+ } }) }), _jsx(StatusBar, { hint: "Enter: view section q: back" })] }));
75
+ }
76
+ //# sourceMappingURL=DesignEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesignEditor.js","sourceRoot":"","sources":["../../src/tui/DesignEditor.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ interface PromptBuilderProps {
2
+ onBack?: () => void;
3
+ }
4
+ export declare function PromptBuilder({ onBack }: PromptBuilderProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,102 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import SelectInput from 'ink-select-input';
5
+ import TextInput from 'ink-text-input';
6
+ import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
7
+ import { buildInitialPrompt } from '../templates/prompts.js';
8
+ import { validatePrompt } from '../utils/validators.js';
9
+ import { StitchMcpClient } from '../mcp/client.js';
10
+ import { StatusBar } from './components/StatusBar.js';
11
+ import { Spinner } from './components/Spinner.js';
12
+ const PAGE_TYPES = [
13
+ { label: 'Landing Page', value: 'landing page' },
14
+ { label: 'About Page', value: 'about page' },
15
+ { label: 'Pricing Page', value: 'pricing page' },
16
+ { label: 'Dashboard', value: 'dashboard' },
17
+ { label: 'Contact Page', value: 'contact page' },
18
+ { label: 'Custom...', value: 'custom' },
19
+ ];
20
+ const MODEL_OPTIONS = [
21
+ { label: 'Flash — fast iteration (350/month)', value: 'flash' },
22
+ { label: 'Pro — higher quality (200/month)', value: 'pro' },
23
+ ];
24
+ export function PromptBuilder({ onBack }) {
25
+ const [step, setStep] = useState('page-type');
26
+ const [pageType, setPageType] = useState('');
27
+ const [description, setDescription] = useState('');
28
+ const [sections, setSections] = useState('');
29
+ const [customType, setCustomType] = useState('');
30
+ const [errors, setErrors] = useState([]);
31
+ const [result, setResult] = useState('');
32
+ useInput((input) => {
33
+ if (input === 'q' && step !== 'description' && step !== 'sections' && step !== 'sending') {
34
+ onBack?.();
35
+ }
36
+ });
37
+ const buildPrompt = () => {
38
+ const spec = {
39
+ productName: 'My Project',
40
+ productDescription: 'web application',
41
+ pageType: pageType === 'custom' ? customType : pageType,
42
+ targetUser: 'users',
43
+ visualTone: 'clean, modern',
44
+ sections: sections.split('\n').filter(s => s.trim()),
45
+ hasDesignMd: false,
46
+ };
47
+ spec.hasDesignMd = existsSync('DESIGN.md');
48
+ return buildInitialPrompt(spec);
49
+ };
50
+ const handleReview = () => {
51
+ const prompt = buildPrompt();
52
+ const validation = validatePrompt(prompt);
53
+ if (!validation.valid) {
54
+ setErrors(validation.errors);
55
+ }
56
+ else {
57
+ setErrors([]);
58
+ }
59
+ setStep('review');
60
+ };
61
+ const handleSend = (item) => {
62
+ const model = item.value;
63
+ setStep('sending');
64
+ const modelId = model === 'pro' ? 'GEMINI_3_PRO' : 'GEMINI_2_5_FLASH';
65
+ (async () => {
66
+ try {
67
+ const client = new StitchMcpClient();
68
+ const projects = await client.listProjects();
69
+ if (projects.length === 0) {
70
+ setResult('No Stitch projects found. Create one at stitch.withgoogle.com first.');
71
+ setStep('done');
72
+ return;
73
+ }
74
+ const projectId = projects[0].id;
75
+ const prompt = buildPrompt();
76
+ const generated = await client.generateScreen(projectId, prompt, modelId);
77
+ const html = await client.getScreenCode(projectId, generated.screenId);
78
+ if (!existsSync('screens'))
79
+ mkdirSync('screens');
80
+ const filename = `screens/${generated.name || generated.screenId}.html`;
81
+ writeFileSync(filename, html);
82
+ setResult(`Screen saved: ${filename}`);
83
+ setStep('done');
84
+ }
85
+ catch (err) {
86
+ setResult(`Generation failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
87
+ setStep('done');
88
+ }
89
+ })();
90
+ };
91
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Prompt Builder" }), _jsx(Text, { dimColor: true, children: "Build a screen prompt step by step" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [step === 'page-type' && (_jsxs(_Fragment, { children: [_jsx(Text, { children: "What type of page do you want to create?" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: PAGE_TYPES, onSelect: (item) => {
92
+ if (item.value === 'custom') {
93
+ setPageType('custom');
94
+ setStep('description');
95
+ }
96
+ else {
97
+ setPageType(item.value);
98
+ setStep('description');
99
+ }
100
+ } }) })] })), step === 'description' && pageType === 'custom' && !customType && (_jsxs(_Fragment, { children: [_jsx(Text, { children: "Enter the page type:" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "> " }), _jsx(TextInput, { value: customType, onChange: setCustomType, onSubmit: () => setStep('description') })] })] })), step === 'description' && (pageType !== 'custom' || customType) && (_jsxs(_Fragment, { children: [_jsx(Text, { children: "Describe the page in a few words:" }), _jsx(Text, { dimColor: true, children: "Example: \"A modern landing page for a project management SaaS\"" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "> " }), _jsx(TextInput, { value: description, onChange: setDescription, onSubmit: () => setStep('sections') })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter to continue" }) })] })), step === 'sections' && (_jsxs(_Fragment, { children: [_jsx(Text, { children: "What sections should it include? (one per line, Enter twice to finish)" }), _jsx(Text, { dimColor: true, children: "Example: Hero with CTA, Features grid, Testimonials, Footer" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "> " }), _jsx(TextInput, { value: sections, onChange: setSections, onSubmit: handleReview })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter to continue" }) })] })), step === 'review' && (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Generated Prompt:" }), _jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: _jsx(Text, { children: buildPrompt() }) }), errors.length > 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "Issues found:" }), errors.map((err, i) => (_jsxs(Text, { color: "red", children: [" ", err] }, i)))] })), errors.length === 0 && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "green", children: "Prompt looks good! Choose a model:" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: MODEL_OPTIONS, onSelect: handleSend }) })] }))] })), step === 'sending' && _jsx(Spinner, { label: "Preparing prompt..." }), step === 'done' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", children: result }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press q to go back to menu" }) })] }))] }), _jsx(StatusBar, { hint: step === 'description' || step === 'sections' ? 'type and press Enter' : 'q: back ctrl+c: exit' })] }));
101
+ }
102
+ //# sourceMappingURL=PromptBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromptBuilder.js","sourceRoot":"","sources":["../../src/tui/PromptBuilder.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface QuotaMeterProps {
2
+ label: string;
3
+ used: number;
4
+ limit: number;
5
+ width?: number;
6
+ }
7
+ export declare function QuotaMeter({ label, used, limit, width }: QuotaMeterProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function QuotaMeter({ label, used, limit, width = 20 }) {
4
+ const filled = Math.round((used / limit) * width);
5
+ const empty = width - filled;
6
+ const remaining = limit - used;
7
+ const isLow = remaining / limit < 0.1;
8
+ return (_jsxs(Box, { children: [_jsx(Text, { children: label.padEnd(14) }), _jsx(Text, { color: "gray", children: "[" }), _jsx(Text, { color: isLow ? 'red' : 'green', children: '='.repeat(filled) }), _jsx(Text, { color: "gray", children: '-'.repeat(empty) }), _jsx(Text, { color: "gray", children: "]" }), _jsxs(Text, { children: [" ", used, "/", limit] }), _jsxs(Text, { dimColor: true, children: [" (", remaining, " left)"] })] }));
9
+ }
10
+ //# sourceMappingURL=QuotaMeter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuotaMeter.js","sourceRoot":"","sources":["../../../src/tui/components/QuotaMeter.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAShC,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,EAAmB;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC7B,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;IAC/B,MAAM,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,GAAG,CAAC;IAEtC,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,EAC/B,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,kBAAS,EAC3B,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,YAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAQ,EACjE,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAQ,EAC7C,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,kBAAS,EAC3B,MAAC,IAAI,oBAAG,IAAI,OAAG,KAAK,IAAQ,EAC5B,MAAC,IAAI,IAAC,QAAQ,yBAAI,SAAS,cAAc,IACrC,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ interface ScreenCardProps {
2
+ name: string;
3
+ route?: string;
4
+ lastSynced?: string;
5
+ }
6
+ export declare function ScreenCard({ name, route, lastSynced }: ScreenCardProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function ScreenCard({ name, route, lastSynced }) {
4
+ return (_jsxs(Box, { borderStyle: "round", borderColor: "gray", paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, children: name }), route && _jsxs(Text, { dimColor: true, children: [" ", route] }), lastSynced && (_jsxs(Text, { dimColor: true, children: [" synced ", new Date(lastSynced).toLocaleDateString()] }))] }));
5
+ }
6
+ //# sourceMappingURL=ScreenCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScreenCard.js","sourceRoot":"","sources":["../../../src/tui/components/ScreenCard.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAQhC,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAmB;IACrE,OAAO,CACL,MAAC,GAAG,IAAC,WAAW,EAAC,OAAO,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,aACtE,KAAC,IAAI,IAAC,IAAI,kBAAE,IAAI,GAAQ,EACvB,KAAK,IAAI,MAAC,IAAI,IAAC,QAAQ,yBAAI,KAAK,IAAQ,EACxC,UAAU,IAAI,CACb,MAAC,IAAI,IAAC,QAAQ,gCAAW,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,kBAAkB,EAAE,IAAQ,CAC3E,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ interface SpinnerProps {
2
+ label: string;
3
+ }
4
+ export declare function Spinner({ label }: SpinnerProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import InkSpinner from 'ink-spinner';
4
+ export function Spinner({ label }) {
5
+ return (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: _jsx(InkSpinner, { type: "dots" }) }), _jsxs(Text, { children: [" ", label] })] }));
6
+ }
7
+ //# sourceMappingURL=Spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../../src/tui/components/Spinner.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,UAAU,MAAM,aAAa,CAAC;AAMrC,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAgB;IAC7C,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAChB,KAAC,UAAU,IAAC,IAAI,EAAC,MAAM,GAAG,GACrB,EACP,MAAC,IAAI,oBAAG,KAAK,IAAQ,IACjB,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ interface StatusBarProps {
2
+ projectName?: string;
3
+ model?: string;
4
+ hint?: string;
5
+ }
6
+ export declare function StatusBar({ projectName, model, hint }: StatusBarProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,6 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function StatusBar({ projectName, model, hint }) {
4
+ return (_jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginTop: 1, children: [projectName && (_jsxs(Text, { dimColor: true, children: ["Project: ", projectName] })), model && (_jsxs(Text, { dimColor: true, children: [" Model: ", model] })), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, children: hint || 'q: back ctrl+c: exit' })] }));
5
+ }
6
+ //# sourceMappingURL=StatusBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../src/tui/components/StatusBar.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAQhC,MAAM,UAAU,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAkB;IACpE,OAAO,CACL,MAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,aACnE,WAAW,IAAI,CACd,MAAC,IAAI,IAAC,QAAQ,gCAAW,WAAW,IAAQ,CAC7C,EACA,KAAK,IAAI,CACR,MAAC,IAAI,IAAC,QAAQ,gCAAW,KAAK,IAAQ,CACvC,EACD,KAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,GAAI,EACpB,KAAC,IAAI,IAAC,QAAQ,kBAAE,IAAI,IAAI,uBAAuB,GAAQ,IACnD,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface StitchConfig {
2
+ apiKey?: string;
3
+ projectId?: string;
4
+ projectName?: string;
5
+ defaultModel: 'GEMINI_3_PRO' | 'GEMINI_2_5_FLASH';
6
+ framework?: 'static' | 'astro' | 'nextjs';
7
+ screens: Array<{
8
+ id: string;
9
+ name: string;
10
+ route?: string;
11
+ lastSynced?: string;
12
+ }>;
13
+ quota: {
14
+ flashUsed: number;
15
+ proUsed: number;
16
+ resetDate: string;
17
+ };
18
+ lastSync?: string;
19
+ lastResearch?: string;
20
+ }
21
+ export declare function getConfigPath(): string;
22
+ export declare function configExists(): boolean;
23
+ export declare function getConfig(): StitchConfig;
24
+ export declare function saveConfig(config: StitchConfig): void;
25
+ export declare function updateConfig(updates: Partial<StitchConfig>): StitchConfig;
26
+ export declare function incrementQuota(model: 'GEMINI_3_PRO' | 'GEMINI_2_5_FLASH'): StitchConfig;
@@ -0,0 +1,66 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ const CONFIG_FILE = '.forgerc.json';
4
+ const DEFAULT_CONFIG = {
5
+ defaultModel: 'GEMINI_2_5_FLASH',
6
+ screens: [],
7
+ quota: {
8
+ flashUsed: 0,
9
+ proUsed: 0,
10
+ resetDate: getNextResetDate(),
11
+ },
12
+ };
13
+ function getNextResetDate() {
14
+ const now = new Date();
15
+ const next = new Date(now.getFullYear(), now.getMonth() + 1, 1);
16
+ return next.toISOString().split('T')[0];
17
+ }
18
+ export function getConfigPath() {
19
+ return join(process.cwd(), CONFIG_FILE);
20
+ }
21
+ export function configExists() {
22
+ return existsSync(getConfigPath());
23
+ }
24
+ export function getConfig() {
25
+ const path = getConfigPath();
26
+ if (!existsSync(path)) {
27
+ return { ...DEFAULT_CONFIG };
28
+ }
29
+ try {
30
+ const raw = readFileSync(path, 'utf-8');
31
+ return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
32
+ }
33
+ catch (error) {
34
+ const msg = error instanceof Error ? error.message : 'unknown error';
35
+ console.error(`[forge] Warning: Failed to parse ${CONFIG_FILE}: ${msg}. Using defaults.`);
36
+ return { ...DEFAULT_CONFIG };
37
+ }
38
+ }
39
+ export function saveConfig(config) {
40
+ const path = getConfigPath();
41
+ writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
42
+ }
43
+ export function updateConfig(updates) {
44
+ const config = { ...getConfig(), ...updates };
45
+ saveConfig(config);
46
+ return config;
47
+ }
48
+ export function incrementQuota(model) {
49
+ const config = getConfig();
50
+ // Check if quota needs reset
51
+ const now = new Date().toISOString().split('T')[0];
52
+ if (now >= config.quota.resetDate) {
53
+ config.quota.flashUsed = 0;
54
+ config.quota.proUsed = 0;
55
+ config.quota.resetDate = getNextResetDate();
56
+ }
57
+ if (model === 'GEMINI_2_5_FLASH') {
58
+ config.quota.flashUsed++;
59
+ }
60
+ else {
61
+ config.quota.proUsed++;
62
+ }
63
+ saveConfig(config);
64
+ return config;
65
+ }
66
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Design Quality Validator for DESIGN.md files.
3
+ *
4
+ * Scores a DESIGN.md across four dimensions — specificity, differentiation,
5
+ * completeness, and actionability — and surfaces concrete issues.
6
+ */
7
+ import type { BusinessResearchResult, CompetitorAnalysis, DesignQualityIssue, DesignQualityScore } from '../research/types.js';
8
+ /**
9
+ * Euclidean distance between two hex colors in RGB space.
10
+ * Threshold for "too similar": distance < 50.
11
+ */
12
+ export declare function hexDistance(a: string, b: string): number;
13
+ /**
14
+ * Scores how specific and concrete the DESIGN.md is (0-25).
15
+ * Penalizes placeholders, generic adjectives, missing hex values, etc.
16
+ */
17
+ export declare function scoreSpecificity(markdown: string): number;
18
+ /**
19
+ * Scores how differentiated the design is from competitors (0-25).
20
+ * Without competitor data, caps at 15 (cannot assess differentiation).
21
+ */
22
+ export declare function scoreDifferentiation(markdown: string, competitors?: CompetitorAnalysis[]): number;
23
+ /**
24
+ * Scores structural completeness of the DESIGN.md (0-25).
25
+ * Checks for all 8 sections, color count, component patterns, do/don't counts.
26
+ */
27
+ export declare function scoreCompleteness(markdown: string): number;
28
+ /**
29
+ * Scores how actionable and implementation-ready the rules are (0-25).
30
+ * Penalizes vague language, color words without hex, non-numeric sizes.
31
+ */
32
+ export declare function scoreActionability(markdown: string): number;
33
+ /**
34
+ * Checks for cultural alignment issues in the DESIGN.md.
35
+ */
36
+ export declare function checkCulturalAlignment(markdown: string, locale?: string, audience?: string): DesignQualityIssue[];
37
+ /**
38
+ * Orchestrates all sub-scorers and returns a complete quality score.
39
+ */
40
+ export declare function scoreDesignMd(markdown: string, research?: BusinessResearchResult): DesignQualityScore;
41
+ /**
42
+ * Formats a DesignQualityScore into a human-readable report.
43
+ */
44
+ export declare function formatDesignQualityReport(score: DesignQualityScore): string;