mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
template work
This commit is contained in:
parent
5e590aa16a
commit
a4a852ace0
@ -214,6 +214,7 @@ export const ChatImpl = memo(
|
||||
});
|
||||
useEffect(() => {
|
||||
const prompt = searchParams.get('prompt');
|
||||
const templateUrl = searchParams.get('template');
|
||||
|
||||
// console.log(prompt, searchParams, model, provider);
|
||||
|
||||
@ -229,9 +230,47 @@ export const ChatImpl = memo(
|
||||
},
|
||||
] as any, // Type assertion to bypass compiler check
|
||||
});
|
||||
} else if (templateUrl) {
|
||||
setSearchParams({});
|
||||
runAnimation();
|
||||
|
||||
// Process template URL
|
||||
processTemplateUrl(templateUrl);
|
||||
}
|
||||
}, [model, provider, searchParams]);
|
||||
|
||||
const processTemplateUrl = async (templateUrl: string) => {
|
||||
try {
|
||||
setFakeLoading(true);
|
||||
|
||||
const { getTemplateFromUrl } = await import('~/utils/selectStarterTemplate');
|
||||
const result = await getTemplateFromUrl(templateUrl);
|
||||
|
||||
if (result) {
|
||||
const { assistantMessage, userMessage } = result;
|
||||
setMessages([
|
||||
{
|
||||
id: `1-${new Date().getTime()}`,
|
||||
role: 'assistant',
|
||||
content: assistantMessage,
|
||||
},
|
||||
{
|
||||
id: `2-${new Date().getTime()}`,
|
||||
role: 'user',
|
||||
content: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${userMessage}`,
|
||||
annotations: ['hidden'],
|
||||
},
|
||||
]);
|
||||
reload();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing template URL:', error);
|
||||
toast.error('Failed to load template from URL: ' + (error instanceof Error ? error.message : 'Unknown error'));
|
||||
} finally {
|
||||
setFakeLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const { enhancingPrompt, promptEnhanced, enhancePrompt, resetEnhancer } = usePromptEnhancer();
|
||||
const { parsedMessages, parseMessages } = useMessageParser();
|
||||
|
||||
|
@ -129,4 +129,12 @@ export const STARTER_TEMPLATES: Template[] = [
|
||||
tags: ['angular', 'typescript', 'frontend', 'spa'],
|
||||
icon: 'i-bolt:angular',
|
||||
},
|
||||
{
|
||||
name: 'Prometheus AI',
|
||||
label: 'Prometheus AI',
|
||||
description: 'Advanced AI-powered application template with modern tooling and best practices',
|
||||
githubRepo: 'Prometheus-AGS/prometheus-bolt-template',
|
||||
tags: ['ai', 'prometheus', 'typescript', 'modern', 'advanced'],
|
||||
icon: 'i-bolt:prometheus',
|
||||
},
|
||||
];
|
||||
|
@ -52,10 +52,11 @@ Response:
|
||||
|
||||
Instructions:
|
||||
1. For trivial tasks and simple scripts, always recommend the blank template
|
||||
2. For more complex projects, recommend templates from the provided list
|
||||
3. Follow the exact XML format
|
||||
4. Consider both technical requirements and tags
|
||||
5. If no perfect match exists, recommend the closest option
|
||||
2. For AI-related projects, chatbots, or advanced applications, prefer the Prometheus AI template
|
||||
3. For more complex projects, recommend templates from the provided list
|
||||
4. Follow the exact XML format
|
||||
5. Consider both technical requirements and tags
|
||||
6. If no perfect match exists, recommend the closest option
|
||||
|
||||
Important: Provide only the selection tags in your response, no additional text.
|
||||
MOST IMPORTANT: YOU DONT HAVE TIME TO THINK JUST START RESPONDING BASED ON HUNCH
|
||||
@ -101,11 +102,11 @@ export const selectStarterTemplate = async (options: { message: string; model: s
|
||||
if (selectedTemplate) {
|
||||
return selectedTemplate;
|
||||
} else {
|
||||
console.log('No template selected, using blank template');
|
||||
console.log('No template selected, using Prometheus AI template as default');
|
||||
|
||||
return {
|
||||
template: 'blank',
|
||||
title: '',
|
||||
template: 'Prometheus AI',
|
||||
title: 'AI-Powered Application',
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -251,3 +252,149 @@ IMPORTANT: Dont Forget to install the dependencies before running the app by usi
|
||||
userMessage,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse GitHub URL from template parameter and extract repo information
|
||||
*/
|
||||
const parseGitHubUrl = (templateUrl: string): string | null => {
|
||||
try {
|
||||
// Remove .git suffix if present
|
||||
const cleanUrl = templateUrl.replace(/\.git$/, '');
|
||||
|
||||
// Handle different GitHub URL formats
|
||||
const githubRegex = /(?:https?:\/\/)?(?:www\.)?github\.com\/([^\/]+\/[^\/]+)/;
|
||||
const match = cleanUrl.match(githubRegex);
|
||||
|
||||
if (match && match[1]) {
|
||||
return match[1]; // Returns "user/repo"
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Error parsing GitHub URL:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get template from URL and process it similar to existing template processing
|
||||
*/
|
||||
export async function getTemplateFromUrl(templateUrl: string, title?: string) {
|
||||
try {
|
||||
// Parse the GitHub URL to get repo name
|
||||
const repoName = parseGitHubUrl(templateUrl);
|
||||
|
||||
if (!repoName) {
|
||||
throw new Error('Invalid GitHub URL format. Please provide a valid GitHub repository URL.');
|
||||
}
|
||||
|
||||
// Fetch repository content using existing function
|
||||
const files = await getGitHubRepoContent(repoName);
|
||||
|
||||
let filteredFiles = files;
|
||||
|
||||
// Apply same filtering logic as existing template processing
|
||||
// Exclude .git files
|
||||
filteredFiles = filteredFiles.filter((x) => x.path.startsWith('.git') == false);
|
||||
|
||||
// Exclude .bolt files from main content
|
||||
filteredFiles = filteredFiles.filter((x) => x.path.startsWith('.bolt') == false);
|
||||
|
||||
// Check for ignore file in .bolt folder
|
||||
const templateIgnoreFile = files.find((x) => x.path.startsWith('.bolt') && x.name == 'ignore');
|
||||
|
||||
const filesToImport = {
|
||||
files: filteredFiles,
|
||||
ignoreFile: [] as typeof filteredFiles,
|
||||
};
|
||||
|
||||
if (templateIgnoreFile) {
|
||||
// Process files specified in ignore file
|
||||
const ignorepatterns = templateIgnoreFile.content.split('\n').map((x) => x.trim());
|
||||
const ig = ignore().add(ignorepatterns);
|
||||
|
||||
const ignoredFiles = filteredFiles.filter((x) => ig.ignores(x.path));
|
||||
|
||||
filesToImport.files = filteredFiles;
|
||||
filesToImport.ignoreFile = ignoredFiles;
|
||||
}
|
||||
|
||||
// Generate assistant message with template files
|
||||
const assistantMessage = `
|
||||
Bolt is importing your template from ${templateUrl}.
|
||||
<boltArtifact id="imported-template-files" title="${title || 'Import template files'}" type="bundled">
|
||||
${filesToImport.files
|
||||
.map(
|
||||
(file) =>
|
||||
`<boltAction type="file" filePath="${file.path}">
|
||||
${file.content}
|
||||
</boltAction>`,
|
||||
)
|
||||
.join('\n')}
|
||||
</boltArtifact>
|
||||
`;
|
||||
|
||||
let userMessage = ``;
|
||||
|
||||
// Check for template prompt file
|
||||
const templatePromptFile = files.filter((x) => x.path.startsWith('.bolt')).find((x) => x.name == 'prompt');
|
||||
|
||||
if (templatePromptFile) {
|
||||
userMessage = `
|
||||
TEMPLATE INSTRUCTIONS:
|
||||
${templatePromptFile.content}
|
||||
|
||||
---
|
||||
`;
|
||||
}
|
||||
|
||||
// Add ignore file instructions if present
|
||||
if (filesToImport.ignoreFile.length > 0) {
|
||||
userMessage =
|
||||
userMessage +
|
||||
`
|
||||
STRICT FILE ACCESS RULES - READ CAREFULLY:
|
||||
|
||||
The following files are READ-ONLY and must never be modified:
|
||||
${filesToImport.ignoreFile.map((file) => `- ${file.path}`).join('\n')}
|
||||
|
||||
Permitted actions:
|
||||
✓ Import these files as dependencies
|
||||
✓ Read from these files
|
||||
✓ Reference these files
|
||||
|
||||
Strictly forbidden actions:
|
||||
❌ Modify any content within these files
|
||||
❌ Delete these files
|
||||
❌ Rename these files
|
||||
❌ Move these files
|
||||
❌ Create new versions of these files
|
||||
❌ Suggest changes to these files
|
||||
|
||||
Any attempt to modify these protected files will result in immediate termination of the operation.
|
||||
|
||||
If you need to make changes to functionality, create new files instead of modifying the protected ones listed above.
|
||||
---
|
||||
`;
|
||||
}
|
||||
|
||||
userMessage += `
|
||||
---
|
||||
Template import from ${templateUrl} is complete. You can now use the imported files.
|
||||
Edit only the files that need to be changed, and you can create new files as needed.
|
||||
DO NOT EDIT/WRITE ANY FILES THAT ALREADY EXIST IN THE PROJECT AND DO NOT NEED TO BE MODIFIED
|
||||
---
|
||||
The template has been successfully imported. You can now work with the imported files.
|
||||
|
||||
IMPORTANT: Don't forget to install the dependencies before running the app by using \`npm install && npm run dev\`
|
||||
`;
|
||||
|
||||
return {
|
||||
assistantMessage,
|
||||
userMessage,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error processing template URL:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
appId: com.stackblitz.bolt.diy
|
||||
productName: Bolt Local
|
||||
appId: ai.prometheusags.bolt
|
||||
productName: Prometheus Bolt
|
||||
directories:
|
||||
buildResources: build
|
||||
output: dist
|
||||
@ -9,6 +9,7 @@ files:
|
||||
- node_modules/**/*
|
||||
- icons/**
|
||||
- electron-update.yml
|
||||
- .env
|
||||
extraMetadata:
|
||||
main: build/electron/main/index.mjs
|
||||
asarUnpack:
|
||||
|
@ -4,6 +4,7 @@ import electron, { app, BrowserWindow, ipcMain, protocol, session } from 'electr
|
||||
import log from 'electron-log';
|
||||
import path from 'node:path';
|
||||
import * as pkg from '../../package.json';
|
||||
import dotenv from 'dotenv';
|
||||
import { setupAutoUpdater } from './utils/auto-update';
|
||||
import { isDev, DEFAULT_PORT } from './utils/constants';
|
||||
import { initViteServer, viteServer } from './utils/vite-server';
|
||||
@ -15,7 +16,42 @@ import { reloadOnChange } from './utils/reload';
|
||||
|
||||
Object.assign(console, log.functions);
|
||||
|
||||
console.debug('main: import.meta.env:', import.meta.env);
|
||||
// Load environment variables from .env file
|
||||
let envPath = '';
|
||||
|
||||
try {
|
||||
// In development mode
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
if (isDev) {
|
||||
envPath = path.join(app.getAppPath(), '.env');
|
||||
|
||||
const result = dotenv.config({ path: envPath });
|
||||
|
||||
if (result.error) {
|
||||
console.log('Error loading .env file in development:', result.error.message);
|
||||
} else {
|
||||
console.log('Loaded environment variables from:', envPath);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* In production/packaged mode, environment variables should be baked into the build
|
||||
* or handled differently as .env files aren't typically accessible in packaged apps
|
||||
*/
|
||||
console.log('Running in production mode, using bundled environment variables');
|
||||
|
||||
/*
|
||||
* For critical environment variables that must be available in production,
|
||||
* you can set them directly here or read from a config file included in the package
|
||||
*/
|
||||
// process.env.CRITICAL_VARIABLE = 'some-value';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error setting up environment variables:', error);
|
||||
}
|
||||
|
||||
// Safely access import.meta.env if available
|
||||
console.debug('main: import.meta.env:', typeof import.meta !== 'undefined' ? import.meta.env : 'Not available');
|
||||
console.log('main: isDev:', isDev);
|
||||
console.log('NODE_ENV:', global.process.env.NODE_ENV);
|
||||
console.log('isPackaged:', app.isPackaged);
|
||||
@ -30,7 +66,9 @@ process.on('unhandledRejection', async (error) => {
|
||||
});
|
||||
|
||||
(() => {
|
||||
const root = global.process.env.APP_PATH_ROOT ?? import.meta.env.VITE_APP_PATH_ROOT;
|
||||
/* eslint-disable-next-line */
|
||||
const root = global.process.env.APP_PATH_ROOT ??
|
||||
(typeof import.meta !== 'undefined' ? import.meta.env.VITE_APP_PATH_ROOT : undefined);
|
||||
|
||||
if (root === undefined) {
|
||||
console.log('no given APP_PATH_ROOT or VITE_APP_PATH_ROOT. default path is used.');
|
||||
@ -82,7 +120,20 @@ declare global {
|
||||
|
||||
if (isDev) {
|
||||
console.log('Dev mode: forwarding to vite server');
|
||||
return await fetch(req);
|
||||
|
||||
try {
|
||||
const response = await fetch(req);
|
||||
return response;
|
||||
} catch (err) {
|
||||
console.error('Error forwarding to vite server:', err);
|
||||
return new Response(
|
||||
`Error forwarding request to vite server: ${err instanceof Error ? err.message : String(err)}`,
|
||||
{
|
||||
status: 500,
|
||||
headers: { 'content-type': 'text/plain' },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
req.headers.append('Referer', req.referrer);
|
||||
@ -189,7 +240,32 @@ declare global {
|
||||
|
||||
return win;
|
||||
})
|
||||
.then((win) => setupMenu(win));
|
||||
.then((win) => {
|
||||
/* eslint-disable-next-line */
|
||||
// Add navigationHistory to Electron's WebContents prototype if it doesn't exist
|
||||
const webContentsProto = Object.getPrototypeOf(win.webContents);
|
||||
|
||||
if (!('navigationHistory' in webContentsProto)) {
|
||||
Object.defineProperty(webContentsProto, 'navigationHistory', {
|
||||
get() {
|
||||
return {
|
||||
goBack: () => {
|
||||
if (this.canGoBack()) {
|
||||
this.goBack();
|
||||
}
|
||||
},
|
||||
goForward: () => {
|
||||
if (this.canGoForward()) {
|
||||
this.goForward();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return setupMenu(win);
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
|
@ -4,7 +4,6 @@
|
||||
"lib": ["ESNext"],
|
||||
"jsx": "preserve",
|
||||
"target": "ESNext",
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true,
|
||||
"useDefineForClassFields": true,
|
||||
|
||||
|
1
icons/prometheus.svg
Normal file
1
icons/prometheus.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28' fill='none'><path fill='#7B7B7B' d='M14 2.5c-1.2 0-2.3.6-3 1.5-.4.5-.6 1.1-.6 1.7 0 .3.1.6.2.9-.7-.3-1.5-.2-2.1.2-.8.5-1.2 1.4-.9 2.3.2.6.5 1.1 1 1.4-.5.3-.9.9-.9 1.6 0 1 .8 1.9 1.8 2v.1c0 1.2.9 2.2 2.2 2.2h.8c.3 1.4 1.5 2.5 3 2.5s2.7-1.1 3-2.5h.8c1.2 0 2.2-1 2.2-2.2v-.1c1-.1 1.8-.9 1.8-2 0-.7-.3-1.3-.9-1.6.5-.3.8-.8 1-1.4.3-.9-.1-1.8-.9-2.3-.6-.4-1.4-.5-2.1-.2.1-.3.2-.6.2-.9 0-.6-.2-1.2-.6-1.7-.7-.9-1.8-1.5-3-1.5z'/><path fill='#7B7B7B' d='M14 4.5c-.6 0-1.1.3-1.4.7-.2.2-.3.5-.3.8 0 .2 0 .3.1.4-.3-.1-.7-.1-1 .1-.4.2-.6.6-.4 1 .1.3.2.5.4.6-.2.1-.4.4-.4.7 0 .4.3.7.7.8v.1c0 .5.4.9.9.9h.3c.1.6.6 1 1.2 1s1.1-.4 1.2-1h.3c.5 0 .9-.4.9-.9v-.1c.4 0 .7-.3.7-.8 0-.3-.1-.5-.4-.7.2-.1.3-.3.4-.6.1-.4-.1-.8-.4-1-.3-.2-.6-.2-1-.1.1-.1.1-.2.1-.4 0-.3-.1-.6-.3-.8-.3-.4-.8-.7-1.4-.7z'/><path fill='#7B7B7B' d='M14 6.5c-.4 0-.7.2-.9.4-.1.1-.2.3-.2.5 0 .1 0 .2.1.3-.2-.1-.4-.1-.6.1-.2.1-.4.4-.3.6.1.2.1.3.3.4-.1.1-.2.2-.2.4 0 .3.2.5.5.5v.1c0 .3.3.6.6.6h.2c.1.4.4.7.8.7s.7-.3.8-.7h.2c.3 0 .6-.3.6-.6v-.1c.3 0 .5-.2.5-.5 0-.2-.1-.3-.2-.4.1-.1.2-.2.3-.4.1-.2-.1-.5-.3-.6-.2-.1-.4-.1-.6-.1.1-.1.1-.2.1-.3 0-.2-.1-.4-.2-.5-.2-.2-.5-.4-.9-.4z'/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
Loading…
Reference in New Issue
Block a user