Spaces:
Running
Running
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: ` | |
<boltArtifact id="project-setup" title="Project Setup"> | |
${commandString} | |
</boltArtifact>${commands.followupMessage ? `\n\n${commands.followupMessage}` : ''}`, | |
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)); | |
} | |