;
+ nonExistentFunction();
+
+ export default App;
+ `,
+ );
+ await po.runPnpmInstall();
+ await po.clickTogglePreviewPanel();
+
+ await po.selectPreviewMode("problems");
+ await po.clickRecheckProblems();
+ await po.snapshotProblemsPane();
+
+ fs.unlinkSync(badFilePath);
+
+ await po.clickRecheckProblems();
+ await po.snapshotProblemsPane();
+});
diff --git a/e2e-tests/select_component.spec.ts b/e2e-tests/select_component.spec.ts
index be45c27..3831d10 100644
--- a/e2e-tests/select_component.spec.ts
+++ b/e2e-tests/select_component.spec.ts
@@ -81,10 +81,7 @@ testSkipIfWindows("upgrade app to select component", async ({ po }) => {
testSkipIfWindows("select component next.js", async ({ po }) => {
await po.setUp();
- // Select Next.js template
- await po.goToHubTab();
- await po.selectTemplate("Next.js Template");
- await po.goToAppsTab();
+ await po.selectHubTemplate("Next.js Template");
await po.sendPrompt("tc=basic");
await po.clickTogglePreviewPanel();
diff --git a/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt b/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt
index 5d93311..8407343 100644
--- a/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt
+++ b/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt
@@ -14,5 +14,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---fix-all-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---fix-all-1.aria.yml
new file mode 100644
index 0000000..a437903
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---fix-all-1.aria.yml
@@ -0,0 +1,21 @@
+- paragraph: tc=create-ts-errors
+- paragraph: This will get a TypeScript error.
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: This will get a TypeScript error."
+- paragraph: EOM
+- paragraph: "Fix these 3 TypeScript compile-time errors:"
+- list:
+ - listitem: src/bad-file.tsx:2:1 - Cannot find name 'nonExistentFunction1'. (TS2304)
+ - listitem: src/bad-file.tsx:3:1 - Cannot find name 'nonExistentFunction2'. (TS2304)
+ - listitem: src/bad-file.tsx:4:1 - Cannot find name 'nonExistentFunction3'. (TS2304)
+- paragraph: Please fix all errors in a concise way.
+- img
+- text: file1.txt
+- img
+- text: file1.txt
+- paragraph: More EOM
+- paragraph: "[[dyad-dump-path=*]]"
+- button "Retry":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---fix-all-1.txt b/e2e-tests/snapshots/problems.spec.ts_problems---fix-all-1.txt
new file mode 100644
index 0000000..5db7910
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---fix-all-1.txt
@@ -0,0 +1,9 @@
+===
+role: user
+message: Fix these 3 TypeScript compile-time errors:
+
+1. src/bad-file.tsx:2:1 - Cannot find name 'nonExistentFunction1'. (TS2304)
+2. src/bad-file.tsx:3:1 - Cannot find name 'nonExistentFunction2'. (TS2304)
+3. src/bad-file.tsx:4:1 - Cannot find name 'nonExistentFunction3'. (TS2304)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-1.aria.yml
new file mode 100644
index 0000000..65e41fb
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-1.aria.yml
@@ -0,0 +1,10 @@
+- img
+- text: 1 error
+- button "Recheck":
+ - img
+- button "Fix All":
+ - img
+- img
+- img
+- text: src/bad-file.tsx 2:1
+- paragraph: Cannot find name 'nonExistentFunction'.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-2.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-2.aria.yml
new file mode 100644
index 0000000..8a691dd
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-2.aria.yml
@@ -0,0 +1,3 @@
+- paragraph: No problems found
+- button "Recheck":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-next-js-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-next-js-1.aria.yml
new file mode 100644
index 0000000..afd952a
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-next-js-1.aria.yml
@@ -0,0 +1,10 @@
+- img
+- text: 1 error
+- button "Recheck":
+ - img
+- button "Fix All":
+ - img
+- img
+- img
+- text: src/bad-file.tsx 2:3
+- paragraph: Cannot find name 'nonExistentFunction'.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-next-js-2.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-next-js-2.aria.yml
new file mode 100644
index 0000000..8a691dd
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-next-js-2.aria.yml
@@ -0,0 +1,3 @@
+- paragraph: No problems found
+- button "Recheck":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-react-vite-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-react-vite-1.aria.yml
new file mode 100644
index 0000000..65e41fb
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-react-vite-1.aria.yml
@@ -0,0 +1,10 @@
+- img
+- text: 1 error
+- button "Recheck":
+ - img
+- button "Fix All":
+ - img
+- img
+- img
+- text: src/bad-file.tsx 2:1
+- paragraph: Cannot find name 'nonExistentFunction'.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-react-vite-2.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-react-vite-2.aria.yml
new file mode 100644
index 0000000..8a691dd
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems---manual-edit-react-vite-2.aria.yml
@@ -0,0 +1,3 @@
+- paragraph: No problems found
+- button "Recheck":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-1.aria.yml
new file mode 100644
index 0000000..db2a3fe
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-1.aria.yml
@@ -0,0 +1,29 @@
+- paragraph: tc=create-ts-errors-complex
+- paragraph: Tests delete-rename-write order
+- img
+- text: main.tsx Delete src/main.tsx
+- img
+- text: "App.tsx → main.tsx Rename From: src/App.tsx To: src/main.tsx"
+- img
+- text: main.tsx
+- img
+- text: "src/main.tsx Summary: final main.tsx file."
+- paragraph: EOM
+- img
+- text: Auto-fix1 problems
+- img
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: Fix remaining error."
+- paragraph: "[[dyad-dump-path=*]]"
+- img
+- text: Auto-fix1 problems
+- img
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: Fix remaining error."
+- paragraph: "[[dyad-dump-path=*]]"
+- button "Retry":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-1.txt b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-1.txt
new file mode 100644
index 0000000..64af21f
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-1.txt
@@ -0,0 +1,406 @@
+===
+role: system
+message:
+ You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
+You make efficient and effective changes to codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations.
+
+# App Preview / Commands
+
+Do *not* tell the user to run shell commands. Instead, they can do one of the following commands in the UI:
+
+- **Rebuild**: This will rebuild the app from scratch. First it deletes the node_modules folder and then it re-installs the npm packages and then starts the app server.
+- **Restart**: This will restart the app server.
+- **Refresh**: This will refresh the app preview page.
+
+You can suggest one of these commands by using the tag like this:
+
+
+
+
+If you output one of these commands, tell the user to look for the action button above the chat input.
+
+# Guidelines
+
+Always reply to the user in the same language they are using.
+
+- Use for setting the chat summary (put this at the end). The chat summary should be less than a sentence, but more than a few words. YOU SHOULD ALWAYS INCLUDE EXACTLY ONE CHAT TITLE
+- Before proceeding with any code edits, check whether the user's request has already been implemented. If the requested change has already been made in the codebase, point this out to the user, e.g., "This feature is already implemented as described."
+- Only edit files that are related to the user's request and leave all other files alone.
+
+If new code needs to be written (i.e., the requested feature does not exist), you MUST:
+
+- Briefly explain the needed changes in a few short sentences, without being too technical.
+- Use for creating or updating files. Try to create small, focused files that will be easy to maintain. Use only one block per file. Do not forget to close the dyad-write tag after writing the file. If you do NOT need to change a file, then do not use the tag.
+- Use for renaming files.
+- Use for removing files.
+- Use for installing packages.
+ - If the user asks for multiple packages, use
+ - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
+- After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
+
+Before sending your final answer, review every import statement you output and do the following:
+
+First-party imports (modules that live in this project)
+- Only import files/modules that have already been described to you.
+- If you need a project file that does not yet exist, create it immediately with before finishing your response.
+
+Third-party imports (anything that would come from npm)
+- If the package is not listed in package.json, install it with .
+
+Do not leave any import unresolved.
+
+# Examples
+
+## Example 1: Adding a new component
+
+
+"use client";
+
+import React from 'react';
+
+const Button = ({ children, variant = 'primary', onClick, disabled = false }) => {
+ const baseClasses = "px-4 py-2 rounded-md font-medium transition-colors";
+
+ const variantClasses = {
+ primary: "bg-blue-600 hover:bg-blue-700 text-white",
+ secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
+ danger: "bg-red-600 hover:bg-red-700 text-white"
+ };
+
+ return (
+
+ );
+};
+
+export default Button;
+
+
+
+"use client";
+
+import React from 'react';
+import Button from './components/Button';
+
+
+function App() {
+
+
+ return (
+
+
My Application
+
+
+
+
+
+
+
+ {/* ... keep existing code (rest of the component) */}
+
+ );
+}
+
+export default App;
+
+Adding a new component
+
+## Example 2: Installing a package and creating a Toast notification system
+
+### User prompt
+
+I want to add a toast
+### System response
+
+OK first, you need to install the package.
+
+
+### User prompt
+
+OK, I've installed the package. Now, I want to create a ToastProvider component.
+
+### System response
+
+
+"use client";
+
+import React from 'react';
+import { Toaster } from 'react-hot-toast';
+const ToastProvider = () => { };
+export default ToastProvider;
+
+
+
+"use client";
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import ToastProvider from './components/ToastProvider';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+
+);
+
+
+
+"use client";
+
+import toast from 'react-hot-toast';
+export const showSuccess = (message) => {
+toast.success(message);
+};
+export const showError = (message) => {
+toast.error(message);
+};
+export const showLoading = (message) => {
+return toast.loading(message);
+};
+export const dismissToast = (toastId) => {
+toast.dismiss(toastId);
+};
+
+Installing & using toast
+I've added a toast notification system using react-hot-toast, created a ToastProvider component, and added utility functions to make showing notifications easy throughout the app.
+
+## Example 3: Renaming and deleting files
+
+
+
+
+"use client";
+
+import React from 'react';
+import { User } from 'lucide-react';
+
+const ProfileCard = ({ user }) => {
+ return (
+
+ );
+};
+
+export default Dashboard;
+
+Renaming profile file
+I've renamed the UserProfile component to ProfileCard, updated its styling, removed an unused Analytics component, and updated imports in the Dashboard page.
+
+# Additional Guidelines
+
+All edits you make on the codebase will directly be built and rendered, therefore you should NEVER make partial changes like letting the user know that they should implement some components or partially implementing features.
+If a user asks for many features at once, you do not have to implement them all as long as the ones you implement are FULLY FUNCTIONAL and you clearly communicate to the user that you didn't implement some specific features.
+
+Immediate Component Creation
+You MUST create a new file for every new component or hook, no matter how small.
+Never add new components to existing files, even if they seem related.
+Aim for components that are 100 lines of code or less.
+Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
+
+Important Rules for dyad-write operations:
+- Only make changes that were directly requested by the user. Everything else in the files must stay exactly as it was.
+- Always specify the correct file path when using dyad-write.
+- Ensure that the code you write is complete, syntactically correct, and follows the existing coding style and conventions of the project.
+- Make sure to close all tags when writing files, with a line break before the closing tag.
+- IMPORTANT: Only use ONE block per file that you write!
+- Prioritize creating small, focused files and components.
+- do NOT be lazy and ALWAYS write the entire file. It needs to be a complete file.
+
+Coding guidelines
+- ALWAYS generate responsive designs.
+- Use toasts components to inform the user about important events.
+- Don't catch errors with try/catch blocks unless specifically requested by the user. It's important that errors are thrown since then they bubble back to you so that you can fix them.
+
+DO NOT OVERENGINEER THE CODE. You take great pride in keeping things simple and elegant. You don't start by writing very complex error handling, fallback mechanisms, etc. You focus on the user's request and make the minimum amount of changes needed.
+DON'T DO MORE THAN WHAT THE USER ASKS FOR.
+
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+Directory names MUST be all lower-case (src/pages, src/components, etc.). File names may use mixed-case if you like.
+
+# REMEMBER
+
+> **CODE FORMATTING IS NON-NEGOTIABLE:**
+> **NEVER, EVER** use markdown code blocks (```) for code.
+> **ONLY** use tags for **ALL** code output.
+> Using ``` for code is **PROHIBITED**.
+> Using for code is **MANDATORY**.
+> Any instance of code within ``` is a **CRITICAL FAILURE**.
+> **REPEAT: NO MARKDOWN CODE BLOCKS. USE EXCLUSIVELY FOR CODE.**
+> Do NOT use tags in the output. ALWAYS use to generate code.
+
+
+
+If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
+tell them that they need to add supabase to their app.
+
+The following response will show a button that allows the user to add supabase to their app.
+
+
+
+# Examples
+
+## Example 1: User wants to use Supabase
+
+### User prompt
+
+I want to use supabase in my app.
+
+### Assistant response
+
+You need to first add Supabase to your app.
+
+
+
+## Example 2: User wants to add auth to their app
+
+### User prompt
+
+I want to add auth to my app.
+
+### Assistant response
+
+You need to first add Supabase to your app and then we can add auth.
+
+
+
+
+===
+role: user
+message: This is my codebase.
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+
+
+
+
+
+
+
+ dyad-generated-app
+
+
+
+
+
+
+
+
+
+
+
+finalMainTsxFileWithError();
+
+
+
+///
+
+
+
+
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react-swc";
+import path from "path";
+
+export default defineConfig(() => ({
+ server: {
+ host: "::",
+ port: 8080,
+ },
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+}));
+
+
+
+
+
+===
+role: assistant
+message: OK, got it. I'm ready to help
+
+===
+role: user
+message: tc=create-ts-errors-complex
+
+===
+role: assistant
+message: Tests delete-rename-write order
+
+
+
+
+
+finalMainTsxFileWithError();
+
+EOM
+
+
+===
+role: user
+message: Fix these 1 TypeScript compile-time error:
+
+1. src/main.tsx:1:1 - Cannot find name 'finalMainTsxFileWithError'. (TS2304)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-2.txt b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-2.txt
new file mode 100644
index 0000000..da95149
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---complex-delete-rename-write-2.txt
@@ -0,0 +1,439 @@
+===
+role: system
+message:
+ You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
+You make efficient and effective changes to codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations.
+
+# App Preview / Commands
+
+Do *not* tell the user to run shell commands. Instead, they can do one of the following commands in the UI:
+
+- **Rebuild**: This will rebuild the app from scratch. First it deletes the node_modules folder and then it re-installs the npm packages and then starts the app server.
+- **Restart**: This will restart the app server.
+- **Refresh**: This will refresh the app preview page.
+
+You can suggest one of these commands by using the tag like this:
+
+
+
+
+If you output one of these commands, tell the user to look for the action button above the chat input.
+
+# Guidelines
+
+Always reply to the user in the same language they are using.
+
+- Use for setting the chat summary (put this at the end). The chat summary should be less than a sentence, but more than a few words. YOU SHOULD ALWAYS INCLUDE EXACTLY ONE CHAT TITLE
+- Before proceeding with any code edits, check whether the user's request has already been implemented. If the requested change has already been made in the codebase, point this out to the user, e.g., "This feature is already implemented as described."
+- Only edit files that are related to the user's request and leave all other files alone.
+
+If new code needs to be written (i.e., the requested feature does not exist), you MUST:
+
+- Briefly explain the needed changes in a few short sentences, without being too technical.
+- Use for creating or updating files. Try to create small, focused files that will be easy to maintain. Use only one block per file. Do not forget to close the dyad-write tag after writing the file. If you do NOT need to change a file, then do not use the tag.
+- Use for renaming files.
+- Use for removing files.
+- Use for installing packages.
+ - If the user asks for multiple packages, use
+ - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
+- After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
+
+Before sending your final answer, review every import statement you output and do the following:
+
+First-party imports (modules that live in this project)
+- Only import files/modules that have already been described to you.
+- If you need a project file that does not yet exist, create it immediately with before finishing your response.
+
+Third-party imports (anything that would come from npm)
+- If the package is not listed in package.json, install it with .
+
+Do not leave any import unresolved.
+
+# Examples
+
+## Example 1: Adding a new component
+
+
+"use client";
+
+import React from 'react';
+
+const Button = ({ children, variant = 'primary', onClick, disabled = false }) => {
+ const baseClasses = "px-4 py-2 rounded-md font-medium transition-colors";
+
+ const variantClasses = {
+ primary: "bg-blue-600 hover:bg-blue-700 text-white",
+ secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
+ danger: "bg-red-600 hover:bg-red-700 text-white"
+ };
+
+ return (
+
+ );
+};
+
+export default Button;
+
+
+
+"use client";
+
+import React from 'react';
+import Button from './components/Button';
+
+
+function App() {
+
+
+ return (
+
+
My Application
+
+
+
+
+
+
+
+ {/* ... keep existing code (rest of the component) */}
+
+ );
+}
+
+export default App;
+
+Adding a new component
+
+## Example 2: Installing a package and creating a Toast notification system
+
+### User prompt
+
+I want to add a toast
+### System response
+
+OK first, you need to install the package.
+
+
+### User prompt
+
+OK, I've installed the package. Now, I want to create a ToastProvider component.
+
+### System response
+
+
+"use client";
+
+import React from 'react';
+import { Toaster } from 'react-hot-toast';
+const ToastProvider = () => { };
+export default ToastProvider;
+
+
+
+"use client";
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import ToastProvider from './components/ToastProvider';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+
+);
+
+
+
+"use client";
+
+import toast from 'react-hot-toast';
+export const showSuccess = (message) => {
+toast.success(message);
+};
+export const showError = (message) => {
+toast.error(message);
+};
+export const showLoading = (message) => {
+return toast.loading(message);
+};
+export const dismissToast = (toastId) => {
+toast.dismiss(toastId);
+};
+
+Installing & using toast
+I've added a toast notification system using react-hot-toast, created a ToastProvider component, and added utility functions to make showing notifications easy throughout the app.
+
+## Example 3: Renaming and deleting files
+
+
+
+
+"use client";
+
+import React from 'react';
+import { User } from 'lucide-react';
+
+const ProfileCard = ({ user }) => {
+ return (
+
+ );
+};
+
+export default Dashboard;
+
+Renaming profile file
+I've renamed the UserProfile component to ProfileCard, updated its styling, removed an unused Analytics component, and updated imports in the Dashboard page.
+
+# Additional Guidelines
+
+All edits you make on the codebase will directly be built and rendered, therefore you should NEVER make partial changes like letting the user know that they should implement some components or partially implementing features.
+If a user asks for many features at once, you do not have to implement them all as long as the ones you implement are FULLY FUNCTIONAL and you clearly communicate to the user that you didn't implement some specific features.
+
+Immediate Component Creation
+You MUST create a new file for every new component or hook, no matter how small.
+Never add new components to existing files, even if they seem related.
+Aim for components that are 100 lines of code or less.
+Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
+
+Important Rules for dyad-write operations:
+- Only make changes that were directly requested by the user. Everything else in the files must stay exactly as it was.
+- Always specify the correct file path when using dyad-write.
+- Ensure that the code you write is complete, syntactically correct, and follows the existing coding style and conventions of the project.
+- Make sure to close all tags when writing files, with a line break before the closing tag.
+- IMPORTANT: Only use ONE block per file that you write!
+- Prioritize creating small, focused files and components.
+- do NOT be lazy and ALWAYS write the entire file. It needs to be a complete file.
+
+Coding guidelines
+- ALWAYS generate responsive designs.
+- Use toasts components to inform the user about important events.
+- Don't catch errors with try/catch blocks unless specifically requested by the user. It's important that errors are thrown since then they bubble back to you so that you can fix them.
+
+DO NOT OVERENGINEER THE CODE. You take great pride in keeping things simple and elegant. You don't start by writing very complex error handling, fallback mechanisms, etc. You focus on the user's request and make the minimum amount of changes needed.
+DON'T DO MORE THAN WHAT THE USER ASKS FOR.
+
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+Directory names MUST be all lower-case (src/pages, src/components, etc.). File names may use mixed-case if you like.
+
+# REMEMBER
+
+> **CODE FORMATTING IS NON-NEGOTIABLE:**
+> **NEVER, EVER** use markdown code blocks (```) for code.
+> **ONLY** use tags for **ALL** code output.
+> Using ``` for code is **PROHIBITED**.
+> Using for code is **MANDATORY**.
+> Any instance of code within ``` is a **CRITICAL FAILURE**.
+> **REPEAT: NO MARKDOWN CODE BLOCKS. USE EXCLUSIVELY FOR CODE.**
+> Do NOT use tags in the output. ALWAYS use to generate code.
+
+
+
+If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
+tell them that they need to add supabase to their app.
+
+The following response will show a button that allows the user to add supabase to their app.
+
+
+
+# Examples
+
+## Example 1: User wants to use Supabase
+
+### User prompt
+
+I want to use supabase in my app.
+
+### Assistant response
+
+You need to first add Supabase to your app.
+
+
+
+## Example 2: User wants to add auth to their app
+
+### User prompt
+
+I want to add auth to my app.
+
+### Assistant response
+
+You need to first add Supabase to your app and then we can add auth.
+
+
+
+
+===
+role: user
+message: This is my codebase.
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+
+
+
+
+
+
+
+ dyad-generated-app
+
+
+
+
+
+
+
+
+
+
+
+// Import doesn't exist
+// import NonExistentClass from 'non-existent-class';
+
+
+const x = new Object();
+x.toString(); // replaced with existing method
+
+
+
+finalMainTsxFileWithError();
+
+
+
+///
+
+
+
+
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react-swc";
+import path from "path";
+
+export default defineConfig(() => ({
+ server: {
+ host: "::",
+ port: 8080,
+ },
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+}));
+
+
+
+
+
+===
+role: assistant
+message: OK, got it. I'm ready to help
+
+===
+role: user
+message: tc=create-ts-errors-complex
+
+===
+role: assistant
+message: Tests delete-rename-write order
+
+
+
+
+
+finalMainTsxFileWithError();
+
+EOM
+
+
+===
+role: user
+message: Fix these 1 TypeScript compile-time error:
+
+1. src/main.tsx:1:1 - Cannot find name 'finalMainTsxFileWithError'. (TS2304)
+
+Please fix all errors in a concise way.
+
+===
+role: assistant
+message:
+
+// Import doesn't exist
+// import NonExistentClass from 'non-existent-class';
+
+
+const x = new Object();
+x.toString(); // replaced with existing method
+
+
+
+
+[[dyad-dump-path=*]]
+
+===
+role: user
+message: Fix these 1 TypeScript compile-time error:
+
+1. src/main.tsx:1:1 - Cannot find name 'finalMainTsxFileWithError'. (TS2304)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---disabled-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---disabled-1.aria.yml
new file mode 100644
index 0000000..d9c77c0
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---disabled-1.aria.yml
@@ -0,0 +1,9 @@
+- paragraph: tc=create-ts-errors
+- paragraph: This will get a TypeScript error.
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: This will get a TypeScript error."
+- paragraph: EOM
+- button "Retry":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-1.aria.yml
new file mode 100644
index 0000000..2144983
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-1.aria.yml
@@ -0,0 +1,25 @@
+- paragraph: tc=create-ts-errors
+- paragraph: This will get a TypeScript error.
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: This will get a TypeScript error."
+- paragraph: EOM
+- img
+- text: Auto-fix2 problems
+- img
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: Fix 2 errors and introduce a new error."
+- paragraph: "[[dyad-dump-path=*]]"
+- img
+- text: Auto-fix1 problems
+- img
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: Fix remaining error."
+- paragraph: "[[dyad-dump-path=*]]"
+- button "Retry":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-1.txt b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-1.txt
new file mode 100644
index 0000000..72eef74
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-1.txt
@@ -0,0 +1,426 @@
+===
+role: system
+message:
+ You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
+You make efficient and effective changes to codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations.
+
+# App Preview / Commands
+
+Do *not* tell the user to run shell commands. Instead, they can do one of the following commands in the UI:
+
+- **Rebuild**: This will rebuild the app from scratch. First it deletes the node_modules folder and then it re-installs the npm packages and then starts the app server.
+- **Restart**: This will restart the app server.
+- **Refresh**: This will refresh the app preview page.
+
+You can suggest one of these commands by using the tag like this:
+
+
+
+
+If you output one of these commands, tell the user to look for the action button above the chat input.
+
+# Guidelines
+
+Always reply to the user in the same language they are using.
+
+- Use for setting the chat summary (put this at the end). The chat summary should be less than a sentence, but more than a few words. YOU SHOULD ALWAYS INCLUDE EXACTLY ONE CHAT TITLE
+- Before proceeding with any code edits, check whether the user's request has already been implemented. If the requested change has already been made in the codebase, point this out to the user, e.g., "This feature is already implemented as described."
+- Only edit files that are related to the user's request and leave all other files alone.
+
+If new code needs to be written (i.e., the requested feature does not exist), you MUST:
+
+- Briefly explain the needed changes in a few short sentences, without being too technical.
+- Use for creating or updating files. Try to create small, focused files that will be easy to maintain. Use only one block per file. Do not forget to close the dyad-write tag after writing the file. If you do NOT need to change a file, then do not use the tag.
+- Use for renaming files.
+- Use for removing files.
+- Use for installing packages.
+ - If the user asks for multiple packages, use
+ - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
+- After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
+
+Before sending your final answer, review every import statement you output and do the following:
+
+First-party imports (modules that live in this project)
+- Only import files/modules that have already been described to you.
+- If you need a project file that does not yet exist, create it immediately with before finishing your response.
+
+Third-party imports (anything that would come from npm)
+- If the package is not listed in package.json, install it with .
+
+Do not leave any import unresolved.
+
+# Examples
+
+## Example 1: Adding a new component
+
+
+"use client";
+
+import React from 'react';
+
+const Button = ({ children, variant = 'primary', onClick, disabled = false }) => {
+ const baseClasses = "px-4 py-2 rounded-md font-medium transition-colors";
+
+ const variantClasses = {
+ primary: "bg-blue-600 hover:bg-blue-700 text-white",
+ secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
+ danger: "bg-red-600 hover:bg-red-700 text-white"
+ };
+
+ return (
+
+ );
+};
+
+export default Button;
+
+
+
+"use client";
+
+import React from 'react';
+import Button from './components/Button';
+
+
+function App() {
+
+
+ return (
+
+
My Application
+
+
+
+
+
+
+
+ {/* ... keep existing code (rest of the component) */}
+
+ );
+}
+
+export default App;
+
+Adding a new component
+
+## Example 2: Installing a package and creating a Toast notification system
+
+### User prompt
+
+I want to add a toast
+### System response
+
+OK first, you need to install the package.
+
+
+### User prompt
+
+OK, I've installed the package. Now, I want to create a ToastProvider component.
+
+### System response
+
+
+"use client";
+
+import React from 'react';
+import { Toaster } from 'react-hot-toast';
+const ToastProvider = () => { };
+export default ToastProvider;
+
+
+
+"use client";
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import ToastProvider from './components/ToastProvider';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+
+);
+
+
+
+"use client";
+
+import toast from 'react-hot-toast';
+export const showSuccess = (message) => {
+toast.success(message);
+};
+export const showError = (message) => {
+toast.error(message);
+};
+export const showLoading = (message) => {
+return toast.loading(message);
+};
+export const dismissToast = (toastId) => {
+toast.dismiss(toastId);
+};
+
+Installing & using toast
+I've added a toast notification system using react-hot-toast, created a ToastProvider component, and added utility functions to make showing notifications easy throughout the app.
+
+## Example 3: Renaming and deleting files
+
+
+
+
+"use client";
+
+import React from 'react';
+import { User } from 'lucide-react';
+
+const ProfileCard = ({ user }) => {
+ return (
+
+ );
+};
+
+export default Dashboard;
+
+Renaming profile file
+I've renamed the UserProfile component to ProfileCard, updated its styling, removed an unused Analytics component, and updated imports in the Dashboard page.
+
+# Additional Guidelines
+
+All edits you make on the codebase will directly be built and rendered, therefore you should NEVER make partial changes like letting the user know that they should implement some components or partially implementing features.
+If a user asks for many features at once, you do not have to implement them all as long as the ones you implement are FULLY FUNCTIONAL and you clearly communicate to the user that you didn't implement some specific features.
+
+Immediate Component Creation
+You MUST create a new file for every new component or hook, no matter how small.
+Never add new components to existing files, even if they seem related.
+Aim for components that are 100 lines of code or less.
+Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
+
+Important Rules for dyad-write operations:
+- Only make changes that were directly requested by the user. Everything else in the files must stay exactly as it was.
+- Always specify the correct file path when using dyad-write.
+- Ensure that the code you write is complete, syntactically correct, and follows the existing coding style and conventions of the project.
+- Make sure to close all tags when writing files, with a line break before the closing tag.
+- IMPORTANT: Only use ONE block per file that you write!
+- Prioritize creating small, focused files and components.
+- do NOT be lazy and ALWAYS write the entire file. It needs to be a complete file.
+
+Coding guidelines
+- ALWAYS generate responsive designs.
+- Use toasts components to inform the user about important events.
+- Don't catch errors with try/catch blocks unless specifically requested by the user. It's important that errors are thrown since then they bubble back to you so that you can fix them.
+
+DO NOT OVERENGINEER THE CODE. You take great pride in keeping things simple and elegant. You don't start by writing very complex error handling, fallback mechanisms, etc. You focus on the user's request and make the minimum amount of changes needed.
+DON'T DO MORE THAN WHAT THE USER ASKS FOR.
+
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+Directory names MUST be all lower-case (src/pages, src/components, etc.). File names may use mixed-case if you like.
+
+# REMEMBER
+
+> **CODE FORMATTING IS NON-NEGOTIABLE:**
+> **NEVER, EVER** use markdown code blocks (```) for code.
+> **ONLY** use tags for **ALL** code output.
+> Using ``` for code is **PROHIBITED**.
+> Using for code is **MANDATORY**.
+> Any instance of code within ``` is a **CRITICAL FAILURE**.
+> **REPEAT: NO MARKDOWN CODE BLOCKS. USE EXCLUSIVELY FOR CODE.**
+> Do NOT use tags in the output. ALWAYS use to generate code.
+
+
+
+If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
+tell them that they need to add supabase to their app.
+
+The following response will show a button that allows the user to add supabase to their app.
+
+
+
+# Examples
+
+## Example 1: User wants to use Supabase
+
+### User prompt
+
+I want to use supabase in my app.
+
+### Assistant response
+
+You need to first add Supabase to your app.
+
+
+
+## Example 2: User wants to add auth to their app
+
+### User prompt
+
+I want to add auth to my app.
+
+### Assistant response
+
+You need to first add Supabase to your app and then we can add auth.
+
+
+
+
+===
+role: user
+message: This is my codebase.
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+
+
+
+
+
+
+
+ dyad-generated-app
+
+
+
+
+
+
+
+
+
+
+
+const App = () =>
Minimal imported app
;
+
+export default App;
+
+
+
+
+import NonExistentClass from 'non-existent-class';
+
+const x = new Object();
+x.nonExistentMethod();
+
+
+
+import { createRoot } from "react-dom/client";
+import App from "./App.tsx";
+
+createRoot(document.getElementById("root")!).render();
+
+
+
+
+///
+
+
+
+
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react-swc";
+import path from "path";
+
+export default defineConfig(() => ({
+ server: {
+ host: "::",
+ port: 8080,
+ },
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+}));
+
+
+
+
+
+===
+role: assistant
+message: OK, got it. I'm ready to help
+
+===
+role: user
+message: tc=create-ts-errors
+
+===
+role: assistant
+message: This will get a TypeScript error.
+
+
+import NonExistentClass from 'non-existent-class';
+
+const x = new Object();
+x.nonExistentMethod();
+
+
+EOM
+
+
+===
+role: user
+message: Fix these 2 TypeScript compile-time errors:
+
+1. src/bad-file.ts:1:30 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+2. src/bad-file.ts:4:3 - Property 'nonExistentMethod' does not exist on type 'Object'. (TS2339)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-2.txt b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-2.txt
new file mode 100644
index 0000000..b615bee
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---enabled-2.txt
@@ -0,0 +1,452 @@
+===
+role: system
+message:
+ You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
+You make efficient and effective changes to codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations.
+
+# App Preview / Commands
+
+Do *not* tell the user to run shell commands. Instead, they can do one of the following commands in the UI:
+
+- **Rebuild**: This will rebuild the app from scratch. First it deletes the node_modules folder and then it re-installs the npm packages and then starts the app server.
+- **Restart**: This will restart the app server.
+- **Refresh**: This will refresh the app preview page.
+
+You can suggest one of these commands by using the tag like this:
+
+
+
+
+If you output one of these commands, tell the user to look for the action button above the chat input.
+
+# Guidelines
+
+Always reply to the user in the same language they are using.
+
+- Use for setting the chat summary (put this at the end). The chat summary should be less than a sentence, but more than a few words. YOU SHOULD ALWAYS INCLUDE EXACTLY ONE CHAT TITLE
+- Before proceeding with any code edits, check whether the user's request has already been implemented. If the requested change has already been made in the codebase, point this out to the user, e.g., "This feature is already implemented as described."
+- Only edit files that are related to the user's request and leave all other files alone.
+
+If new code needs to be written (i.e., the requested feature does not exist), you MUST:
+
+- Briefly explain the needed changes in a few short sentences, without being too technical.
+- Use for creating or updating files. Try to create small, focused files that will be easy to maintain. Use only one block per file. Do not forget to close the dyad-write tag after writing the file. If you do NOT need to change a file, then do not use the tag.
+- Use for renaming files.
+- Use for removing files.
+- Use for installing packages.
+ - If the user asks for multiple packages, use
+ - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
+- After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
+
+Before sending your final answer, review every import statement you output and do the following:
+
+First-party imports (modules that live in this project)
+- Only import files/modules that have already been described to you.
+- If you need a project file that does not yet exist, create it immediately with before finishing your response.
+
+Third-party imports (anything that would come from npm)
+- If the package is not listed in package.json, install it with .
+
+Do not leave any import unresolved.
+
+# Examples
+
+## Example 1: Adding a new component
+
+
+"use client";
+
+import React from 'react';
+
+const Button = ({ children, variant = 'primary', onClick, disabled = false }) => {
+ const baseClasses = "px-4 py-2 rounded-md font-medium transition-colors";
+
+ const variantClasses = {
+ primary: "bg-blue-600 hover:bg-blue-700 text-white",
+ secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
+ danger: "bg-red-600 hover:bg-red-700 text-white"
+ };
+
+ return (
+
+ );
+};
+
+export default Button;
+
+
+
+"use client";
+
+import React from 'react';
+import Button from './components/Button';
+
+
+function App() {
+
+
+ return (
+
+
My Application
+
+
+
+
+
+
+
+ {/* ... keep existing code (rest of the component) */}
+
+ );
+}
+
+export default App;
+
+Adding a new component
+
+## Example 2: Installing a package and creating a Toast notification system
+
+### User prompt
+
+I want to add a toast
+### System response
+
+OK first, you need to install the package.
+
+
+### User prompt
+
+OK, I've installed the package. Now, I want to create a ToastProvider component.
+
+### System response
+
+
+"use client";
+
+import React from 'react';
+import { Toaster } from 'react-hot-toast';
+const ToastProvider = () => { };
+export default ToastProvider;
+
+
+
+"use client";
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import ToastProvider from './components/ToastProvider';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+
+);
+
+
+
+"use client";
+
+import toast from 'react-hot-toast';
+export const showSuccess = (message) => {
+toast.success(message);
+};
+export const showError = (message) => {
+toast.error(message);
+};
+export const showLoading = (message) => {
+return toast.loading(message);
+};
+export const dismissToast = (toastId) => {
+toast.dismiss(toastId);
+};
+
+Installing & using toast
+I've added a toast notification system using react-hot-toast, created a ToastProvider component, and added utility functions to make showing notifications easy throughout the app.
+
+## Example 3: Renaming and deleting files
+
+
+
+
+"use client";
+
+import React from 'react';
+import { User } from 'lucide-react';
+
+const ProfileCard = ({ user }) => {
+ return (
+
+ );
+};
+
+export default Dashboard;
+
+Renaming profile file
+I've renamed the UserProfile component to ProfileCard, updated its styling, removed an unused Analytics component, and updated imports in the Dashboard page.
+
+# Additional Guidelines
+
+All edits you make on the codebase will directly be built and rendered, therefore you should NEVER make partial changes like letting the user know that they should implement some components or partially implementing features.
+If a user asks for many features at once, you do not have to implement them all as long as the ones you implement are FULLY FUNCTIONAL and you clearly communicate to the user that you didn't implement some specific features.
+
+Immediate Component Creation
+You MUST create a new file for every new component or hook, no matter how small.
+Never add new components to existing files, even if they seem related.
+Aim for components that are 100 lines of code or less.
+Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
+
+Important Rules for dyad-write operations:
+- Only make changes that were directly requested by the user. Everything else in the files must stay exactly as it was.
+- Always specify the correct file path when using dyad-write.
+- Ensure that the code you write is complete, syntactically correct, and follows the existing coding style and conventions of the project.
+- Make sure to close all tags when writing files, with a line break before the closing tag.
+- IMPORTANT: Only use ONE block per file that you write!
+- Prioritize creating small, focused files and components.
+- do NOT be lazy and ALWAYS write the entire file. It needs to be a complete file.
+
+Coding guidelines
+- ALWAYS generate responsive designs.
+- Use toasts components to inform the user about important events.
+- Don't catch errors with try/catch blocks unless specifically requested by the user. It's important that errors are thrown since then they bubble back to you so that you can fix them.
+
+DO NOT OVERENGINEER THE CODE. You take great pride in keeping things simple and elegant. You don't start by writing very complex error handling, fallback mechanisms, etc. You focus on the user's request and make the minimum amount of changes needed.
+DON'T DO MORE THAN WHAT THE USER ASKS FOR.
+
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+Directory names MUST be all lower-case (src/pages, src/components, etc.). File names may use mixed-case if you like.
+
+# REMEMBER
+
+> **CODE FORMATTING IS NON-NEGOTIABLE:**
+> **NEVER, EVER** use markdown code blocks (```) for code.
+> **ONLY** use tags for **ALL** code output.
+> Using ``` for code is **PROHIBITED**.
+> Using for code is **MANDATORY**.
+> Any instance of code within ``` is a **CRITICAL FAILURE**.
+> **REPEAT: NO MARKDOWN CODE BLOCKS. USE EXCLUSIVELY FOR CODE.**
+> Do NOT use tags in the output. ALWAYS use to generate code.
+
+
+
+If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
+tell them that they need to add supabase to their app.
+
+The following response will show a button that allows the user to add supabase to their app.
+
+
+
+# Examples
+
+## Example 1: User wants to use Supabase
+
+### User prompt
+
+I want to use supabase in my app.
+
+### Assistant response
+
+You need to first add Supabase to your app.
+
+
+
+## Example 2: User wants to add auth to their app
+
+### User prompt
+
+I want to add auth to my app.
+
+### Assistant response
+
+You need to first add Supabase to your app and then we can add auth.
+
+
+
+
+===
+role: user
+message: This is my codebase.
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+
+
+
+
+
+
+
+ dyad-generated-app
+
+
+
+
+
+
+
+
+
+
+
+const App = () =>
Minimal imported app
;
+
+export default App;
+
+
+
+
+// Import doesn't exist
+// import NonExistentClass from 'non-existent-class';
+
+
+const x = new Object();
+x.nonExistentMethod2();
+
+
+
+import { createRoot } from "react-dom/client";
+import App from "./App.tsx";
+
+createRoot(document.getElementById("root")!).render();
+
+
+
+
+///
+
+
+
+
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react-swc";
+import path from "path";
+
+export default defineConfig(() => ({
+ server: {
+ host: "::",
+ port: 8080,
+ },
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+}));
+
+
+
+
+
+===
+role: assistant
+message: OK, got it. I'm ready to help
+
+===
+role: user
+message: tc=create-ts-errors
+
+===
+role: assistant
+message: This will get a TypeScript error.
+
+
+import NonExistentClass from 'non-existent-class';
+
+const x = new Object();
+x.nonExistentMethod();
+
+
+EOM
+
+
+===
+role: user
+message: Fix these 2 TypeScript compile-time errors:
+
+1. src/bad-file.ts:1:30 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+2. src/bad-file.ts:4:3 - Property 'nonExistentMethod' does not exist on type 'Object'. (TS2339)
+
+Please fix all errors in a concise way.
+
+===
+role: assistant
+message:
+
+// Import doesn't exist
+// import NonExistentClass from 'non-existent-class';
+
+
+const x = new Object();
+x.nonExistentMethod2();
+
+
+
+
+[[dyad-dump-path=*]]
+
+===
+role: user
+message: Fix these 1 TypeScript compile-time error:
+
+1. src/bad-file.ts:6:3 - Property 'nonExistentMethod2' does not exist on type 'Object'. (TS2339)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-1.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-1.aria.yml
new file mode 100644
index 0000000..e03ee87
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-1.aria.yml
@@ -0,0 +1,23 @@
+- img
+- text: Auto-fix5 problems
+- img
+- text: "1"
+- img
+- text: /src\/bad-file\.ts 1:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "2"
+- img
+- text: /src\/bad-file\.ts 2:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "3"
+- img
+- text: /src\/bad-file\.ts 3:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "4"
+- img
+- text: /src\/bad-file\.ts 4:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "5"
+- img
+- text: /src\/bad-file\.ts 5:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-1.txt b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-1.txt
new file mode 100644
index 0000000..863224f
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-1.txt
@@ -0,0 +1,431 @@
+===
+role: system
+message:
+ You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
+You make efficient and effective changes to codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations.
+
+# App Preview / Commands
+
+Do *not* tell the user to run shell commands. Instead, they can do one of the following commands in the UI:
+
+- **Rebuild**: This will rebuild the app from scratch. First it deletes the node_modules folder and then it re-installs the npm packages and then starts the app server.
+- **Restart**: This will restart the app server.
+- **Refresh**: This will refresh the app preview page.
+
+You can suggest one of these commands by using the tag like this:
+
+
+
+
+If you output one of these commands, tell the user to look for the action button above the chat input.
+
+# Guidelines
+
+Always reply to the user in the same language they are using.
+
+- Use for setting the chat summary (put this at the end). The chat summary should be less than a sentence, but more than a few words. YOU SHOULD ALWAYS INCLUDE EXACTLY ONE CHAT TITLE
+- Before proceeding with any code edits, check whether the user's request has already been implemented. If the requested change has already been made in the codebase, point this out to the user, e.g., "This feature is already implemented as described."
+- Only edit files that are related to the user's request and leave all other files alone.
+
+If new code needs to be written (i.e., the requested feature does not exist), you MUST:
+
+- Briefly explain the needed changes in a few short sentences, without being too technical.
+- Use for creating or updating files. Try to create small, focused files that will be easy to maintain. Use only one block per file. Do not forget to close the dyad-write tag after writing the file. If you do NOT need to change a file, then do not use the tag.
+- Use for renaming files.
+- Use for removing files.
+- Use for installing packages.
+ - If the user asks for multiple packages, use
+ - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
+- After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
+
+Before sending your final answer, review every import statement you output and do the following:
+
+First-party imports (modules that live in this project)
+- Only import files/modules that have already been described to you.
+- If you need a project file that does not yet exist, create it immediately with before finishing your response.
+
+Third-party imports (anything that would come from npm)
+- If the package is not listed in package.json, install it with .
+
+Do not leave any import unresolved.
+
+# Examples
+
+## Example 1: Adding a new component
+
+
+"use client";
+
+import React from 'react';
+
+const Button = ({ children, variant = 'primary', onClick, disabled = false }) => {
+ const baseClasses = "px-4 py-2 rounded-md font-medium transition-colors";
+
+ const variantClasses = {
+ primary: "bg-blue-600 hover:bg-blue-700 text-white",
+ secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
+ danger: "bg-red-600 hover:bg-red-700 text-white"
+ };
+
+ return (
+
+ );
+};
+
+export default Button;
+
+
+
+"use client";
+
+import React from 'react';
+import Button from './components/Button';
+
+
+function App() {
+
+
+ return (
+
+
My Application
+
+
+
+
+
+
+
+ {/* ... keep existing code (rest of the component) */}
+
+ );
+}
+
+export default App;
+
+Adding a new component
+
+## Example 2: Installing a package and creating a Toast notification system
+
+### User prompt
+
+I want to add a toast
+### System response
+
+OK first, you need to install the package.
+
+
+### User prompt
+
+OK, I've installed the package. Now, I want to create a ToastProvider component.
+
+### System response
+
+
+"use client";
+
+import React from 'react';
+import { Toaster } from 'react-hot-toast';
+const ToastProvider = () => { };
+export default ToastProvider;
+
+
+
+"use client";
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import ToastProvider from './components/ToastProvider';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+
+);
+
+
+
+"use client";
+
+import toast from 'react-hot-toast';
+export const showSuccess = (message) => {
+toast.success(message);
+};
+export const showError = (message) => {
+toast.error(message);
+};
+export const showLoading = (message) => {
+return toast.loading(message);
+};
+export const dismissToast = (toastId) => {
+toast.dismiss(toastId);
+};
+
+Installing & using toast
+I've added a toast notification system using react-hot-toast, created a ToastProvider component, and added utility functions to make showing notifications easy throughout the app.
+
+## Example 3: Renaming and deleting files
+
+
+
+
+"use client";
+
+import React from 'react';
+import { User } from 'lucide-react';
+
+const ProfileCard = ({ user }) => {
+ return (
+
+ );
+};
+
+export default Dashboard;
+
+Renaming profile file
+I've renamed the UserProfile component to ProfileCard, updated its styling, removed an unused Analytics component, and updated imports in the Dashboard page.
+
+# Additional Guidelines
+
+All edits you make on the codebase will directly be built and rendered, therefore you should NEVER make partial changes like letting the user know that they should implement some components or partially implementing features.
+If a user asks for many features at once, you do not have to implement them all as long as the ones you implement are FULLY FUNCTIONAL and you clearly communicate to the user that you didn't implement some specific features.
+
+Immediate Component Creation
+You MUST create a new file for every new component or hook, no matter how small.
+Never add new components to existing files, even if they seem related.
+Aim for components that are 100 lines of code or less.
+Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
+
+Important Rules for dyad-write operations:
+- Only make changes that were directly requested by the user. Everything else in the files must stay exactly as it was.
+- Always specify the correct file path when using dyad-write.
+- Ensure that the code you write is complete, syntactically correct, and follows the existing coding style and conventions of the project.
+- Make sure to close all tags when writing files, with a line break before the closing tag.
+- IMPORTANT: Only use ONE block per file that you write!
+- Prioritize creating small, focused files and components.
+- do NOT be lazy and ALWAYS write the entire file. It needs to be a complete file.
+
+Coding guidelines
+- ALWAYS generate responsive designs.
+- Use toasts components to inform the user about important events.
+- Don't catch errors with try/catch blocks unless specifically requested by the user. It's important that errors are thrown since then they bubble back to you so that you can fix them.
+
+DO NOT OVERENGINEER THE CODE. You take great pride in keeping things simple and elegant. You don't start by writing very complex error handling, fallback mechanisms, etc. You focus on the user's request and make the minimum amount of changes needed.
+DON'T DO MORE THAN WHAT THE USER ASKS FOR.
+
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+Directory names MUST be all lower-case (src/pages, src/components, etc.). File names may use mixed-case if you like.
+
+# REMEMBER
+
+> **CODE FORMATTING IS NON-NEGOTIABLE:**
+> **NEVER, EVER** use markdown code blocks (```) for code.
+> **ONLY** use tags for **ALL** code output.
+> Using ``` for code is **PROHIBITED**.
+> Using for code is **MANDATORY**.
+> Any instance of code within ``` is a **CRITICAL FAILURE**.
+> **REPEAT: NO MARKDOWN CODE BLOCKS. USE EXCLUSIVELY FOR CODE.**
+> Do NOT use tags in the output. ALWAYS use to generate code.
+
+
+
+If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
+tell them that they need to add supabase to their app.
+
+The following response will show a button that allows the user to add supabase to their app.
+
+
+
+# Examples
+
+## Example 1: User wants to use Supabase
+
+### User prompt
+
+I want to use supabase in my app.
+
+### Assistant response
+
+You need to first add Supabase to your app.
+
+
+
+## Example 2: User wants to add auth to their app
+
+### User prompt
+
+I want to add auth to my app.
+
+### Assistant response
+
+You need to first add Supabase to your app and then we can add auth.
+
+
+
+
+===
+role: user
+message: This is my codebase.
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+
+
+
+
+
+
+
+ dyad-generated-app
+
+
+
+
+
+
+
+
+
+
+
+const App = () =>
Minimal imported app
;
+
+export default App;
+
+
+
+
+import NonExistentClass from 'non-existent-class';
+import NonExistentClass2 from 'non-existent-class';
+import NonExistentClass3 from 'non-existent-class';
+import NonExistentClass4 from 'non-existent-class';
+import NonExistentClass5 from 'non-existent-class';
+
+
+
+import { createRoot } from "react-dom/client";
+import App from "./App.tsx";
+
+createRoot(document.getElementById("root")!).render();
+
+
+
+
+///
+
+
+
+
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react-swc";
+import path from "path";
+
+export default defineConfig(() => ({
+ server: {
+ host: "::",
+ port: 8080,
+ },
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+}));
+
+
+
+
+
+===
+role: assistant
+message: OK, got it. I'm ready to help
+
+===
+role: user
+message: tc=create-unfixable-ts-errors
+
+===
+role: assistant
+message: This should not get fixed
+
+
+import NonExistentClass from 'non-existent-class';
+import NonExistentClass2 from 'non-existent-class';
+import NonExistentClass3 from 'non-existent-class';
+import NonExistentClass4 from 'non-existent-class';
+import NonExistentClass5 from 'non-existent-class';
+
+
+EOM
+
+
+===
+role: user
+message: Fix these 5 TypeScript compile-time errors:
+
+1. src/bad-file.ts:1:30 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+2. src/bad-file.ts:2:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+3. src/bad-file.ts:3:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+4. src/bad-file.ts:4:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+5. src/bad-file.ts:5:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-2.aria.yml b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-2.aria.yml
new file mode 100644
index 0000000..f108dc5
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-2.aria.yml
@@ -0,0 +1,47 @@
+- paragraph: tc=create-unfixable-ts-errors
+- paragraph: This should not get fixed
+- img
+- text: bad-file.ts
+- img
+- text: "src/bad-file.ts Summary: This will produce 5 TypeScript errors."
+- paragraph: EOM
+- img
+- text: Auto-fix5 problems
+- img
+- img
+- text: file1.txt
+- img
+- text: file1.txt
+- paragraph: More EOM
+- paragraph: "[[dyad-dump-path=*]]"
+- img
+- text: Auto-fix5 problems
+- img
+- text: "1"
+- img
+- text: /src\/bad-file\.ts 1:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "2"
+- img
+- text: /src\/bad-file\.ts 2:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "3"
+- img
+- text: /src\/bad-file\.ts 3:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "4"
+- img
+- text: /src\/bad-file\.ts 4:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- text: "5"
+- img
+- text: /src\/bad-file\.ts 5:\d+ TS2307/
+- paragraph: Cannot find module 'non-existent-class' or its corresponding type declarations.
+- img
+- text: file1.txt
+- img
+- text: file1.txt
+- paragraph: More EOM
+- paragraph: "[[dyad-dump-path=*]]"
+- button "Retry":
+ - img
\ No newline at end of file
diff --git a/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-2.txt b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-2.txt
new file mode 100644
index 0000000..52984fb
--- /dev/null
+++ b/e2e-tests/snapshots/problems.spec.ts_problems-auto-fix---gives-up-after-2-attempts-2.txt
@@ -0,0 +1,458 @@
+===
+role: system
+message:
+ You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
+You make efficient and effective changes to codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations.
+
+# App Preview / Commands
+
+Do *not* tell the user to run shell commands. Instead, they can do one of the following commands in the UI:
+
+- **Rebuild**: This will rebuild the app from scratch. First it deletes the node_modules folder and then it re-installs the npm packages and then starts the app server.
+- **Restart**: This will restart the app server.
+- **Refresh**: This will refresh the app preview page.
+
+You can suggest one of these commands by using the tag like this:
+
+
+
+
+If you output one of these commands, tell the user to look for the action button above the chat input.
+
+# Guidelines
+
+Always reply to the user in the same language they are using.
+
+- Use for setting the chat summary (put this at the end). The chat summary should be less than a sentence, but more than a few words. YOU SHOULD ALWAYS INCLUDE EXACTLY ONE CHAT TITLE
+- Before proceeding with any code edits, check whether the user's request has already been implemented. If the requested change has already been made in the codebase, point this out to the user, e.g., "This feature is already implemented as described."
+- Only edit files that are related to the user's request and leave all other files alone.
+
+If new code needs to be written (i.e., the requested feature does not exist), you MUST:
+
+- Briefly explain the needed changes in a few short sentences, without being too technical.
+- Use for creating or updating files. Try to create small, focused files that will be easy to maintain. Use only one block per file. Do not forget to close the dyad-write tag after writing the file. If you do NOT need to change a file, then do not use the tag.
+- Use for renaming files.
+- Use for removing files.
+- Use for installing packages.
+ - If the user asks for multiple packages, use
+ - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
+- After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
+
+Before sending your final answer, review every import statement you output and do the following:
+
+First-party imports (modules that live in this project)
+- Only import files/modules that have already been described to you.
+- If you need a project file that does not yet exist, create it immediately with before finishing your response.
+
+Third-party imports (anything that would come from npm)
+- If the package is not listed in package.json, install it with .
+
+Do not leave any import unresolved.
+
+# Examples
+
+## Example 1: Adding a new component
+
+
+"use client";
+
+import React from 'react';
+
+const Button = ({ children, variant = 'primary', onClick, disabled = false }) => {
+ const baseClasses = "px-4 py-2 rounded-md font-medium transition-colors";
+
+ const variantClasses = {
+ primary: "bg-blue-600 hover:bg-blue-700 text-white",
+ secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800",
+ danger: "bg-red-600 hover:bg-red-700 text-white"
+ };
+
+ return (
+
+ );
+};
+
+export default Button;
+
+
+
+"use client";
+
+import React from 'react';
+import Button from './components/Button';
+
+
+function App() {
+
+
+ return (
+
+
My Application
+
+
+
+
+
+
+
+ {/* ... keep existing code (rest of the component) */}
+
+ );
+}
+
+export default App;
+
+Adding a new component
+
+## Example 2: Installing a package and creating a Toast notification system
+
+### User prompt
+
+I want to add a toast
+### System response
+
+OK first, you need to install the package.
+
+
+### User prompt
+
+OK, I've installed the package. Now, I want to create a ToastProvider component.
+
+### System response
+
+
+"use client";
+
+import React from 'react';
+import { Toaster } from 'react-hot-toast';
+const ToastProvider = () => { };
+export default ToastProvider;
+
+
+
+"use client";
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import ToastProvider from './components/ToastProvider';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+
+);
+
+
+
+"use client";
+
+import toast from 'react-hot-toast';
+export const showSuccess = (message) => {
+toast.success(message);
+};
+export const showError = (message) => {
+toast.error(message);
+};
+export const showLoading = (message) => {
+return toast.loading(message);
+};
+export const dismissToast = (toastId) => {
+toast.dismiss(toastId);
+};
+
+Installing & using toast
+I've added a toast notification system using react-hot-toast, created a ToastProvider component, and added utility functions to make showing notifications easy throughout the app.
+
+## Example 3: Renaming and deleting files
+
+
+
+
+"use client";
+
+import React from 'react';
+import { User } from 'lucide-react';
+
+const ProfileCard = ({ user }) => {
+ return (
+
+ );
+};
+
+export default Dashboard;
+
+Renaming profile file
+I've renamed the UserProfile component to ProfileCard, updated its styling, removed an unused Analytics component, and updated imports in the Dashboard page.
+
+# Additional Guidelines
+
+All edits you make on the codebase will directly be built and rendered, therefore you should NEVER make partial changes like letting the user know that they should implement some components or partially implementing features.
+If a user asks for many features at once, you do not have to implement them all as long as the ones you implement are FULLY FUNCTIONAL and you clearly communicate to the user that you didn't implement some specific features.
+
+Immediate Component Creation
+You MUST create a new file for every new component or hook, no matter how small.
+Never add new components to existing files, even if they seem related.
+Aim for components that are 100 lines of code or less.
+Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
+
+Important Rules for dyad-write operations:
+- Only make changes that were directly requested by the user. Everything else in the files must stay exactly as it was.
+- Always specify the correct file path when using dyad-write.
+- Ensure that the code you write is complete, syntactically correct, and follows the existing coding style and conventions of the project.
+- Make sure to close all tags when writing files, with a line break before the closing tag.
+- IMPORTANT: Only use ONE block per file that you write!
+- Prioritize creating small, focused files and components.
+- do NOT be lazy and ALWAYS write the entire file. It needs to be a complete file.
+
+Coding guidelines
+- ALWAYS generate responsive designs.
+- Use toasts components to inform the user about important events.
+- Don't catch errors with try/catch blocks unless specifically requested by the user. It's important that errors are thrown since then they bubble back to you so that you can fix them.
+
+DO NOT OVERENGINEER THE CODE. You take great pride in keeping things simple and elegant. You don't start by writing very complex error handling, fallback mechanisms, etc. You focus on the user's request and make the minimum amount of changes needed.
+DON'T DO MORE THAN WHAT THE USER ASKS FOR.
+
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+Directory names MUST be all lower-case (src/pages, src/components, etc.). File names may use mixed-case if you like.
+
+# REMEMBER
+
+> **CODE FORMATTING IS NON-NEGOTIABLE:**
+> **NEVER, EVER** use markdown code blocks (```) for code.
+> **ONLY** use tags for **ALL** code output.
+> Using ``` for code is **PROHIBITED**.
+> Using for code is **MANDATORY**.
+> Any instance of code within ``` is a **CRITICAL FAILURE**.
+> **REPEAT: NO MARKDOWN CODE BLOCKS. USE EXCLUSIVELY FOR CODE.**
+> Do NOT use tags in the output. ALWAYS use to generate code.
+
+
+
+If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
+tell them that they need to add supabase to their app.
+
+The following response will show a button that allows the user to add supabase to their app.
+
+
+
+# Examples
+
+## Example 1: User wants to use Supabase
+
+### User prompt
+
+I want to use supabase in my app.
+
+### Assistant response
+
+You need to first add Supabase to your app.
+
+
+
+## Example 2: User wants to add auth to their app
+
+### User prompt
+
+I want to add auth to my app.
+
+### Assistant response
+
+You need to first add Supabase to your app and then we can add auth.
+
+
+
+
+===
+role: user
+message: This is my codebase.
+[[beginning of AI_RULES.md]]
+There's already AI rules...
+[[end of AI_RULES.md]]
+
+
+
+
+A file (2)
+
+
+
+
+
+
+
+
+ dyad-generated-app
+
+
+
+
+
+
+
+
+
+
+
+const App = () =>
Minimal imported app
;
+
+export default App;
+
+
+
+
+import NonExistentClass from 'non-existent-class';
+import NonExistentClass2 from 'non-existent-class';
+import NonExistentClass3 from 'non-existent-class';
+import NonExistentClass4 from 'non-existent-class';
+import NonExistentClass5 from 'non-existent-class';
+
+
+
+import { createRoot } from "react-dom/client";
+import App from "./App.tsx";
+
+createRoot(document.getElementById("root")!).render();
+
+
+
+
+///
+
+
+
+
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react-swc";
+import path from "path";
+
+export default defineConfig(() => ({
+ server: {
+ host: "::",
+ port: 8080,
+ },
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+}));
+
+
+
+
+
+===
+role: assistant
+message: OK, got it. I'm ready to help
+
+===
+role: user
+message: tc=create-unfixable-ts-errors
+
+===
+role: assistant
+message: This should not get fixed
+
+
+import NonExistentClass from 'non-existent-class';
+import NonExistentClass2 from 'non-existent-class';
+import NonExistentClass3 from 'non-existent-class';
+import NonExistentClass4 from 'non-existent-class';
+import NonExistentClass5 from 'non-existent-class';
+
+
+EOM
+
+
+===
+role: user
+message: Fix these 5 TypeScript compile-time errors:
+
+1. src/bad-file.ts:1:30 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+2. src/bad-file.ts:2:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+3. src/bad-file.ts:3:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+4. src/bad-file.ts:4:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+5. src/bad-file.ts:5:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+
+Please fix all errors in a concise way.
+
+===
+role: assistant
+message:
+
+ A file (2)
+
+ More
+ EOM
+
+[[dyad-dump-path=*]]
+
+===
+role: user
+message: Fix these 5 TypeScript compile-time errors:
+
+1. src/bad-file.ts:1:30 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+2. src/bad-file.ts:2:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+3. src/bad-file.ts:3:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+4. src/bad-file.ts:4:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+5. src/bad-file.ts:5:31 - Cannot find module 'non-existent-class' or its corresponding type declarations. (TS2307)
+
+Please fix all errors in a concise way.
\ No newline at end of file
diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt
index 68824e0..41ef2f3 100644
--- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt
+++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt
@@ -11,5 +11,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt
index 18307e3..290cd8e 100644
--- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt
+++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt
@@ -12,5 +12,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt
index 68824e0..41ef2f3 100644
--- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt
+++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt
@@ -11,5 +11,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt
index 9d6f84c..6ac34ca 100644
--- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt
+++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt
@@ -12,5 +12,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt
index 68824e0..41ef2f3 100644
--- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt
+++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt
@@ -11,5 +11,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt
index 99152ab..b03ebb6 100644
--- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt
+++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt
@@ -12,5 +12,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt
index 1b01e1d..caccb58 100644
--- a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt
+++ b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt
@@ -21,5 +21,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt
index 16ea61d..fcad7f1 100644
--- a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt
+++ b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt
@@ -21,5 +21,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt
index 331cdb3..ca2175f 100644
--- a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt
+++ b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt
@@ -21,5 +21,6 @@
"enableProLazyEditsMode": true,
"enableProSmartFilesContextMode": true,
"selectedChatMode": "build",
+ "enableAutoFixProblems": true,
"isTestMode": true
}
\ No newline at end of file
diff --git a/e2e-tests/template-create-nextjs.spec.ts b/e2e-tests/template-create-nextjs.spec.ts
index c291fd6..06fcfe5 100644
--- a/e2e-tests/template-create-nextjs.spec.ts
+++ b/e2e-tests/template-create-nextjs.spec.ts
@@ -3,10 +3,7 @@ import { expect } from "@playwright/test";
test("create next.js app", async ({ po }) => {
await po.setUp();
- // Select Next.js template
- await po.goToHubTab();
- await po.selectTemplate("Next.js Template");
- await po.goToAppsTab();
+ await po.selectHubTemplate("Next.js Template");
// Create an app
await po.sendPrompt("tc=edit-made-with-dyad");
diff --git a/src/__tests__/__snapshots__/problem_prompt.test.ts.snap b/src/__tests__/__snapshots__/problem_prompt.test.ts.snap
new file mode 100644
index 0000000..ed556f8
--- /dev/null
+++ b/src/__tests__/__snapshots__/problem_prompt.test.ts.snap
@@ -0,0 +1,63 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`problem_prompt > createConciseProblemFixPrompt > should format a concise prompt for multiple errors 1`] = `
+"Fix these 2 TypeScript compile-time errors:
+
+1. src/main.ts:5:12 - Cannot find module 'react-dom/client' or its corresponding type declarations. (TS2307)
+2. src/components/Modal.tsx:35:20 - Property 'isOpen' does not exist on type 'IntrinsicAttributes & ModalProps'. (TS2339)
+
+Please fix all errors in a concise way."
+`;
+
+exports[`problem_prompt > createConciseProblemFixPrompt > should format a concise prompt for single error 1`] = `
+"Fix these 1 TypeScript compile-time error:
+
+1. src/App.tsx:10:5 - Cannot find name 'consol'. Did you mean 'console'? (TS2552)
+
+Please fix all errors in a concise way."
+`;
+
+exports[`problem_prompt > createConciseProblemFixPrompt > should return a short message when no problems exist 1`] = `"No TypeScript problems detected."`;
+
+exports[`problem_prompt > createProblemFixPrompt > should format a single error correctly 1`] = `
+"Fix these 1 TypeScript compile-time error:
+
+1. src/components/Button.tsx:15:23 - Property 'onClick' does not exist on type 'ButtonProps'. (TS2339)
+
+Please fix all errors in a concise way."
+`;
+
+exports[`problem_prompt > createProblemFixPrompt > should format multiple errors across multiple files 1`] = `
+"Fix these 4 TypeScript compile-time errors:
+
+1. src/components/Button.tsx:15:23 - Property 'onClick' does not exist on type 'ButtonProps'. (TS2339)
+2. src/components/Button.tsx:8:12 - Type 'string | undefined' is not assignable to type 'string'. (TS2322)
+3. src/hooks/useApi.ts:42:5 - Argument of type 'unknown' is not assignable to parameter of type 'string'. (TS2345)
+4. src/utils/helpers.ts:45:8 - Function lacks ending return statement and return type does not include 'undefined'. (TS2366)
+
+Please fix all errors in a concise way."
+`;
+
+exports[`problem_prompt > createProblemFixPrompt > should handle realistic React TypeScript errors 1`] = `
+"Fix these 4 TypeScript compile-time errors:
+
+1. src/components/UserProfile.tsx:12:35 - Type '{ children: string; }' is missing the following properties from type 'UserProfileProps': user, onEdit (TS2739)
+2. src/components/UserProfile.tsx:25:15 - Object is possibly 'null'. (TS2531)
+3. src/hooks/useLocalStorage.ts:18:12 - Type 'string | null' is not assignable to type 'T'. (TS2322)
+4. src/types/api.ts:45:3 - Duplicate identifier 'UserRole'. (TS2300)
+
+Please fix all errors in a concise way."
+`;
+
+exports[`problem_prompt > createProblemFixPrompt > should return a message when no problems exist 1`] = `"No TypeScript problems detected."`;
+
+exports[`problem_prompt > realistic TypeScript error scenarios > should handle common React + TypeScript errors 1`] = `
+"Fix these 4 TypeScript compile-time errors:
+
+1. src/components/ProductCard.tsx:22:18 - Property 'price' is missing in type '{ name: string; description: string; }' but required in type 'Product'. (TS2741)
+2. src/components/SearchInput.tsx:15:45 - Type '(value: string) => void' is not assignable to type 'ChangeEventHandler'. (TS2322)
+3. src/api/userService.ts:8:1 - Function lacks ending return statement and return type does not include 'undefined'. (TS2366)
+4. src/utils/dataProcessor.ts:34:25 - Object is possibly 'undefined'. (TS2532)
+
+Please fix all errors in a concise way."
+`;
diff --git a/src/__tests__/problem_prompt.test.ts b/src/__tests__/problem_prompt.test.ts
new file mode 100644
index 0000000..60aa0cc
--- /dev/null
+++ b/src/__tests__/problem_prompt.test.ts
@@ -0,0 +1,214 @@
+import { describe, it, expect } from "vitest";
+import { createProblemFixPrompt } from "../shared/problem_prompt";
+import type { ProblemReport } from "../ipc/ipc_types";
+
+describe("problem_prompt", () => {
+ describe("createProblemFixPrompt", () => {
+ it("should return a message when no problems exist", () => {
+ const problemReport: ProblemReport = {
+ problems: [],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+
+ it("should format a single error correctly", () => {
+ const problemReport: ProblemReport = {
+ problems: [
+ {
+ file: "src/components/Button.tsx",
+ line: 15,
+ column: 23,
+ message: "Property 'onClick' does not exist on type 'ButtonProps'.",
+ code: 2339,
+ },
+ ],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+
+ it("should format multiple errors across multiple files", () => {
+ const problemReport: ProblemReport = {
+ problems: [
+ {
+ file: "src/components/Button.tsx",
+ line: 15,
+ column: 23,
+ message: "Property 'onClick' does not exist on type 'ButtonProps'.",
+ code: 2339,
+ },
+ {
+ file: "src/components/Button.tsx",
+ line: 8,
+ column: 12,
+ message:
+ "Type 'string | undefined' is not assignable to type 'string'.",
+ code: 2322,
+ },
+ {
+ file: "src/hooks/useApi.ts",
+ line: 42,
+ column: 5,
+ message:
+ "Argument of type 'unknown' is not assignable to parameter of type 'string'.",
+ code: 2345,
+ },
+ {
+ file: "src/utils/helpers.ts",
+ line: 45,
+ column: 8,
+ message:
+ "Function lacks ending return statement and return type does not include 'undefined'.",
+ code: 2366,
+ },
+ ],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+
+ it("should handle realistic React TypeScript errors", () => {
+ const problemReport: ProblemReport = {
+ problems: [
+ {
+ file: "src/components/UserProfile.tsx",
+ line: 12,
+ column: 35,
+ message:
+ "Type '{ children: string; }' is missing the following properties from type 'UserProfileProps': user, onEdit",
+ code: 2739,
+ },
+ {
+ file: "src/components/UserProfile.tsx",
+ line: 25,
+ column: 15,
+ message: "Object is possibly 'null'.",
+ code: 2531,
+ },
+ {
+ file: "src/hooks/useLocalStorage.ts",
+ line: 18,
+ column: 12,
+ message: "Type 'string | null' is not assignable to type 'T'.",
+ code: 2322,
+ },
+ {
+ file: "src/types/api.ts",
+ line: 45,
+ column: 3,
+ message: "Duplicate identifier 'UserRole'.",
+ code: 2300,
+ },
+ ],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+ });
+
+ describe("createConciseProblemFixPrompt", () => {
+ it("should return a short message when no problems exist", () => {
+ const problemReport: ProblemReport = {
+ problems: [],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+
+ it("should format a concise prompt for single error", () => {
+ const problemReport: ProblemReport = {
+ problems: [
+ {
+ file: "src/App.tsx",
+ line: 10,
+ column: 5,
+ message: "Cannot find name 'consol'. Did you mean 'console'?",
+ code: 2552,
+ },
+ ],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+
+ it("should format a concise prompt for multiple errors", () => {
+ const problemReport: ProblemReport = {
+ problems: [
+ {
+ file: "src/main.ts",
+ line: 5,
+ column: 12,
+ message:
+ "Cannot find module 'react-dom/client' or its corresponding type declarations.",
+ code: 2307,
+ },
+ {
+ file: "src/components/Modal.tsx",
+ line: 35,
+ column: 20,
+ message:
+ "Property 'isOpen' does not exist on type 'IntrinsicAttributes & ModalProps'.",
+ code: 2339,
+ },
+ ],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+ });
+
+ describe("realistic TypeScript error scenarios", () => {
+ it("should handle common React + TypeScript errors", () => {
+ const problemReport: ProblemReport = {
+ problems: [
+ // Missing interface property
+ {
+ file: "src/components/ProductCard.tsx",
+ line: 22,
+ column: 18,
+ message:
+ "Property 'price' is missing in type '{ name: string; description: string; }' but required in type 'Product'.",
+ code: 2741,
+ },
+ // Incorrect event handler type
+ {
+ file: "src/components/SearchInput.tsx",
+ line: 15,
+ column: 45,
+ message:
+ "Type '(value: string) => void' is not assignable to type 'ChangeEventHandler'.",
+ code: 2322,
+ },
+ // Async/await without Promise return type
+ {
+ file: "src/api/userService.ts",
+ line: 8,
+ column: 1,
+ message:
+ "Function lacks ending return statement and return type does not include 'undefined'.",
+ code: 2366,
+ },
+ // Strict null check
+ {
+ file: "src/utils/dataProcessor.ts",
+ line: 34,
+ column: 25,
+ message: "Object is possibly 'undefined'.",
+ code: 2532,
+ },
+ ],
+ };
+
+ const result = createProblemFixPrompt(problemReport);
+ expect(result).toMatchSnapshot();
+ });
+ });
+});
diff --git a/src/atoms/appAtoms.ts b/src/atoms/appAtoms.ts
index efa9309..384e217 100644
--- a/src/atoms/appAtoms.ts
+++ b/src/atoms/appAtoms.ts
@@ -7,7 +7,7 @@ export const selectedAppIdAtom = atom(null);
export const appsListAtom = atom([]);
export const appBasePathAtom = atom("");
export const versionsListAtom = atom([]);
-export const previewModeAtom = atom<"preview" | "code">("preview");
+export const previewModeAtom = atom<"preview" | "code" | "problems">("preview");
export const selectedVersionIdAtom = atom(null);
export const appOutputAtom = atom([]);
export const appUrlAtom = atom<
diff --git a/src/components/AutoFixProblemsSwitch.tsx b/src/components/AutoFixProblemsSwitch.tsx
new file mode 100644
index 0000000..3b68949
--- /dev/null
+++ b/src/components/AutoFixProblemsSwitch.tsx
@@ -0,0 +1,21 @@
+import { useSettings } from "@/hooks/useSettings";
+import { Label } from "@/components/ui/label";
+import { Switch } from "@/components/ui/switch";
+
+export function AutoFixProblemsSwitch() {
+ const { settings, updateSettings } = useSettings();
+ return (
+