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,99 @@
|
|
|
1
|
+
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { log } from '../utils/logger.js';
|
|
3
|
+
import { saveConfig, getConfigPath } from '../utils/config.js';
|
|
4
|
+
export async function runInit() {
|
|
5
|
+
log.info('Initializing Stitch Forge project...');
|
|
6
|
+
log.info('');
|
|
7
|
+
// Step 1: API Key
|
|
8
|
+
const apiKey = process.env.STITCH_API_KEY;
|
|
9
|
+
if (apiKey) {
|
|
10
|
+
log.success('API key found in environment.');
|
|
11
|
+
// Validate API key with a test call
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch('https://stitch.googleapis.com/mcp', {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
'X-Goog-Api-Key': apiKey,
|
|
18
|
+
},
|
|
19
|
+
body: JSON.stringify({ method: 'tools/call', params: { name: 'list_projects', arguments: {} } }),
|
|
20
|
+
});
|
|
21
|
+
if (response.ok) {
|
|
22
|
+
log.success('API key verified — connection to Stitch works!');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
log.warn('API key set but connection test failed. It may still work with MCP proxy.');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
log.warn('Could not reach Stitch API directly. This is fine if using MCP proxy.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
log.warn('No API key found. You need one to generate screens.');
|
|
34
|
+
log.info('');
|
|
35
|
+
log.info('How to get your API key:');
|
|
36
|
+
log.info(' 1. Go to stitch.withgoogle.com');
|
|
37
|
+
log.info(' 2. Open Settings (gear icon)');
|
|
38
|
+
log.info(' 3. Copy your API Key');
|
|
39
|
+
log.info(' 4. Add it to your .env file: STITCH_API_KEY=your-key-here');
|
|
40
|
+
log.info('');
|
|
41
|
+
}
|
|
42
|
+
// Step 2: Create config
|
|
43
|
+
if (existsSync(getConfigPath())) {
|
|
44
|
+
log.warn('.forgerc.json already exists. Keeping current config.');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const config = {
|
|
48
|
+
apiKey: apiKey || undefined,
|
|
49
|
+
defaultModel: 'GEMINI_2_5_FLASH',
|
|
50
|
+
framework: 'static',
|
|
51
|
+
screens: [],
|
|
52
|
+
quota: {
|
|
53
|
+
flashUsed: 0,
|
|
54
|
+
proUsed: 0,
|
|
55
|
+
resetDate: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 1)
|
|
56
|
+
.toISOString().split('T')[0],
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
saveConfig(config);
|
|
60
|
+
log.success('Created .forgerc.json');
|
|
61
|
+
log.info('Default build framework: static (change with --framework or in .forgerc.json)');
|
|
62
|
+
}
|
|
63
|
+
// Step 3: Create .env if missing
|
|
64
|
+
if (!existsSync('.env') && !apiKey) {
|
|
65
|
+
writeFileSync('.env', 'STITCH_API_KEY=\nGOOGLE_CLOUD_PROJECT=\n');
|
|
66
|
+
log.success('Created .env — add your API key there.');
|
|
67
|
+
}
|
|
68
|
+
// Step 4: Create screens directory
|
|
69
|
+
if (!existsSync('screens')) {
|
|
70
|
+
mkdirSync('screens');
|
|
71
|
+
log.success('Created screens/ directory');
|
|
72
|
+
}
|
|
73
|
+
// Step 5: Create .mcp.json for Claude Code if missing
|
|
74
|
+
if (!existsSync('.mcp.json')) {
|
|
75
|
+
const mcpConfig = {
|
|
76
|
+
mcpServers: {
|
|
77
|
+
stitch: {
|
|
78
|
+
command: 'npx',
|
|
79
|
+
args: ['@_davideast/stitch-mcp', 'proxy'],
|
|
80
|
+
env: { STITCH_API_KEY: '${STITCH_API_KEY}' },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
writeFileSync('.mcp.json', JSON.stringify(mcpConfig, null, 2) + '\n');
|
|
85
|
+
log.success('Created .mcp.json for Claude Code integration.');
|
|
86
|
+
}
|
|
87
|
+
// Next steps
|
|
88
|
+
log.info('');
|
|
89
|
+
log.success('Project initialized!');
|
|
90
|
+
log.info('');
|
|
91
|
+
log.info('Next steps:');
|
|
92
|
+
log.info(' 1. forge design "Company, Industry, Audience, Style" — Create your design system');
|
|
93
|
+
log.info(' 2. forge generate "A landing page for..." — Generate a screen');
|
|
94
|
+
log.info(' 3. forge build --auto — Build your site');
|
|
95
|
+
log.info('');
|
|
96
|
+
log.info('Or run `forge workflow` to see guided step-by-step workflows.');
|
|
97
|
+
log.info('Or run `forge tui` for the interactive terminal interface.');
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { log } from '../utils/logger.js';
|
|
2
|
+
import { openInBrowser, listScreenFiles, resolveScreenPath, openAllScreens } from '../utils/preview.js';
|
|
3
|
+
export async function runPreview(screenName, opts = {}) {
|
|
4
|
+
if (opts.all) {
|
|
5
|
+
const files = listScreenFiles();
|
|
6
|
+
if (files.length === 0) {
|
|
7
|
+
log.error('No screens found in screens/. Run `forge generate` first.');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
await openAllScreens();
|
|
11
|
+
log.success(`Opened ${files.length} screens in browser.`);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (screenName) {
|
|
15
|
+
const path = resolveScreenPath(screenName);
|
|
16
|
+
if (!path) {
|
|
17
|
+
log.error(`Screen not found: ${screenName}`);
|
|
18
|
+
const available = listScreenFiles();
|
|
19
|
+
if (available.length > 0) {
|
|
20
|
+
log.info('Available screens:');
|
|
21
|
+
available.forEach(s => log.info(` ${s}`));
|
|
22
|
+
}
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
await openInBrowser(path);
|
|
26
|
+
log.success(`Opened ${screenName} in browser.`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// No arguments: list and let user pick
|
|
30
|
+
const files = listScreenFiles();
|
|
31
|
+
if (files.length === 0) {
|
|
32
|
+
log.error('No screens found in screens/. Run `forge generate` first.');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
log.info('Available screens:');
|
|
36
|
+
files.forEach((s, i) => log.info(` ${i + 1}. ${s}`));
|
|
37
|
+
log.info('');
|
|
38
|
+
log.info('Usage: forge preview <screen-name>');
|
|
39
|
+
log.info(' forge preview --all');
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAMxG,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAmB,EAAE,OAAuB,EAAE;IAC7E,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,cAAc,EAAE,CAAC;QACvB,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,CAAC,MAAM,sBAAsB,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,GAAG,CAAC,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;YAC7C,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;YACpC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;gBAC/B,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;QAC1B,GAAG,CAAC,OAAO,CAAC,UAAU,UAAU,cAAc,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,GAAG,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IAC/C,GAAG,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runResearch(topic?: string): Promise<void>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { log } from '../utils/logger.js';
|
|
2
|
+
import { crawlSources } from '../research/crawler.js';
|
|
3
|
+
import { diffAgainstKnownState } from '../research/differ.js';
|
|
4
|
+
import { getKnownState, updateKnownState, isStale, getLastUpdated } from '../research/updater.js';
|
|
5
|
+
export async function runResearch(topic) {
|
|
6
|
+
const lastUpdated = getLastUpdated();
|
|
7
|
+
log.info(`Knowledge base last updated: ${lastUpdated.toISOString().split('T')[0]}`);
|
|
8
|
+
if (isStale()) {
|
|
9
|
+
log.warn('Knowledge base is over 30 days old. Running full update...');
|
|
10
|
+
}
|
|
11
|
+
log.step(1, 3, 'Crawling Stitch documentation sources...');
|
|
12
|
+
const crawlResults = await crawlSources();
|
|
13
|
+
const successCount = crawlResults.filter(r => !r.content.startsWith('[')).length;
|
|
14
|
+
const failCount = crawlResults.length - successCount;
|
|
15
|
+
log.info(` Fetched ${successCount} sources${failCount > 0 ? `, ${failCount} failed` : ''}`);
|
|
16
|
+
log.step(2, 3, 'Comparing against known state...');
|
|
17
|
+
const knownState = getKnownState();
|
|
18
|
+
const diff = diffAgainstKnownState(crawlResults, knownState);
|
|
19
|
+
if (!diff.hasChanges) {
|
|
20
|
+
log.success('No changes detected. Knowledge base is current.');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
log.step(3, 3, `Found ${diff.changes.length} change(s). Updating...`);
|
|
24
|
+
for (const change of diff.changes) {
|
|
25
|
+
const icon = change.severity === 'breaking' ? '🔴' : change.severity === 'warning' ? '🟡' : '🟢';
|
|
26
|
+
log.info(` ${icon} [${change.category}] ${change.description}`);
|
|
27
|
+
}
|
|
28
|
+
updateKnownState(diff.changes);
|
|
29
|
+
log.success(`Knowledge base updated. ${diff.changes.length} change(s) recorded.`);
|
|
30
|
+
const breaking = diff.changes.filter(c => c.severity === 'breaking');
|
|
31
|
+
if (breaking.length > 0) {
|
|
32
|
+
log.warn('BREAKING CHANGES detected. Review and update framework accordingly:');
|
|
33
|
+
for (const b of breaking) {
|
|
34
|
+
log.warn(` → ${b.description}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=research.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/commands/research.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAElG,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAc;IAC9C,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,GAAG,CAAC,IAAI,CAAC,gCAAgC,WAAW,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEpF,IAAI,OAAO,EAAE,EAAE,CAAC;QACd,GAAG,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;IACzE,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,0CAA0C,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,MAAM,YAAY,EAAE,CAAC;IAE1C,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IACjF,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC;IACrD,GAAG,CAAC,IAAI,CAAC,aAAa,YAAY,WAAW,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE7F,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,kCAAkC,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,qBAAqB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAE7D,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACrB,GAAG,CAAC,OAAO,CAAC,iDAAiD,CAAC,CAAC;QAC/D,OAAO;IACT,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,IAAI,CAAC,OAAO,CAAC,MAAM,yBAAyB,CAAC,CAAC;IAEtE,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACjG,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE/B,GAAG,CAAC,OAAO,CAAC,2BAA2B,IAAI,CAAC,OAAO,CAAC,MAAM,sBAAsB,CAAC,CAAC;IAElF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IACrE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QAChF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSync(projectId?: string): Promise<void>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { log } from '../utils/logger.js';
|
|
3
|
+
import { getConfig, updateConfig } from '../utils/config.js';
|
|
4
|
+
import { StitchMcpClient } from '../mcp/client.js';
|
|
5
|
+
export async function runSync(projectId) {
|
|
6
|
+
const config = getConfig();
|
|
7
|
+
const id = projectId || config.projectId;
|
|
8
|
+
let client;
|
|
9
|
+
try {
|
|
10
|
+
client = new StitchMcpClient();
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
log.error(err instanceof Error ? err.message : 'Failed to initialize Stitch client.');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
if (!id) {
|
|
17
|
+
log.info('No project ID. Listing available projects...');
|
|
18
|
+
const projects = await client.listProjects();
|
|
19
|
+
if (projects.length === 0) {
|
|
20
|
+
log.error('No projects found.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
for (const p of projects) {
|
|
24
|
+
log.info(` ${p.id} — ${p.name}`);
|
|
25
|
+
}
|
|
26
|
+
log.info('Run: forge sync <project-id>');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!existsSync('screens'))
|
|
30
|
+
mkdirSync('screens');
|
|
31
|
+
log.step(1, 2, 'Fetching screens...');
|
|
32
|
+
const screens = await client.listScreens(id);
|
|
33
|
+
log.step(2, 2, `Downloading ${screens.length} screens...`);
|
|
34
|
+
const screenRecords = [];
|
|
35
|
+
for (const screen of screens) {
|
|
36
|
+
const html = await client.getScreenCode(id, screen.id);
|
|
37
|
+
const filename = `screens/${screen.name || screen.id}.html`;
|
|
38
|
+
writeFileSync(filename, html);
|
|
39
|
+
log.info(` ${filename}`);
|
|
40
|
+
screenRecords.push({
|
|
41
|
+
id: screen.id,
|
|
42
|
+
name: screen.name,
|
|
43
|
+
lastSynced: new Date().toISOString(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
updateConfig({
|
|
47
|
+
projectId: id,
|
|
48
|
+
screens: screenRecords,
|
|
49
|
+
lastSync: new Date().toISOString(),
|
|
50
|
+
});
|
|
51
|
+
log.success(`Synced ${screens.length} screens from project.`);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,SAAkB;IAC9C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,GAAG,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC;IACzC,IAAI,MAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,GAAG,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;QAC7C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEjD,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,qBAAqB,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAE7C,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,eAAe,OAAO,CAAC,MAAM,aAAa,CAAC,CAAC;IAC3D,MAAM,aAAa,GAAG,EAAE,CAAC;IAEzB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,WAAW,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,OAAO,CAAC;QAC5D,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;QAE1B,aAAa,CAAC,IAAI,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,CAAC,CAAC;IACL,CAAC;IAED,YAAY,CAAC;QACX,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,aAAa;QACtB,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACnC,CAAC,CAAC;IAEH,GAAG,CAAC,OAAO,CAAC,UAAU,OAAO,CAAC,MAAM,wBAAwB,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runWorkflow(type?: string): Promise<void>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { log } from '../utils/logger.js';
|
|
2
|
+
import { getWorkflow } from '../templates/workflows.js';
|
|
3
|
+
export async function runWorkflow(type) {
|
|
4
|
+
if (!type || !['redesign', 'new-app'].includes(type)) {
|
|
5
|
+
log.info('Available workflows:');
|
|
6
|
+
log.info('');
|
|
7
|
+
log.info(' redesign — Redesign an existing site with a fresh design system');
|
|
8
|
+
log.info(' Start from DESIGN.md, then generate screens one by one.');
|
|
9
|
+
log.info('');
|
|
10
|
+
log.info(' new-app — Build a new app from scratch');
|
|
11
|
+
log.info(' Start with brainstorming, then refine and build.');
|
|
12
|
+
log.info('');
|
|
13
|
+
log.info('Usage: forge workflow <redesign|new-app>');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const steps = getWorkflow(type);
|
|
17
|
+
const title = type === 'redesign' ? 'Website Redesign' : 'New App from Scratch';
|
|
18
|
+
log.info(`Workflow: ${title}`);
|
|
19
|
+
log.info('');
|
|
20
|
+
log.info('Follow these steps in order:');
|
|
21
|
+
log.info('');
|
|
22
|
+
for (let i = 0; i < steps.length; i++) {
|
|
23
|
+
const step = steps[i];
|
|
24
|
+
const num = `${i + 1}`.padStart(2);
|
|
25
|
+
const isManual = step.command === 'manual';
|
|
26
|
+
const tag = isManual ? ' (manual step)' : '';
|
|
27
|
+
const cmd = isManual ? '' : ` Command: ${step.command}`;
|
|
28
|
+
log.info(` ${num}. ${step.description}${tag}`);
|
|
29
|
+
if (cmd)
|
|
30
|
+
log.info(` ${cmd}`);
|
|
31
|
+
if (step.dependsOn) {
|
|
32
|
+
log.info(` (after: ${step.dependsOn})`);
|
|
33
|
+
}
|
|
34
|
+
log.info('');
|
|
35
|
+
}
|
|
36
|
+
log.info('Tip: Use the TUI (`forge tui`) for a guided interactive experience.');
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/commands/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAqB,MAAM,2BAA2B,CAAC;AAE3E,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAa;IAC7C,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QAChF,GAAG,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;QACnF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACxD,GAAG,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;QAC5E,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,IAA8B,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,sBAAsB,CAAC;IAEhF,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC;IAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACzC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC;QAC3C,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC;QAEzD,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,CAAC,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC;QAChD,IAAI,GAAG;YAAE,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,GAAG,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;AAClF,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
const program = new Command();
|
|
4
|
+
program
|
|
5
|
+
.name('forge')
|
|
6
|
+
.description('Stitch Forge — CLI framework for automating web design with Google Stitch')
|
|
7
|
+
.version('0.2.0');
|
|
8
|
+
program
|
|
9
|
+
.command('init')
|
|
10
|
+
.description('Setup project: authenticate and create .forgerc.json')
|
|
11
|
+
.action(async () => {
|
|
12
|
+
const { runInit } = await import('./commands/init.js');
|
|
13
|
+
await runInit();
|
|
14
|
+
});
|
|
15
|
+
program
|
|
16
|
+
.command('design')
|
|
17
|
+
.description('Generate a DESIGN.md from a brand brief')
|
|
18
|
+
.argument('[brief...]', 'Brand brief description')
|
|
19
|
+
.option('--force', 'Overwrite without confirmation')
|
|
20
|
+
.option('--research', 'Enable research-driven generation (same as forge discover)')
|
|
21
|
+
.action(async (brief, opts) => {
|
|
22
|
+
if (opts.research) {
|
|
23
|
+
const { runDiscover } = await import('./commands/discover.js');
|
|
24
|
+
await runDiscover(brief.join(' '), { force: opts.force });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const { runDesign } = await import('./commands/design.js');
|
|
28
|
+
await runDesign(brief.join(' '), opts);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
program
|
|
32
|
+
.command('discover')
|
|
33
|
+
.description('Research a business and generate a tailored DESIGN.md')
|
|
34
|
+
.argument('[brief...]', 'Business brief (name, industry, audience, aesthetic)')
|
|
35
|
+
.option('--force', 'Overwrite DESIGN.md without confirmation')
|
|
36
|
+
.option('-u, --url <url>', 'Business website URL')
|
|
37
|
+
.option('--competitors <urls>', 'Comma-separated competitor URLs')
|
|
38
|
+
.option('--locale <locale>', 'Target locale (e.g., es-MX)')
|
|
39
|
+
.option('--no-research', 'Skip research, use presets only')
|
|
40
|
+
.action(async (brief, opts) => {
|
|
41
|
+
const { runDiscover } = await import('./commands/discover.js');
|
|
42
|
+
await runDiscover(brief.join(' '), opts);
|
|
43
|
+
});
|
|
44
|
+
program
|
|
45
|
+
.command('generate')
|
|
46
|
+
.description('Generate a screen in Stitch from a description')
|
|
47
|
+
.argument('<description...>', 'Screen description')
|
|
48
|
+
.option('-m, --model <model>', 'Model to use (flash|pro)', 'flash')
|
|
49
|
+
.option('-p, --project <id>', 'Stitch project ID')
|
|
50
|
+
.option('--preview', 'Open screen in browser after generating')
|
|
51
|
+
.action(async (description, opts) => {
|
|
52
|
+
const { runGenerate } = await import('./commands/generate.js');
|
|
53
|
+
await runGenerate(description.join(' '), opts);
|
|
54
|
+
});
|
|
55
|
+
program
|
|
56
|
+
.command('build')
|
|
57
|
+
.description('Build a deployable site from Stitch screens')
|
|
58
|
+
.option('-p, --project <id>', 'Stitch project ID')
|
|
59
|
+
.option('--auto', 'Auto-map screen names to routes')
|
|
60
|
+
.option('-f, --framework <type>', 'Output framework: static, astro, nextjs')
|
|
61
|
+
.action(async (opts) => {
|
|
62
|
+
const { runBuild } = await import('./commands/build.js');
|
|
63
|
+
await runBuild(opts);
|
|
64
|
+
});
|
|
65
|
+
program
|
|
66
|
+
.command('preview')
|
|
67
|
+
.description('Preview generated screens in the browser')
|
|
68
|
+
.argument('[screen-name]', 'Screen to preview')
|
|
69
|
+
.option('-a, --all', 'Open all screens')
|
|
70
|
+
.action(async (screenName, opts) => {
|
|
71
|
+
const { runPreview } = await import('./commands/preview.js');
|
|
72
|
+
await runPreview(screenName, opts || {});
|
|
73
|
+
});
|
|
74
|
+
program
|
|
75
|
+
.command('sync')
|
|
76
|
+
.description('Sync local files with Stitch project')
|
|
77
|
+
.argument('[projectId]', 'Stitch project ID')
|
|
78
|
+
.action(async (projectId) => {
|
|
79
|
+
const { runSync } = await import('./commands/sync.js');
|
|
80
|
+
await runSync(projectId);
|
|
81
|
+
});
|
|
82
|
+
program
|
|
83
|
+
.command('research')
|
|
84
|
+
.description('Check for Stitch updates and refresh knowledge base')
|
|
85
|
+
.option('-t, --topic <topic>', 'Specific topic to research')
|
|
86
|
+
.action(async (opts) => {
|
|
87
|
+
const { runResearch } = await import('./commands/research.js');
|
|
88
|
+
await runResearch(opts.topic);
|
|
89
|
+
});
|
|
90
|
+
program
|
|
91
|
+
.command('tui')
|
|
92
|
+
.description('Launch interactive terminal UI')
|
|
93
|
+
.action(async () => {
|
|
94
|
+
const { renderApp } = await import('./tui/App.js');
|
|
95
|
+
renderApp();
|
|
96
|
+
});
|
|
97
|
+
program
|
|
98
|
+
.command('workflow')
|
|
99
|
+
.description('Show guided workflow steps for common design tasks')
|
|
100
|
+
.argument('[type]', 'Workflow type: redesign or new-app')
|
|
101
|
+
.action(async (type) => {
|
|
102
|
+
const { runWorkflow } = await import('./commands/workflow.js');
|
|
103
|
+
await runWorkflow(type);
|
|
104
|
+
});
|
|
105
|
+
program
|
|
106
|
+
.command('quota')
|
|
107
|
+
.description('Show current generation quota usage')
|
|
108
|
+
.action(async () => {
|
|
109
|
+
const { formatQuotaDisplay } = await import('./utils/quota.js');
|
|
110
|
+
console.log(formatQuotaDisplay());
|
|
111
|
+
});
|
|
112
|
+
program.parse();
|
|
113
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AuthMethod = 'api_key' | 'gcloud_oauth' | 'none';
|
|
2
|
+
export interface AuthConfig {
|
|
3
|
+
method: AuthMethod;
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve authentication for Stitch MCP.
|
|
9
|
+
* Priority: env var > .env file > .forgerc.json > none
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveAuth(): AuthConfig;
|
|
12
|
+
/**
|
|
13
|
+
* Check if gcloud CLI is available for OAuth fallback.
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkGcloudAvailable(): Promise<boolean>;
|
package/dist/mcp/auth.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve authentication for Stitch MCP.
|
|
5
|
+
* Priority: env var > .env file > .forgerc.json > none
|
|
6
|
+
*/
|
|
7
|
+
export function resolveAuth() {
|
|
8
|
+
// 1. Environment variable
|
|
9
|
+
if (process.env.STITCH_API_KEY) {
|
|
10
|
+
return {
|
|
11
|
+
method: 'api_key',
|
|
12
|
+
apiKey: process.env.STITCH_API_KEY,
|
|
13
|
+
projectId: process.env.GOOGLE_CLOUD_PROJECT,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
// 2. .env file
|
|
17
|
+
const envPath = join(process.cwd(), '.env');
|
|
18
|
+
if (existsSync(envPath)) {
|
|
19
|
+
const envContent = readFileSync(envPath, 'utf-8');
|
|
20
|
+
const apiKeyMatch = envContent.match(/^STITCH_API_KEY=(.+)$/m);
|
|
21
|
+
const projectMatch = envContent.match(/^GOOGLE_CLOUD_PROJECT=(.+)$/m);
|
|
22
|
+
if (apiKeyMatch?.[1]?.trim()) {
|
|
23
|
+
return {
|
|
24
|
+
method: 'api_key',
|
|
25
|
+
apiKey: apiKeyMatch[1].trim(),
|
|
26
|
+
projectId: projectMatch?.[1]?.trim(),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// 3. .forgerc.json
|
|
31
|
+
const rcPath = join(process.cwd(), '.forgerc.json');
|
|
32
|
+
if (existsSync(rcPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const rc = JSON.parse(readFileSync(rcPath, 'utf-8'));
|
|
35
|
+
if (rc.apiKey) {
|
|
36
|
+
return { method: 'api_key', apiKey: rc.apiKey, projectId: rc.projectId };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch { /* ignore parse errors */ }
|
|
40
|
+
}
|
|
41
|
+
return { method: 'none' };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if gcloud CLI is available for OAuth fallback.
|
|
45
|
+
*/
|
|
46
|
+
export async function checkGcloudAvailable() {
|
|
47
|
+
try {
|
|
48
|
+
const { execSync } = await import('node:child_process');
|
|
49
|
+
execSync('gcloud --version', { stdio: 'ignore' });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/mcp/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,0BAA0B;IAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;YAClC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;SAC5C,CAAC;IACJ,CAAC;IAED,eAAe;IACf,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACtE,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;YAC7B,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBAC7B,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE;aACrC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YACrD,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC;YAC3E,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACxD,QAAQ,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Client wrapper for Stitch tools.
|
|
3
|
+
*
|
|
4
|
+
* When running inside Claude Code with the Stitch MCP server configured,
|
|
5
|
+
* tool calls are handled automatically by the MCP protocol.
|
|
6
|
+
*
|
|
7
|
+
* This module provides typed wrappers for standalone CLI usage
|
|
8
|
+
* (outside Claude Code) via direct HTTP calls to the Stitch MCP endpoint.
|
|
9
|
+
*/
|
|
10
|
+
export interface StitchProject {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
screenCount: number;
|
|
15
|
+
}
|
|
16
|
+
export interface StitchScreen {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
prompt: string;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
}
|
|
22
|
+
export interface GenerateScreenResult {
|
|
23
|
+
screenId: string;
|
|
24
|
+
projectId: string;
|
|
25
|
+
name: string;
|
|
26
|
+
htmlCodeUrl?: string;
|
|
27
|
+
screenshotUrl?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface BuildSiteRoute {
|
|
30
|
+
screenId: string;
|
|
31
|
+
route: string;
|
|
32
|
+
}
|
|
33
|
+
export interface BuildSiteResult {
|
|
34
|
+
pages: Array<{
|
|
35
|
+
route: string;
|
|
36
|
+
html: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Direct HTTP client for Stitch MCP endpoint.
|
|
41
|
+
* Used when running as standalone CLI (not inside Claude Code).
|
|
42
|
+
*/
|
|
43
|
+
export declare class StitchMcpClient {
|
|
44
|
+
private endpoint;
|
|
45
|
+
private apiKey;
|
|
46
|
+
constructor(apiKey?: string, endpoint?: string);
|
|
47
|
+
private callTool;
|
|
48
|
+
private isRetryable;
|
|
49
|
+
private formatError;
|
|
50
|
+
listProjects(): Promise<StitchProject[]>;
|
|
51
|
+
getProject(projectId: string): Promise<StitchProject>;
|
|
52
|
+
listScreens(projectId: string): Promise<StitchScreen[]>;
|
|
53
|
+
generateScreen(projectId: string, prompt: string, modelId?: string): Promise<GenerateScreenResult>;
|
|
54
|
+
/** Extract screen data directly from generate_screen_from_text response */
|
|
55
|
+
private extractScreenFromResponse;
|
|
56
|
+
getScreenCode(projectId: string, screenId: string, htmlCodeUrl?: string): Promise<string>;
|
|
57
|
+
getScreenImage(projectId: string, screenId: string): Promise<string>;
|
|
58
|
+
buildSite(projectId: string, routes: BuildSiteRoute[]): Promise<BuildSiteResult>;
|
|
59
|
+
/** Extract numeric ID from resource name like "projects/123" or "screens/456" */
|
|
60
|
+
private extractId;
|
|
61
|
+
/** Ensure value is a resource name; if it's just an ID, prepend the prefix */
|
|
62
|
+
private toResourceName;
|
|
63
|
+
/** Map internal model names to Stitch API model IDs */
|
|
64
|
+
private mapModelId;
|
|
65
|
+
}
|