Spaces:
Sleeping
Sleeping
| import type { Message } from 'ai'; | |
| import { generateId } from './fileUtils'; | |
| export interface ProjectCommands { | |
| type: string; | |
| setupCommand?: string; | |
| startCommand?: string; | |
| followupMessage: string; | |
| } | |
| interface FileContent { | |
| content: string; | |
| path: string; | |
| } | |
| export async function detectProjectCommands(files: FileContent[]): Promise<ProjectCommands> { | |
| const hasFile = (name: string) => files.some((f) => f.path.endsWith(name)); | |
| if (hasFile('package.json')) { | |
| const packageJsonFile = files.find((f) => f.path.endsWith('package.json')); | |
| if (!packageJsonFile) { | |
| return { type: '', setupCommand: '', followupMessage: '' }; | |
| } | |
| try { | |
| const packageJson = JSON.parse(packageJsonFile.content); | |
| const scripts = packageJson?.scripts || {}; | |
| // Check for preferred commands in priority order | |
| const preferredCommands = ['dev', 'start', 'preview']; | |
| const availableCommand = preferredCommands.find((cmd) => scripts[cmd]); | |
| if (availableCommand) { | |
| return { | |
| type: 'Node.js', | |
| setupCommand: `npm install`, | |
| startCommand: `npm run ${availableCommand}`, | |
| followupMessage: `Found "${availableCommand}" script in package.json. Running "npm run ${availableCommand}" after installation.`, | |
| }; | |
| } | |
| return { | |
| type: 'Node.js', | |
| setupCommand: 'npm install', | |
| followupMessage: | |
| 'Would you like me to inspect package.json to determine the available scripts for running this project?', | |
| }; | |
| } catch (error) { | |
| console.error('Error parsing package.json:', error); | |
| return { type: '', setupCommand: '', followupMessage: '' }; | |
| } | |
| } | |
| if (hasFile('index.html')) { | |
| return { | |
| type: 'Static', | |
| startCommand: 'npx --yes serve', | |
| followupMessage: '', | |
| }; | |
| } | |
| return { type: '', setupCommand: '', followupMessage: '' }; | |
| } | |
| export function createCommandsMessage(commands: ProjectCommands): Message | null { | |
| if (!commands.setupCommand && !commands.startCommand) { | |
| return null; | |
| } | |
| let commandString = ''; | |
| if (commands.setupCommand) { | |
| commandString += ` | |
| <boltAction type="shell">${commands.setupCommand}</boltAction>`; | |
| } | |
| if (commands.startCommand) { | |
| commandString += ` | |
| <boltAction type="start">${commands.startCommand}</boltAction> | |
| `; | |
| } | |
| return { | |
| role: 'assistant', | |
| content: ` | |
| ${commands.followupMessage ? `\n\n${commands.followupMessage}` : ''} | |
| <boltArtifact id="project-setup" title="Project Setup"> | |
| ${commandString} | |
| </boltArtifact>`, | |
| id: generateId(), | |
| createdAt: new Date(), | |
| }; | |
| } | |
| export function escapeBoltArtifactTags(input: string) { | |
| // Regular expression to match boltArtifact tags and their content | |
| const regex = /(<boltArtifact[^>]*>)([\s\S]*?)(<\/boltArtifact>)/g; | |
| return input.replace(regex, (match, openTag, content, closeTag) => { | |
| // Escape the opening tag | |
| const escapedOpenTag = openTag.replace(/</g, '<').replace(/>/g, '>'); | |
| // Escape the closing tag | |
| const escapedCloseTag = closeTag.replace(/</g, '<').replace(/>/g, '>'); | |
| // Return the escaped version | |
| return `${escapedOpenTag}${content}${escapedCloseTag}`; | |
| }); | |
| } | |
| export function escapeBoltAActionTags(input: string) { | |
| // Regular expression to match boltArtifact tags and their content | |
| const regex = /(<boltAction[^>]*>)([\s\S]*?)(<\/boltAction>)/g; | |
| return input.replace(regex, (match, openTag, content, closeTag) => { | |
| // Escape the opening tag | |
| const escapedOpenTag = openTag.replace(/</g, '<').replace(/>/g, '>'); | |
| // Escape the closing tag | |
| const escapedCloseTag = closeTag.replace(/</g, '<').replace(/>/g, '>'); | |
| // Return the escaped version | |
| return `${escapedOpenTag}${content}${escapedCloseTag}`; | |
| }); | |
| } | |
| export function escapeBoltTags(input: string) { | |
| return escapeBoltArtifactTags(escapeBoltAActionTags(input)); | |
| } | |
| // We have this seperate function to simplify the restore snapshot process in to one single artifact. | |
| export function createCommandActionsString(commands: ProjectCommands): string { | |
| if (!commands.setupCommand && !commands.startCommand) { | |
| // Return empty string if no commands | |
| return ''; | |
| } | |
| let commandString = ''; | |
| if (commands.setupCommand) { | |
| commandString += ` | |
| <boltAction type="shell">${commands.setupCommand}</boltAction>`; | |
| } | |
| if (commands.startCommand) { | |
| commandString += ` | |
| <boltAction type="start">${commands.startCommand}</boltAction> | |
| `; | |
| } | |
| return commandString; | |
| } | |