scrollToBottom()}
>
Go to last message
diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx
index c5ff7dbb..8786b222 100644
--- a/app/components/chat/Chat.client.tsx
+++ b/app/components/chat/Chat.client.tsx
@@ -316,14 +316,14 @@ export const ChatImpl = memo(
setFakeLoading(true);
if (autoSelectTemplate) {
- const { template, title } = await selectStarterTemplate({
+ const { template } = await selectStarterTemplate({
message: messageContent,
model,
provider,
});
if (template !== 'blank') {
- const temResp = await getTemplates(template, title).catch((e) => {
+ const temResp = await getTemplates(template).catch((e) => {
if (e.message.includes('rate limit')) {
toast.warning('Rate limit exceeded. Skipping starter template\n Continuing with blank template');
} else {
diff --git a/app/components/chat/SupabaseAlert.tsx b/app/components/chat/SupabaseAlert.tsx
index d86e5e53..414a6e51 100644
--- a/app/components/chat/SupabaseAlert.tsx
+++ b/app/components/chat/SupabaseAlert.tsx
@@ -99,7 +99,7 @@ export function SupabaseChatAlert({ alert, clearAlert, postMessage }: Props) {
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
- className="max-w-chat rounded-lg border-l-2 border-l-[#098F5F] border-bolt-elements-borderColor bg-bolt-elements-background-depth-2"
+ className="max-w-chat rounded-lg border-l-2 border-l-[#098F5F] border border-bolt-elements-borderColor bg-bolt-elements-background-depth-2"
>
{/* Header */}
diff --git a/app/lib/persistence/useChatHistory.ts b/app/lib/persistence/useChatHistory.ts
index 3676dc32..dad3da7c 100644
--- a/app/lib/persistence/useChatHistory.ts
+++ b/app/lib/persistence/useChatHistory.ts
@@ -20,7 +20,7 @@ import {
import type { FileMap } from '~/lib/stores/files';
import type { Snapshot } from './types';
import { webcontainer } from '~/lib/webcontainer';
-import { createCommandsMessage, detectProjectCommands } from '~/utils/projectCommands';
+import { detectProjectCommands, createCommandActionsString } from '~/utils/projectCommands';
import type { ContextAnnotation } from '~/types/context';
export interface ChatHistoryItem {
@@ -112,23 +112,26 @@ export function useChatHistory() {
path: key,
};
})
- .filter((x) => !!x);
+ .filter((x): x is { content: string; path: string } => !!x); // Type assertion
const projectCommands = await detectProjectCommands(files);
- const commands = createCommandsMessage(projectCommands);
+
+ // Call the modified function to get only the command actions string
+ const commandActionsString = createCommandActionsString(projectCommands);
filteredMessages = [
{
id: generateId(),
role: 'user',
- content: `Restore project from snapshot
- `,
+ content: `Restore project from snapshot`, // Removed newline
annotations: ['no-store', 'hidden'],
},
{
id: storedMessages.messages[snapshotIndex].id,
role: 'assistant',
- content: ` 📦 Chat Restored from snapshot, You can revert this message to load the full chat history
-
+
+ // Combine followup message and the artifact with files and command actions
+ content: `Bolt Restored your chat from a snapshot. You can revert this message to load the full chat history.
+
${Object.entries(snapshot?.files || {})
.map(([key, value]) => {
if (value?.type === 'file') {
@@ -142,8 +145,9 @@ ${value.content}
}
})
.join('\n')}
+ ${commandActionsString}
- `,
+ `, // Added commandActionsString, followupMessage, updated id and title
annotations: [
'no-store',
...(summary
@@ -157,33 +161,13 @@ ${value.content}
: []),
],
},
- ...(commands !== null
- ? [
- {
- id: `${storedMessages.messages[snapshotIndex].id}-2`,
- role: 'user' as const,
- content: `setup project`,
- annotations: ['no-store', 'hidden'],
- },
- {
- ...commands,
- id: `${storedMessages.messages[snapshotIndex].id}-3`,
- annotations: [
- 'no-store',
- ...(commands.annotations || []),
- ...(summary
- ? [
- {
- chatId: `${storedMessages.messages[snapshotIndex].id}-3`,
- type: 'chatSummary',
- summary,
- } satisfies ContextAnnotation,
- ]
- : []),
- ],
- },
- ]
- : []),
+
+ // Remove the separate user and assistant messages for commands
+ /*
+ *...(commands !== null // This block is no longer needed
+ * ? [ ... ]
+ * : []),
+ */
...filteredMessages,
];
restoreSnapshot(mixedId);
diff --git a/app/utils/constants.ts b/app/utils/constants.ts
index e85405d6..4d955d75 100644
--- a/app/utils/constants.ts
+++ b/app/utils/constants.ts
@@ -26,7 +26,7 @@ PROVIDER_LIST.forEach((provider) => {
export const STARTER_TEMPLATES: Template[] = [
{
- name: 'bolt-expo-app',
+ name: 'Expo App',
label: 'Expo App',
description: 'Expo starter template for building cross-platform mobile apps',
githubRepo: 'xKevIsDev/bolt-expo-template',
@@ -34,7 +34,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:expo',
},
{
- name: 'bolt-astro-basic',
+ name: 'Basic Astro',
label: 'Astro Basic',
description: 'Lightweight Astro starter template for building fast static websites',
githubRepo: 'xKevIsDev/bolt-astro-basic-template',
@@ -42,7 +42,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:astro',
},
{
- name: 'bolt-nextjs-shadcn',
+ name: 'NextJS Shadcn',
label: 'Next.js with shadcn/ui',
description: 'Next.js starter fullstack template integrated with shadcn/ui components and styling system',
githubRepo: 'xKevIsDev/bolt-nextjs-shadcn-template',
@@ -50,7 +50,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:nextjs',
},
{
- name: 'bolt-qwik-ts',
+ name: 'Qwik Typescript',
label: 'Qwik TypeScript',
description: 'Qwik framework starter with TypeScript for building resumable applications',
githubRepo: 'xKevIsDev/bolt-qwik-ts-template',
@@ -58,7 +58,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:qwik',
},
{
- name: 'bolt-remix-ts',
+ name: 'Remix Typescript',
label: 'Remix TypeScript',
description: 'Remix framework starter with TypeScript for full-stack web applications',
githubRepo: 'xKevIsDev/bolt-remix-ts-template',
@@ -66,7 +66,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:remix',
},
{
- name: 'bolt-slidev',
+ name: 'Slidev',
label: 'Slidev Presentation',
description: 'Slidev starter template for creating developer-friendly presentations using Markdown',
githubRepo: 'xKevIsDev/bolt-slidev-template',
@@ -74,7 +74,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:slidev',
},
{
- name: 'bolt-sveltekit',
+ name: 'Sveltekit',
label: 'SvelteKit',
description: 'SvelteKit starter template for building fast, efficient web applications',
githubRepo: 'bolt-sveltekit-template',
@@ -82,7 +82,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:svelte',
},
{
- name: 'vanilla-vite',
+ name: 'Vanilla Vite',
label: 'Vanilla + Vite',
description: 'Minimal Vite starter template for vanilla JavaScript projects',
githubRepo: 'xKevIsDev/vanilla-vite-template',
@@ -90,7 +90,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:vite',
},
{
- name: 'bolt-vite-react',
+ name: 'Vite React',
label: 'React + Vite + typescript',
description: 'React starter template powered by Vite for fast development experience',
githubRepo: 'xKevIsDev/bolt-vite-react-ts-template',
@@ -98,7 +98,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:react',
},
{
- name: 'bolt-vite-ts',
+ name: 'Vite Typescript',
label: 'Vite + TypeScript',
description: 'Vite starter template with TypeScript configuration for type-safe development',
githubRepo: 'xKevIsDev/bolt-vite-ts-template',
@@ -106,7 +106,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:typescript',
},
{
- name: 'bolt-vue',
+ name: 'Vue',
label: 'Vue.js',
description: 'Vue.js starter template with modern tooling and best practices',
githubRepo: 'xKevIsDev/bolt-vue-template',
@@ -114,7 +114,7 @@ export const STARTER_TEMPLATES: Template[] = [
icon: 'i-bolt:vue',
},
{
- name: 'bolt-angular',
+ name: 'Angular',
label: 'Angular Starter',
description: 'A modern Angular starter template with TypeScript support and best practices configuration',
githubRepo: 'xKevIsDev/bolt-angular-template',
diff --git a/app/utils/projectCommands.ts b/app/utils/projectCommands.ts
index 34abc0a0..f3a9f8be 100644
--- a/app/utils/projectCommands.ts
+++ b/app/utils/projectCommands.ts
@@ -84,9 +84,10 @@ export function createCommandsMessage(commands: ProjectCommands): Message | null
return {
role: 'assistant',
content: `
+${commands.followupMessage ? `\n\n${commands.followupMessage}` : ''}
${commandString}
-${commands.followupMessage ? `\n\n${commands.followupMessage}` : ''}`,
+`,
id: generateId(),
createdAt: new Date(),
};
@@ -127,3 +128,26 @@ export function escapeBoltAActionTags(input: string) {
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 += `
+${commands.setupCommand}`;
+ }
+
+ if (commands.startCommand) {
+ commandString += `
+${commands.startCommand}
+`;
+ }
+
+ return commandString;
+}
diff --git a/app/utils/selectStarterTemplate.ts b/app/utils/selectStarterTemplate.ts
index bccab72c..29fe6cbb 100644
--- a/app/utils/selectStarterTemplate.ts
+++ b/app/utils/selectStarterTemplate.ts
@@ -129,7 +129,7 @@ const getGitHubRepoContent = async (repoName: string): Promise<{ name: string; p
}
};
-export async function getTemplates(templateName: string, title?: string) {
+export async function getTemplates(templateName: string) {
const template = STARTER_TEMPLATES.find((t) => t.name == templateName);
if (!template) {
@@ -182,7 +182,8 @@ export async function getTemplates(templateName: string, title?: string) {
}
const assistantMessage = `
-
+Bolt is initializing your project with the required files using the ${template.name} template.
+
${filesToImport.files
.map(
(file) =>