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.
- package/.claude/skills/forge-build/SKILL.md +79 -0
- package/.claude/skills/forge-design/SKILL.md +64 -0
- package/.claude/skills/forge-discover/SKILL.md +139 -0
- package/.claude/skills/forge-generate/SKILL.md +77 -0
- package/.claude/skills/forge-preview/SKILL.md +26 -0
- package/.claude/skills/forge-research/SKILL.md +42 -0
- package/.claude/skills/forge-sync/SKILL.md +45 -0
- package/DESIGN.md +113 -0
- package/LICENSE +21 -0
- package/README.es.md +242 -0
- package/README.md +242 -0
- package/dist/adapters/astro.d.ts +8 -0
- package/dist/adapters/astro.js +24 -0
- package/dist/adapters/astro.js.map +1 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.js +9 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/nextjs.d.ts +7 -0
- package/dist/adapters/nextjs.js +136 -0
- package/dist/adapters/nextjs.js.map +1 -0
- package/dist/adapters/static.d.ts +7 -0
- package/dist/adapters/static.js +43 -0
- package/dist/adapters/static.js.map +1 -0
- package/dist/adapters/types.d.ts +22 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/commands/build.d.ts +7 -0
- package/dist/commands/build.js +98 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/design.d.ts +3 -0
- package/dist/commands/design.js +39 -0
- package/dist/commands/design.js.map +1 -0
- package/dist/commands/discover.d.ts +9 -0
- package/dist/commands/discover.js +91 -0
- package/dist/commands/discover.js.map +1 -0
- package/dist/commands/generate.d.ts +7 -0
- package/dist/commands/generate.js +105 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +99 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/preview.d.ts +5 -0
- package/dist/commands/preview.js +41 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/research.d.ts +1 -0
- package/dist/commands/research.js +38 -0
- package/dist/commands/research.js.map +1 -0
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +53 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/workflow.d.ts +1 -0
- package/dist/commands/workflow.js +38 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +113 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/auth.d.ts +15 -0
- package/dist/mcp/auth.js +56 -0
- package/dist/mcp/auth.js.map +1 -0
- package/dist/mcp/client.d.ts +65 -0
- package/dist/mcp/client.js +302 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/tools.d.ts +26 -0
- package/dist/mcp/tools.js +46 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/research/business-researcher.d.ts +41 -0
- package/dist/research/business-researcher.js +888 -0
- package/dist/research/business-researcher.js.map +1 -0
- package/dist/research/crawler.d.ts +11 -0
- package/dist/research/crawler.js +56 -0
- package/dist/research/crawler.js.map +1 -0
- package/dist/research/design-synthesizer.d.ts +46 -0
- package/dist/research/design-synthesizer.js +628 -0
- package/dist/research/design-synthesizer.js.map +1 -0
- package/dist/research/differ.d.ts +19 -0
- package/dist/research/differ.js +58 -0
- package/dist/research/differ.js.map +1 -0
- package/dist/research/known-state.json +68 -0
- package/dist/research/research-cache.d.ts +6 -0
- package/dist/research/research-cache.js +62 -0
- package/dist/research/research-cache.js.map +1 -0
- package/dist/research/types.d.ts +98 -0
- package/dist/research/types.js +6 -0
- package/dist/research/types.js.map +1 -0
- package/dist/research/updater.d.ts +5 -0
- package/dist/research/updater.js +43 -0
- package/dist/research/updater.js.map +1 -0
- package/dist/templates/design-md.d.ts +52 -0
- package/dist/templates/design-md.js +315 -0
- package/dist/templates/design-md.js.map +1 -0
- package/dist/templates/prompts.d.ts +31 -0
- package/dist/templates/prompts.js +39 -0
- package/dist/templates/prompts.js.map +1 -0
- package/dist/templates/workflows.d.ts +9 -0
- package/dist/templates/workflows.js +21 -0
- package/dist/templates/workflows.js.map +1 -0
- package/dist/tui/App.d.ts +1 -0
- package/dist/tui/App.js +87 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/Dashboard.d.ts +5 -0
- package/dist/tui/Dashboard.js +23 -0
- package/dist/tui/Dashboard.js.map +1 -0
- package/dist/tui/DesignEditor.d.ts +6 -0
- package/dist/tui/DesignEditor.js +76 -0
- package/dist/tui/DesignEditor.js.map +1 -0
- package/dist/tui/PromptBuilder.d.ts +5 -0
- package/dist/tui/PromptBuilder.js +102 -0
- package/dist/tui/PromptBuilder.js.map +1 -0
- package/dist/tui/components/QuotaMeter.d.ts +8 -0
- package/dist/tui/components/QuotaMeter.js +10 -0
- package/dist/tui/components/QuotaMeter.js.map +1 -0
- package/dist/tui/components/ScreenCard.d.ts +7 -0
- package/dist/tui/components/ScreenCard.js +6 -0
- package/dist/tui/components/ScreenCard.js.map +1 -0
- package/dist/tui/components/Spinner.d.ts +5 -0
- package/dist/tui/components/Spinner.js +7 -0
- package/dist/tui/components/Spinner.js.map +1 -0
- package/dist/tui/components/StatusBar.d.ts +7 -0
- package/dist/tui/components/StatusBar.js +6 -0
- package/dist/tui/components/StatusBar.js.map +1 -0
- package/dist/utils/config.d.ts +26 -0
- package/dist/utils/config.js +66 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/design-validator.d.ts +44 -0
- package/dist/utils/design-validator.js +396 -0
- package/dist/utils/design-validator.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +10 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/output-validator.d.ts +18 -0
- package/dist/utils/output-validator.js +194 -0
- package/dist/utils/output-validator.js.map +1 -0
- package/dist/utils/preview.d.ts +4 -0
- package/dist/utils/preview.js +49 -0
- package/dist/utils/preview.js.map +1 -0
- package/dist/utils/prompt-enhancer.d.ts +21 -0
- package/dist/utils/prompt-enhancer.js +104 -0
- package/dist/utils/prompt-enhancer.js.map +1 -0
- package/dist/utils/quota.d.ts +18 -0
- package/dist/utils/quota.js +49 -0
- package/dist/utils/quota.js.map +1 -0
- package/dist/utils/validators.d.ts +125 -0
- package/dist/utils/validators.js +110 -0
- package/dist/utils/validators.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import * as cheerio from 'cheerio';
|
|
4
|
+
import { getForgeSignature } from './types.js';
|
|
5
|
+
export class NextjsAdapter {
|
|
6
|
+
name = 'nextjs';
|
|
7
|
+
async build(context) {
|
|
8
|
+
const { outputDir, screens } = context;
|
|
9
|
+
const files = [];
|
|
10
|
+
// Create package.json
|
|
11
|
+
const packageJsonPath = join(outputDir, 'package.json');
|
|
12
|
+
mkdirSync(outputDir, { recursive: true });
|
|
13
|
+
writeFileSync(packageJsonPath, JSON.stringify({
|
|
14
|
+
name: 'stitch-forge-site',
|
|
15
|
+
version: '0.2.0',
|
|
16
|
+
private: true,
|
|
17
|
+
scripts: {
|
|
18
|
+
dev: 'next dev',
|
|
19
|
+
build: 'next build',
|
|
20
|
+
start: 'next start',
|
|
21
|
+
},
|
|
22
|
+
dependencies: {
|
|
23
|
+
next: '^14.2.0',
|
|
24
|
+
react: '^18.3.1',
|
|
25
|
+
'react-dom': '^18.3.1',
|
|
26
|
+
},
|
|
27
|
+
}, null, 2) + '\n');
|
|
28
|
+
files.push(packageJsonPath);
|
|
29
|
+
// Create next.config.js
|
|
30
|
+
const nextConfigPath = join(outputDir, 'next.config.js');
|
|
31
|
+
writeFileSync(nextConfigPath, `/** @type {import('next').NextConfig} */\nconst nextConfig = {\n output: 'export',\n};\n\nmodule.exports = nextConfig;\n`);
|
|
32
|
+
files.push(nextConfigPath);
|
|
33
|
+
// Create tsconfig.json
|
|
34
|
+
const tsconfigPath = join(outputDir, 'tsconfig.json');
|
|
35
|
+
writeFileSync(tsconfigPath, JSON.stringify({
|
|
36
|
+
compilerOptions: {
|
|
37
|
+
target: 'es5',
|
|
38
|
+
lib: ['dom', 'dom.iterable', 'esnext'],
|
|
39
|
+
allowJs: true,
|
|
40
|
+
skipLibCheck: true,
|
|
41
|
+
strict: true,
|
|
42
|
+
noEmit: true,
|
|
43
|
+
esModuleInterop: true,
|
|
44
|
+
module: 'esnext',
|
|
45
|
+
moduleResolution: 'bundler',
|
|
46
|
+
resolveJsonModule: true,
|
|
47
|
+
isolatedModules: true,
|
|
48
|
+
jsx: 'preserve',
|
|
49
|
+
incremental: true,
|
|
50
|
+
plugins: [{ name: 'next' }],
|
|
51
|
+
paths: { '@/*': ['./*'] },
|
|
52
|
+
},
|
|
53
|
+
include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],
|
|
54
|
+
exclude: ['node_modules'],
|
|
55
|
+
}, null, 2) + '\n');
|
|
56
|
+
files.push(tsconfigPath);
|
|
57
|
+
// Create app directory
|
|
58
|
+
const appDir = join(outputDir, 'app');
|
|
59
|
+
mkdirSync(appDir, { recursive: true });
|
|
60
|
+
// Create globals.css
|
|
61
|
+
const globalsCssPath = join(appDir, 'globals.css');
|
|
62
|
+
writeFileSync(globalsCssPath, '/* Global styles placeholder */\n');
|
|
63
|
+
files.push(globalsCssPath);
|
|
64
|
+
// Create root layout
|
|
65
|
+
const layoutPath = join(appDir, 'layout.tsx');
|
|
66
|
+
writeFileSync(layoutPath, `import './globals.css';
|
|
67
|
+
|
|
68
|
+
export const metadata = {
|
|
69
|
+
title: 'Stitch Forge Site',
|
|
70
|
+
description: 'Generated by Stitch Forge',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default function RootLayout({
|
|
74
|
+
children,
|
|
75
|
+
}: {
|
|
76
|
+
children: React.ReactNode;
|
|
77
|
+
}) {
|
|
78
|
+
return (
|
|
79
|
+
<html lang="en">
|
|
80
|
+
<body>{children}</body>
|
|
81
|
+
</html>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
`);
|
|
85
|
+
files.push(layoutPath);
|
|
86
|
+
// Create pages for each screen
|
|
87
|
+
for (const screen of screens) {
|
|
88
|
+
const pagePath = this.routeToPagePath(appDir, screen.route);
|
|
89
|
+
const pageDir = pagePath.substring(0, pagePath.lastIndexOf('/'));
|
|
90
|
+
mkdirSync(pageDir, { recursive: true });
|
|
91
|
+
const $ = cheerio.load(screen.html);
|
|
92
|
+
const title = $('title').text() || screen.name;
|
|
93
|
+
const bodyContent = $('body').html() || screen.html;
|
|
94
|
+
// Extract inline styles from <head> if any
|
|
95
|
+
const styles = [];
|
|
96
|
+
$('style').each((_, el) => {
|
|
97
|
+
styles.push($(el).html() || '');
|
|
98
|
+
});
|
|
99
|
+
const styleTag = styles.length > 0
|
|
100
|
+
? `\n <style dangerouslySetInnerHTML={{ __html: \`${styles.join('\n')}\` }} />`
|
|
101
|
+
: '';
|
|
102
|
+
const forgeComment = getForgeSignature().replace('<!--', '{/*').replace('-->', '*/}');
|
|
103
|
+
const pageContent = `${forgeComment}import type { Metadata } from 'next';
|
|
104
|
+
|
|
105
|
+
export const metadata: Metadata = {
|
|
106
|
+
title: ${JSON.stringify(title)},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export default function Page() {
|
|
110
|
+
return (
|
|
111
|
+
<>
|
|
112
|
+
<div dangerouslySetInnerHTML={{ __html: \`${this.escapeTemplateLiteral(bodyContent)}\` }} />${styleTag}
|
|
113
|
+
</>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
writeFileSync(pagePath, pageContent);
|
|
118
|
+
files.push(pagePath);
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
files,
|
|
122
|
+
instructions: [`cd ${outputDir} && npm install && npx next dev`],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
routeToPagePath(appDir, route) {
|
|
126
|
+
if (route === '/') {
|
|
127
|
+
return join(appDir, 'page.tsx');
|
|
128
|
+
}
|
|
129
|
+
const cleanRoute = route.replace(/^\//, '');
|
|
130
|
+
return join(appDir, cleanRoute, 'page.tsx');
|
|
131
|
+
}
|
|
132
|
+
escapeTemplateLiteral(str) {
|
|
133
|
+
return str.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=nextjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextjs.js","sourceRoot":"","sources":["../../src/adapters/nextjs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAA8E,MAAM,YAAY,CAAC;AAE3H,MAAM,OAAO,aAAa;IACf,IAAI,GAAc,QAAQ,CAAC;IAEpC,KAAK,CAAC,KAAK,CAAC,OAAqB;QAC/B,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACvC,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,sBAAsB;QACtB,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACxD,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,aAAa,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC;YAC5C,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE;gBACP,GAAG,EAAE,UAAU;gBACf,KAAK,EAAE,YAAY;gBACnB,KAAK,EAAE,YAAY;aACpB;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,SAAS;gBAChB,WAAW,EAAE,SAAS;aACvB;SACF,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAE5B,wBAAwB;QACxB,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACzD,aAAa,CAAC,cAAc,EAAE,2HAA2H,CAAC,CAAC;QAC3J,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE3B,uBAAuB;QACvB,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QACtD,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC;YACzC,eAAe,EAAE;gBACf,MAAM,EAAE,KAAK;gBACb,GAAG,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAC;gBACtC,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,IAAI;gBAClB,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;gBACZ,eAAe,EAAE,IAAI;gBACrB,MAAM,EAAE,QAAQ;gBAChB,gBAAgB,EAAE,SAAS;gBAC3B,iBAAiB,EAAE,IAAI;gBACvB,eAAe,EAAE,IAAI;gBACrB,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC3B,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE;aAC1B;YACD,OAAO,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,qBAAqB,CAAC;YACxE,OAAO,EAAE,CAAC,cAAc,CAAC;SAC1B,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEzB,uBAAuB;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACtC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvC,qBAAqB;QACrB,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACnD,aAAa,CAAC,cAAc,EAAE,mCAAmC,CAAC,CAAC;QACnE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE3B,qBAAqB;QACrB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC9C,aAAa,CAAC,UAAU,EAAE;;;;;;;;;;;;;;;;;;CAkB7B,CAAC,CAAC;QACC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEvB,+BAA+B;QAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;YACjE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAExC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC;YAC/C,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC;YAEpD,2CAA2C;YAC3C,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;gBACxB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC;gBAChC,CAAC,CAAC,uDAAuD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;gBACpF,CAAC,CAAC,EAAE,CAAC;YAEP,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACtF,MAAM,WAAW,GAAG,GAAG,YAAY;;;WAG9B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;;;;;;kDAMkB,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,WAAW,QAAQ;;;;CAI3G,CAAC;YACI,aAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QAED,OAAO;YACL,KAAK;YACL,YAAY,EAAE,CAAC,MAAM,SAAS,iCAAiC,CAAC;SACjE,CAAC;IACJ,CAAC;IAEO,eAAe,CAAC,MAAc,EAAE,KAAa;QACnD,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC9C,CAAC;IAEO,qBAAqB,CAAC,GAAW;QACvC,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClF,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Framework, type FrameworkAdapter, type BuildContext, type BuildResult } from './types.js';
|
|
2
|
+
export declare class StaticAdapter implements FrameworkAdapter {
|
|
3
|
+
readonly name: Framework;
|
|
4
|
+
build(context: BuildContext): Promise<BuildResult>;
|
|
5
|
+
private buildNav;
|
|
6
|
+
private routeToFilePath;
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import * as cheerio from 'cheerio';
|
|
4
|
+
import { getForgeSignature } from './types.js';
|
|
5
|
+
export class StaticAdapter {
|
|
6
|
+
name = 'static';
|
|
7
|
+
async build(context) {
|
|
8
|
+
const { outputDir, screens } = context;
|
|
9
|
+
const files = [];
|
|
10
|
+
// Build navigation HTML
|
|
11
|
+
const navHtml = this.buildNav(screens);
|
|
12
|
+
for (const screen of screens) {
|
|
13
|
+
const $ = cheerio.load(screen.html);
|
|
14
|
+
// Inject navigation at top of <body>
|
|
15
|
+
$('body').prepend(navHtml);
|
|
16
|
+
// Determine file path
|
|
17
|
+
const filePath = this.routeToFilePath(outputDir, screen.route);
|
|
18
|
+
const dir = filePath.substring(0, filePath.lastIndexOf('/'));
|
|
19
|
+
mkdirSync(dir, { recursive: true });
|
|
20
|
+
writeFileSync(filePath, getForgeSignature() + $.html());
|
|
21
|
+
files.push(filePath);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
files,
|
|
25
|
+
instructions: ['Open dist/index.html in your browser'],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
buildNav(screens) {
|
|
29
|
+
const links = screens
|
|
30
|
+
.map((s) => `<a href="${s.route === '/' ? '/index.html' : s.route + '/index.html'}" style="margin-right:1rem;">${s.name}</a>`)
|
|
31
|
+
.join('\n ');
|
|
32
|
+
return `<nav data-forge-nav style="padding:0.5rem 1rem;background:#f0f0f0;border-bottom:1px solid #ddd;display:flex;gap:0.5rem;">\n ${links}\n </nav>`;
|
|
33
|
+
}
|
|
34
|
+
routeToFilePath(outputDir, route) {
|
|
35
|
+
if (route === '/') {
|
|
36
|
+
return join(outputDir, 'index.html');
|
|
37
|
+
}
|
|
38
|
+
// Strip leading slash, create directory structure
|
|
39
|
+
const cleanRoute = route.replace(/^\//, '');
|
|
40
|
+
return join(outputDir, cleanRoute, 'index.html');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=static.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static.js","sourceRoot":"","sources":["../../src/adapters/static.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAA8E,MAAM,YAAY,CAAC;AAE3H,MAAM,OAAO,aAAa;IACf,IAAI,GAAc,QAAQ,CAAC;IAEpC,KAAK,CAAC,KAAK,CAAC,OAAqB;QAC/B,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACvC,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,wBAAwB;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEvC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAEpC,qCAAqC;YACrC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAE3B,sBAAsB;YACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,aAAa,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QAED,OAAO;YACL,KAAK;YACL,YAAY,EAAE,CAAC,sCAAsC,CAAC;SACvD,CAAC;IACJ,CAAC;IAEO,QAAQ,CAAC,OAA0C;QACzD,MAAM,KAAK,GAAG,OAAO;aAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,aAAa,gCAAgC,CAAC,CAAC,IAAI,MAAM,CAAC;aAC7H,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClB,OAAO,kIAAkI,KAAK,YAAY,CAAC;IAC7J,CAAC;IAEO,eAAe,CAAC,SAAiB,EAAE,KAAa;QACtD,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACvC,CAAC;QACD,kDAAkD;QAClD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IACnD,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type Framework = 'static' | 'astro' | 'nextjs';
|
|
2
|
+
/** Stitch Forge signature injected as HTML comment at the top of every generated file */
|
|
3
|
+
export declare function getForgeSignature(): string;
|
|
4
|
+
export interface ScreenData {
|
|
5
|
+
screenId: string;
|
|
6
|
+
route: string;
|
|
7
|
+
name: string;
|
|
8
|
+
html: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BuildContext {
|
|
11
|
+
projectId: string;
|
|
12
|
+
outputDir: string;
|
|
13
|
+
screens: ScreenData[];
|
|
14
|
+
}
|
|
15
|
+
export interface BuildResult {
|
|
16
|
+
files: string[];
|
|
17
|
+
instructions: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface FrameworkAdapter {
|
|
20
|
+
readonly name: Framework;
|
|
21
|
+
build(context: BuildContext): Promise<BuildResult>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Stitch Forge signature injected as HTML comment at the top of every generated file */
|
|
2
|
+
export function getForgeSignature() {
|
|
3
|
+
const now = new Date().toISOString().split('T')[0];
|
|
4
|
+
return `<!-- Built with Stitch Forge (https://github.com/FReptar0/stitch-forge) — ${now} -->\n`;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAEA,yFAAyF;AACzF,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,6EAA6E,GAAG,QAAQ,CAAC;AAClG,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { log } from '../utils/logger.js';
|
|
2
|
+
import { getConfig } from '../utils/config.js';
|
|
3
|
+
import { StitchMcpClient } from '../mcp/client.js';
|
|
4
|
+
import { getAdapter } from '../adapters/index.js';
|
|
5
|
+
import { AstroAdapter } from '../adapters/astro.js';
|
|
6
|
+
const VALID_FRAMEWORKS = ['static', 'astro', 'nextjs'];
|
|
7
|
+
export async function runBuild(opts) {
|
|
8
|
+
const config = getConfig();
|
|
9
|
+
const projectId = opts.project || config.projectId;
|
|
10
|
+
if (!projectId) {
|
|
11
|
+
log.error('No project ID. Use --project <id> or run `forge init` first.');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
// Resolve framework: CLI flag > config > default
|
|
15
|
+
const framework = (opts.framework || config.framework || 'static');
|
|
16
|
+
if (!VALID_FRAMEWORKS.includes(framework)) {
|
|
17
|
+
log.error(`Unknown framework "${framework}". Valid options: ${VALID_FRAMEWORKS.join(', ')}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
let client;
|
|
21
|
+
try {
|
|
22
|
+
client = new StitchMcpClient();
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
log.error(err instanceof Error ? err.message : 'Failed to initialize Stitch client.');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
log.step(1, 3, 'Fetching screens...');
|
|
29
|
+
const screens = await client.listScreens(projectId);
|
|
30
|
+
if (screens.length === 0) {
|
|
31
|
+
log.error('No screens in project. Run `forge generate` first.');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
// Build route mapping
|
|
35
|
+
const routes = screens.map((screen, i) => ({
|
|
36
|
+
screenId: screen.id,
|
|
37
|
+
route: opts.auto ? inferRoute(screen.name, i) : screen.name,
|
|
38
|
+
name: screen.name,
|
|
39
|
+
}));
|
|
40
|
+
if (!opts.auto) {
|
|
41
|
+
log.info('Auto-mapping screens to routes (use --auto or TUI for manual mapping)');
|
|
42
|
+
}
|
|
43
|
+
log.info(`Using framework: ${framework}`);
|
|
44
|
+
if (framework === 'astro') {
|
|
45
|
+
// Astro path: delegate to Stitch MCP build_site
|
|
46
|
+
log.step(2, 3, `Building Astro site with ${routes.length} routes...`);
|
|
47
|
+
const adapter = new AstroAdapter(client);
|
|
48
|
+
const result = await adapter.build({
|
|
49
|
+
projectId,
|
|
50
|
+
outputDir: 'dist',
|
|
51
|
+
screens: routes.map((r) => ({
|
|
52
|
+
screenId: r.screenId,
|
|
53
|
+
route: r.route,
|
|
54
|
+
name: r.name,
|
|
55
|
+
html: '', // Astro adapter uses MCP buildSite, doesn't need HTML
|
|
56
|
+
})),
|
|
57
|
+
});
|
|
58
|
+
log.step(3, 3, 'Site generated.');
|
|
59
|
+
log.success('Site built successfully!');
|
|
60
|
+
for (const instruction of result.instructions) {
|
|
61
|
+
log.info(instruction);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Static / Next.js path: fetch HTML per screen, delegate to adapter
|
|
66
|
+
log.step(2, 3, `Fetching screen code for ${routes.length} screens...`);
|
|
67
|
+
const screenData = [];
|
|
68
|
+
for (const route of routes) {
|
|
69
|
+
const html = await client.getScreenCode(projectId, route.screenId);
|
|
70
|
+
screenData.push({
|
|
71
|
+
screenId: route.screenId,
|
|
72
|
+
route: route.route,
|
|
73
|
+
name: route.name,
|
|
74
|
+
html,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const adapter = getAdapter(framework);
|
|
78
|
+
log.step(3, 3, `Building ${framework} site...`);
|
|
79
|
+
const result = await adapter.build({
|
|
80
|
+
projectId,
|
|
81
|
+
outputDir: 'dist',
|
|
82
|
+
screens: screenData,
|
|
83
|
+
});
|
|
84
|
+
log.success('Site built successfully!');
|
|
85
|
+
log.info('');
|
|
86
|
+
log.info(`Generated ${result.files.length} files.`);
|
|
87
|
+
for (const instruction of result.instructions) {
|
|
88
|
+
log.info(instruction);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function inferRoute(name, index) {
|
|
93
|
+
const normalized = name.toLowerCase().replace(/\s+/g, '-');
|
|
94
|
+
if (index === 0 || /home|landing|hero|main/i.test(name))
|
|
95
|
+
return '/';
|
|
96
|
+
return `/${normalized}`;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { writeFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { log } from '../utils/logger.js';
|
|
3
|
+
import { generateDesignMdTemplate } from '../templates/design-md.js';
|
|
4
|
+
export async function runDesign(briefText, opts) {
|
|
5
|
+
if (existsSync('DESIGN.md') && !opts?.force) {
|
|
6
|
+
const rl = await import('node:readline');
|
|
7
|
+
const iface = rl.createInterface({ input: process.stdin, output: process.stderr });
|
|
8
|
+
const answer = await new Promise(resolve => {
|
|
9
|
+
iface.question('DESIGN.md already exists. Overwrite? (y/N) ', resolve);
|
|
10
|
+
});
|
|
11
|
+
iface.close();
|
|
12
|
+
if (answer.toLowerCase() !== 'y') {
|
|
13
|
+
log.info('Skipped. Use --force to overwrite without asking.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (!briefText.trim()) {
|
|
18
|
+
log.error('Provide a brand brief. Example:');
|
|
19
|
+
log.info(' forge design "Acme Corp, SaaS platform, startups, modern minimal"');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
// Parse brief text into structured brief
|
|
23
|
+
// This is a minimal parser — Claude Code slash command provides richer input
|
|
24
|
+
const parts = briefText.split(',').map(s => s.trim());
|
|
25
|
+
const brief = {
|
|
26
|
+
companyName: parts[0] || 'Company',
|
|
27
|
+
industry: parts[1] || 'Technology',
|
|
28
|
+
targetAudience: parts[2] || 'Professionals',
|
|
29
|
+
aesthetic: parts[3] || 'modern clean',
|
|
30
|
+
};
|
|
31
|
+
log.step(1, 2, `Generating DESIGN.md for ${brief.companyName}...`);
|
|
32
|
+
const content = generateDesignMdTemplate(brief);
|
|
33
|
+
log.step(2, 2, 'Writing DESIGN.md...');
|
|
34
|
+
writeFileSync('DESIGN.md', content);
|
|
35
|
+
log.success(`DESIGN.md created for ${brief.companyName}`);
|
|
36
|
+
log.info('Review and fill in placeholder sections (marked with <!-- -->)');
|
|
37
|
+
log.info('Then import into Stitch project for consistent generation.');
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=design.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/commands/design.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAoB,MAAM,2BAA2B,CAAC;AAEvF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB,EAAE,IAA0B;IAC3E,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACnF,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAS,OAAO,CAAC,EAAE;YACjD,KAAK,CAAC,QAAQ,CAAC,6CAA6C,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;IACH,CAAC;IAED,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACtB,GAAG,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAC7C,GAAG,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,yCAAyC;IACzC,6EAA6E;IAC7E,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,GAAgB;QACzB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS;QAClC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,YAAY;QAClC,cAAc,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,eAAe;QAC3C,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,cAAc;KACtC,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,4BAA4B,KAAK,CAAC,WAAW,KAAK,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEhD,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,sBAAsB,CAAC,CAAC;IACvC,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAEpC,GAAG,CAAC,OAAO,CAAC,yBAAyB,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,GAAG,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;IAC3E,GAAG,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { writeFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { log } from '../utils/logger.js';
|
|
3
|
+
import { researchBusiness } from '../research/business-researcher.js';
|
|
4
|
+
import { synthesizeDesign } from '../research/design-synthesizer.js';
|
|
5
|
+
import { cacheResearch } from '../research/research-cache.js';
|
|
6
|
+
import { formatDesignQualityReport } from '../utils/design-validator.js';
|
|
7
|
+
export async function runDiscover(briefText, opts) {
|
|
8
|
+
if (!briefText.trim()) {
|
|
9
|
+
log.error('Provide a business brief. Example:');
|
|
10
|
+
log.info(' forge discover "Tiendas 3B, hard-discount retail, Mexican families, confident warm" --url https://tiendas3b.com');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
// Check existing DESIGN.md
|
|
14
|
+
if (existsSync('DESIGN.md') && !opts.force) {
|
|
15
|
+
const rl = await import('node:readline');
|
|
16
|
+
const iface = rl.createInterface({ input: process.stdin, output: process.stderr });
|
|
17
|
+
const answer = await new Promise(resolve => {
|
|
18
|
+
iface.question('DESIGN.md already exists. Overwrite? (y/N) ', resolve);
|
|
19
|
+
});
|
|
20
|
+
iface.close();
|
|
21
|
+
if (answer.toLowerCase() !== 'y') {
|
|
22
|
+
log.info('Skipped. Use --force to overwrite without asking.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Parse brief
|
|
27
|
+
const parts = briefText.split(',').map(s => s.trim());
|
|
28
|
+
const brief = {
|
|
29
|
+
companyName: parts[0] || 'Company',
|
|
30
|
+
industry: parts[1] || 'Technology',
|
|
31
|
+
targetAudience: parts[2] || 'Professionals',
|
|
32
|
+
aesthetic: parts[3] || 'modern confident',
|
|
33
|
+
websiteUrl: opts.url,
|
|
34
|
+
competitorUrls: opts.competitors?.split(',').map(s => s.trim()),
|
|
35
|
+
locale: opts.locale,
|
|
36
|
+
};
|
|
37
|
+
if (opts.noResearch) {
|
|
38
|
+
// Fall back to static template
|
|
39
|
+
log.info('Research disabled. Using industry presets...');
|
|
40
|
+
const { generateDesignMdTemplate } = await import('../templates/design-md.js');
|
|
41
|
+
const content = generateDesignMdTemplate(brief);
|
|
42
|
+
writeFileSync('DESIGN.md', content);
|
|
43
|
+
log.success(`DESIGN.md created for ${brief.companyName} (preset mode)`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Research phase
|
|
47
|
+
log.step(1, 4, `Researching ${brief.companyName}...`);
|
|
48
|
+
const research = await researchBusiness(brief);
|
|
49
|
+
log.info(` Research confidence: ${research.confidence}%`);
|
|
50
|
+
if (research.currentSite) {
|
|
51
|
+
log.info(` Current site analyzed: ${research.currentSite.url}`);
|
|
52
|
+
log.info(` Colors found: ${research.currentSite.palette.colors.length}`);
|
|
53
|
+
log.info(` Fonts found: ${research.currentSite.typography.fonts.join(', ') || 'none detected'}`);
|
|
54
|
+
}
|
|
55
|
+
if (research.competitors.length > 0) {
|
|
56
|
+
log.info(` Competitors analyzed: ${research.competitors.map(c => c.name).join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
if (research.fallbacksUsed.length > 0) {
|
|
59
|
+
log.warn(` Fallbacks used: ${research.fallbacksUsed.join(', ')}`);
|
|
60
|
+
}
|
|
61
|
+
// Synthesis phase
|
|
62
|
+
log.step(2, 4, 'Synthesizing design system...');
|
|
63
|
+
const design = synthesizeDesign(research);
|
|
64
|
+
// Quality check
|
|
65
|
+
log.step(3, 4, 'Validating quality...');
|
|
66
|
+
log.info('');
|
|
67
|
+
log.info(formatDesignQualityReport(design.qualityScore));
|
|
68
|
+
log.info('');
|
|
69
|
+
log.info(` Token estimate: ${design.tokenEstimate} (limit: 3000)`);
|
|
70
|
+
log.info(` Data sources: ${design.sources.join(', ')}`);
|
|
71
|
+
// Write
|
|
72
|
+
log.step(4, 4, 'Writing DESIGN.md...');
|
|
73
|
+
writeFileSync('DESIGN.md', design.markdown);
|
|
74
|
+
// Cache research
|
|
75
|
+
try {
|
|
76
|
+
cacheResearch(brief.companyName, research);
|
|
77
|
+
log.info(' Research cached to .forge-research/');
|
|
78
|
+
}
|
|
79
|
+
catch { /* cache failure is not critical */ }
|
|
80
|
+
log.success(`DESIGN.md created for ${brief.companyName}`);
|
|
81
|
+
log.info(` Quality: ${design.qualityScore.total}/100`);
|
|
82
|
+
if (design.qualityScore.total < 60) {
|
|
83
|
+
log.warn('Quality is below 60. Consider providing a website URL (--url) or competitor URLs (--competitors) for better results.');
|
|
84
|
+
}
|
|
85
|
+
log.info('');
|
|
86
|
+
log.info('Next steps:');
|
|
87
|
+
log.info(' 1. Review DESIGN.md and adjust colors/fonts if needed');
|
|
88
|
+
log.info(' 2. Run `forge generate` to create your first screen');
|
|
89
|
+
log.info(' 3. Or use `/forge-generate` in Claude Code');
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/commands/discover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { log } from '../utils/logger.js';
|
|
3
|
+
import { validatePrompt } from '../utils/validators.js';
|
|
4
|
+
import { canGenerate, getQuotaStatus } from '../utils/quota.js';
|
|
5
|
+
import { incrementQuota } from '../utils/config.js';
|
|
6
|
+
import { StitchMcpClient } from '../mcp/client.js';
|
|
7
|
+
export async function runGenerate(description, opts) {
|
|
8
|
+
const model = opts.model === 'pro' ? 'GEMINI_3_PRO' : 'GEMINI_2_5_FLASH';
|
|
9
|
+
// Check quota
|
|
10
|
+
if (!canGenerate(model)) {
|
|
11
|
+
const status = getQuotaStatus();
|
|
12
|
+
log.error(`No ${model} generations remaining. Resets ${status.resetDate}.`);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
// Check for DESIGN.md
|
|
16
|
+
const hasDesignMd = existsSync('DESIGN.md');
|
|
17
|
+
if (!hasDesignMd) {
|
|
18
|
+
log.warn('No DESIGN.md found. Screens may be inconsistent. Run `forge design` first.');
|
|
19
|
+
}
|
|
20
|
+
// Build prompt
|
|
21
|
+
// For CLI usage, the description IS the prompt
|
|
22
|
+
// For Claude Code slash command, a structured ScreenSpec is built
|
|
23
|
+
const prompt = description;
|
|
24
|
+
// Validate
|
|
25
|
+
const validation = validatePrompt(prompt);
|
|
26
|
+
if (!validation.valid) {
|
|
27
|
+
for (const error of validation.errors) {
|
|
28
|
+
log.error(error);
|
|
29
|
+
}
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
// Get project ID
|
|
33
|
+
let client;
|
|
34
|
+
try {
|
|
35
|
+
client = new StitchMcpClient();
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
log.error(err instanceof Error ? err.message : 'Failed to initialize Stitch client.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
let projectId = opts.project;
|
|
42
|
+
if (!projectId) {
|
|
43
|
+
log.info('No project ID specified. Listing projects...');
|
|
44
|
+
let projects;
|
|
45
|
+
try {
|
|
46
|
+
projects = await client.listProjects();
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
log.error(err instanceof Error ? err.message : 'Failed to list projects.');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
if (projects.length === 0) {
|
|
53
|
+
log.error('No Stitch projects found. Create one at stitch.withgoogle.com first.');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
if (projects.length === 1) {
|
|
57
|
+
projectId = projects[0].id;
|
|
58
|
+
log.info(`Using project: ${projects[0].name} (${projectId})`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
log.info('Multiple projects found:');
|
|
62
|
+
projects.forEach((p, i) => log.info(` ${i + 1}. ${p.name} (${p.id})`));
|
|
63
|
+
const rl = await import('node:readline');
|
|
64
|
+
const iface = rl.createInterface({ input: process.stdin, output: process.stderr });
|
|
65
|
+
const answer = await new Promise(resolve => {
|
|
66
|
+
iface.question(`Select project (1-${projects.length}): `, resolve);
|
|
67
|
+
});
|
|
68
|
+
iface.close();
|
|
69
|
+
const idx = parseInt(answer) - 1;
|
|
70
|
+
if (idx < 0 || idx >= projects.length) {
|
|
71
|
+
log.error('Invalid selection.');
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
projectId = projects[idx].id;
|
|
75
|
+
log.info(`Using project: ${projects[idx].name} (${projectId})`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Generate
|
|
79
|
+
try {
|
|
80
|
+
log.step(1, 3, `Sending prompt to Stitch (${model})...`);
|
|
81
|
+
const result = await client.generateScreen(projectId, prompt, model);
|
|
82
|
+
log.step(2, 3, 'Retrieving screen code...');
|
|
83
|
+
const html = await client.getScreenCode(projectId, result.screenId, result.htmlCodeUrl);
|
|
84
|
+
log.step(3, 3, 'Saving...');
|
|
85
|
+
if (!existsSync('screens'))
|
|
86
|
+
mkdirSync('screens');
|
|
87
|
+
const filename = `screens/${result.name || result.screenId}.html`;
|
|
88
|
+
writeFileSync(filename, html);
|
|
89
|
+
// Update quota
|
|
90
|
+
incrementQuota(model);
|
|
91
|
+
const status = getQuotaStatus();
|
|
92
|
+
log.success(`Screen saved: ${filename}`);
|
|
93
|
+
log.quota(model, model === 'GEMINI_2_5_FLASH' ? status.flash.used : status.pro.used, model === 'GEMINI_2_5_FLASH' ? status.flash.limit : status.pro.limit);
|
|
94
|
+
if (opts.preview) {
|
|
95
|
+
const { openInBrowser } = await import('../utils/preview.js');
|
|
96
|
+
await openInBrowser(filename);
|
|
97
|
+
log.info('Preview opened in browser.');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
log.error(err instanceof Error ? err.message : 'Generation failed.');
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runInit(): Promise<void>;
|