template work

This commit is contained in:
Travis James 2025-06-09 07:26:04 -05:00
parent 5e590aa16a
commit a4a852ace0
7 changed files with 285 additions and 14 deletions

View File

@ -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();

View File

@ -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',
},
];

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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') {

View File

@ -4,7 +4,6 @@
"lib": ["ESNext"],
"jsx": "preserve",
"target": "ESNext",
"noEmit": true,
"skipLibCheck": true,
"useDefineForClassFields": true,

1
icons/prometheus.svg Normal file
View 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