diff --git a/README-UPDATE-SCRIPT.md b/README-UPDATE-SCRIPT.md
new file mode 100644
index 0000000..5df5134
--- /dev/null
+++ b/README-UPDATE-SCRIPT.md
@@ -0,0 +1,187 @@
+# MoreMinimore Update and Debranding Script
+
+This script (`scripts/update-and-debrand.sh`) automatically applies all custom features and removes Dyad branding/dependencies from the original Dyad codebase, converting it into MoreMinimore.
+
+## π Features Applied
+
+### Custom Features
+- β **Remove-limit feature** - Removes all usage limitations and restrictions
+- β **Smart Context for all users** - Previously Pro-only feature now available to everyone
+- β **Annotator tool for all users** - Previously Pro-only feature now available to everyone
+- β **No Pro upgrade buttons** - All Pro restrictions and upgrade prompts removed
+
+### Debranding Changes
+- β **Dyad β MoreMinimore** - Complete branding transformation
+- β **Component names updated** - All Dyad* components renamed to MoreMinimore*
+- β **URLs updated** - All dyad.sh links changed to moreminimore.com
+- β **Protocol handlers** - Custom `moreminimore://` protocol instead of `dyad://`
+- β **App metadata** - Title bar and app information updated
+
+### API Dependencies Removed
+- β **Dyad Template API** - Uses local templates only
+- β **Dyad Release Notes API** - Release notes check disabled
+- β **Dyad Auto-update API** - Auto-update functionality removed
+- β **Dyad Engine dependencies** - All Dyad Engine references removed
+
+### UI/UX Improvements
+- β **YouTube video section removed** - Cleaner setup experience
+- β **ProBanner commented out** - No Pro promotion banners
+- β **ProModeSelector removed** - Simplified chat controls
+- β **Context Settings button** - Improved UI text
+
+## π Usage
+
+### Quick Start
+```bash
+# Make the script executable
+chmod +x scripts/update-and-debrand.sh
+
+# Run the script
+./scripts/update-and-debrand.sh
+```
+
+### What the Script Does
+1. **Creates backup** - Automatic backup before making changes
+2. **Applies custom features** - Enables remove-limit and other features
+3. **Removes Dyad dependencies** - Eliminates all external API calls
+4. **Updates branding** - Complete Dyad β MoreMinimore transformation
+5. **Installs dependencies** - Updates package dependencies
+6. **Tests compilation** - Verifies TypeScript compilation
+
+### Safety Features
+- β **Automatic backup** - Creates timestamped backup directory
+- β **Error handling** - Script exits on any error
+- β **Compilation test** - Verifies code compiles successfully
+- β **Dependency check** - Ensures all dependencies are installed
+
+## π Update Workflow
+
+When you want to update your MoreMinimore with new features from the original Dyad repository:
+
+1. **Pull latest changes** from upstream Dyad repository
+2. **Run the script** to re-apply all customizations:
+ ```bash
+ ./scripts/update-and-debrand.sh
+ ```
+3. **Test the application** to ensure everything works:
+ ```bash
+ npm start
+ ```
+4. **Commit changes** if everything works correctly
+
+## π Backup System
+
+The script creates automatic backups with timestamp:
+```
+dyad-backup-YYYYMMDD-HHMMSS/
+βββ src/ # Source code backup
+βββ package.json # Package configuration
+βββ scripts/ # Scripts backup
+```
+
+## π οΈ Technical Details
+
+### Files Modified
+- `src/custom/index.ts` - Custom feature flags
+- `src/ipc/utils/template_utils.ts` - Template API removal
+- `src/ipc/handlers/release_note_handlers.ts` - Release notes API removal
+- `src/main.ts` - Auto-update and protocol handler updates
+- `src/ipc/utils/get_model_client.ts` - Dyad Engine removal
+- `src/ipc/ipc_host.ts` - Pro handlers removal
+- `src/preload.ts` - Pro IPC channels removal
+- `src/components/ChatInputControls.tsx` - ProModeSelector removal
+- `src/pages/home.tsx` - ProBanner commenting
+- `src/ipc/utils/smart_context_store.ts` - Smart context liberation
+- `src/ipc/shared/language_model_constants.ts` - Provider updates
+- `src/components/SetupBanner.tsx` - YouTube section removal
+- `src/app/TitleBar.tsx` - Title bar branding
+- `package.json` - App description
+- All component files - Dyad β MoreMinimore renaming
+- All files - URL updates and branding text
+
+### Key Features Liberated
+1. **Smart Context** - Advanced context management for all users
+2. **Annotator Tool** - Visual editing and annotation capabilities
+3. **Unlimited Usage** - No message limits or restrictions
+4. **Full Feature Access** - All Pro features available to everyone
+
+## π― Benefits
+
+### For Users
+- **No limitations** - Unlimited access to all features
+- **Better privacy** - No external API calls to Dyad services
+- **Full functionality** - All Pro features available
+- **Clean interface** - No upgrade prompts or restrictions
+
+### For Developers
+- **Easy updates** - Single script to re-apply all changes
+- **Safe modifications** - Automatic backup system
+- **Maintainable** - Clear separation of custom features
+- **Extensible** - Easy to add new custom features
+
+## π§ Troubleshooting
+
+### Common Issues
+
+#### TypeScript Compilation Errors
+```bash
+# Check TypeScript compilation
+npm run ts
+
+# If errors occur, check the backup and restore if needed
+cp -r dyad-backup-YYYYMMDD-HHMMSS/src ./src
+```
+
+#### Application Won't Start
+```bash
+# Check dependencies
+npm install
+
+# Rebuild the application
+npm run rebuild
+
+# Check logs for specific errors
+npm start
+```
+
+#### Script Permissions
+```bash
+# Make script executable
+chmod +x scripts/update-and-debrand.sh
+```
+
+### Manual Recovery
+If something goes wrong, you can always restore from the backup:
+```bash
+# Find your backup directory
+ls dyad-backup-*
+
+# Restore from backup
+cp -r dyad-backup-YYYYMMDD-HHMMSS/src ./src
+cp dyad-backup-YYYYMMDD-HHMMSS/package.json ./package.json
+```
+
+## π Customization
+
+### Adding New Custom Features
+1. Add your feature flag to `src/custom/index.ts`
+2. Implement the feature in the appropriate files
+3. Update the script to apply your changes automatically
+
+### Modifying the Script
+The script is organized into clear functions:
+- `apply_custom_features()` - Apply custom modifications
+- `remove_dyad_apis()` - Remove external dependencies
+- `update_branding()` - Update branding and names
+- `remove_pro_features()` - Remove Pro restrictions
+
+## π Result
+
+After running the script, you'll have:
+- **MoreMinimore** - Fully branded application
+- **No limitations** - All features available to all users
+- **No external dependencies** - Complete independence from Dyad APIs
+- **Clean interface** - No Pro upgrade prompts or restrictions
+- **Easy updates** - Simple script to re-apply changes
+
+The application will be ready to use with all custom features enabled and no Dyad branding or dependencies.
diff --git a/package.json b/package.json
index dddaf3d..3f6e99e 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "moreminimore",
"productName": "moreminimore",
"version": "0.31.0-beta.1",
- "description": "Free, local, open-source AI app builder",
+ "description": "MoreMinimore - AI-powered development environment",
"main": ".vite/build/main.js",
"repository": {
"type": "git",
diff --git a/scripts/update-and-debrand.sh b/scripts/update-and-debrand.sh
index fea60e3..d9c7d19 100755
--- a/scripts/update-and-debrand.sh
+++ b/scripts/update-and-debrand.sh
@@ -156,15 +156,8 @@ remove_pro_features() {
# Remove Pro restrictions from PreviewIframe (Annotator)
if [ -f "src/components/preview_panel/PreviewIframe.tsx" ]; then
- sed -i.bak '/import { AnnotatorOnlyForPro } from ".\/AnnotatorOnlyForPro";/d' src/components/preview_panel/PreviewIframe.tsx
- sed -i.bak '/{userBudget ? (/,/)} : (/,//c\
- ' src/components/preview_panel/PreviewIframe.tsx
- rm src/components/preview_panel/PreviewIframe.tsx.bak
- print_success "Removed Pro restrictions from Annotator"
+ # The file already uses Annotator directly, no Pro restrictions to remove
+ print_success "Annotator already available for all users"
fi
# Comment out ProBanner in home.tsx
@@ -314,6 +307,18 @@ remove_youtube_section() {
fi
}
+# Function to fix ChatInput.tsx references
+fix_chat_input() {
+ print_status "Fixing ChatInput.tsx references..."
+
+ if [ -f "src/components/chat/ChatInput.tsx" ]; then
+ # Update the Pro URL
+ sed -i.bak 's|https://dyad.sh/pro|https://moreminimore.com/pro|g' src/components/chat/ChatInput.tsx
+ rm src/components/chat/ChatInput.tsx.bak
+ print_success "Fixed ChatInput.tsx references"
+ fi
+}
+
# Function to update title bar and app metadata
update_app_metadata() {
print_status "Updating app metadata..."
@@ -400,6 +405,7 @@ main() {
update_branding_text
update_ai_providers
remove_youtube_section
+ fix_chat_input
update_app_metadata
cleanup_imports
install_dependencies
@@ -420,6 +426,7 @@ main() {
echo "β Updated branding text throughout app"
echo "β Updated AI provider settings"
echo "β Removed YouTube video section"
+ echo "β Fixed ChatInput.tsx references"
echo "β Updated app metadata and title bar"
echo "β Cleaned up unused imports"
echo "β Installed dependencies"
diff --git a/src/__tests__/chat_stream_handlers.test.ts b/src/__tests__/chat_stream_handlers.test.ts
index 5ddf638..14f1abb 100644
--- a/src/__tests__/chat_stream_handlers.test.ts
+++ b/src/__tests__/chat_stream_handlers.test.ts
@@ -1,16 +1,16 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import {
- getDyadWriteTags,
- getDyadRenameTags,
- getDyadAddDependencyTags,
- getDyadDeleteTags,
+ getMoreMinimoreWriteTags,
+ getMoreMinimoreRenameTags,
+ getMoreMinimoreAddDependencyTags,
+ getMoreMinimoreDeleteTags,
} from "../ipc/utils/dyad_tag_parser";
import { processFullResponseActions } from "../ipc/processors/response_processor";
import {
- removeDyadTags,
- hasUnclosedDyadWrite,
+ removeMoreMinimoreTags,
+ hasUnclosedMoreMinimoreWrite,
} from "../ipc/handlers/chat_stream_handlers";
import fs from "node:fs";
import { db } from "../db";
@@ -58,9 +58,9 @@ vi.mock("../ipc/utils/git_utils", () => ({
getGitUncommittedFiles: vi.fn().mockResolvedValue([]),
}));
-// Mock paths module to control getDyadAppPath
+// Mock paths module to control getMoreMinimoreAppPath
vi.mock("../paths/paths", () => ({
- getDyadAppPath: vi.fn().mockImplementation((appPath) => {
+ getMoreMinimoreAppPath: vi.fn().mockImplementation((appPath) => {
return `/mock/user/data/path/${appPath}`;
}),
getUserDataPath: vi.fn().mockReturnValue("/mock/user/data/path"),
@@ -85,49 +85,49 @@ vi.mock("../db", () => ({
},
}));
-describe("getDyadAddDependencyTags", () => {
+describe("getMoreMinimoreAddDependencyTags", () => {
it("should return an empty array when no dyad-add-dependency tags are found", () => {
- const result = getDyadAddDependencyTags("No dyad-add-dependency tags here");
+ const result = getMoreMinimoreAddDependencyTags("No dyad-add-dependency tags here");
expect(result).toEqual([]);
});
it("should return an array of dyad-add-dependency tags", () => {
- const result = getDyadAddDependencyTags(
+ const result = getMoreMinimoreAddDependencyTags(
``,
);
expect(result).toEqual(["uuid"]);
});
it("should return all the packages in the dyad-add-dependency tags", () => {
- const result = getDyadAddDependencyTags(
+ const result = getMoreMinimoreAddDependencyTags(
``,
);
expect(result).toEqual(["pkg1", "pkg2"]);
});
it("should return all the packages in the dyad-add-dependency tags", () => {
- const result = getDyadAddDependencyTags(
+ const result = getMoreMinimoreAddDependencyTags(
`txt beforetext after`,
);
expect(result).toEqual(["pkg1", "pkg2"]);
});
it("should return all the packages in multiple dyad-add-dependency tags", () => {
- const result = getDyadAddDependencyTags(
+ const result = getMoreMinimoreAddDependencyTags(
`txt beforetxt betweentext after`,
);
expect(result).toEqual(["pkg1", "pkg2", "pkg3"]);
});
});
-describe("getDyadWriteTags", () => {
+describe("getMoreMinimoreWriteTags", () => {
it("should return an empty array when no dyad-write tags are found", () => {
- const result = getDyadWriteTags("No dyad-write tags here");
+ const result = getMoreMinimoreWriteTags("No dyad-write tags here");
expect(result).toEqual([]);
});
it("should return a dyad-write tag", () => {
const result =
- getDyadWriteTags(`
+ getMoreMinimoreWriteTags(`
import React from "react";
console.log("TodoItem");
`);
@@ -143,7 +143,7 @@ console.log("TodoItem");`,
it("should strip out code fence (if needed) from a dyad-write tag", () => {
const result =
- getDyadWriteTags(`
+ getMoreMinimoreWriteTags(`
\`\`\`tsx
import React from "react";
console.log("TodoItem");
@@ -161,7 +161,7 @@ console.log("TodoItem");`,
});
it("should handle missing description", () => {
- const result = getDyadWriteTags(`
+ const result = getMoreMinimoreWriteTags(`
import React from 'react';
@@ -176,7 +176,7 @@ import React from 'react';
});
it("should handle extra space", () => {
- const result = getDyadWriteTags(
+ const result = getMoreMinimoreWriteTags(
cleanFullResponse(`
import React from 'react';
@@ -193,7 +193,7 @@ import React from 'react';
});
it("should handle nested tags", () => {
- const result = getDyadWriteTags(
+ const result = getMoreMinimoreWriteTags(
cleanFullResponse(`
BEFORE TAG
@@ -223,7 +223,7 @@ AFTER TAG
const cleanedInput = cleanFullResponse(inputWithNestedTags);
- const result = getDyadWriteTags(cleanedInput);
+ const result = getMoreMinimoreWriteTags(cleanedInput);
expect(result).toEqual([
{
path: "src/pages/locations/neighborhoods/louisville/Highlands.tsx",
@@ -238,7 +238,7 @@ AFTER TAG
// This simulates what cleanFullResponse should do
const cleanedInput = cleanFullResponse(inputWithMultipleNestedTags);
- const result = getDyadWriteTags(cleanedInput);
+ const result = getMoreMinimoreWriteTags(cleanedInput);
expect(result).toEqual([
{
path: "src/file.tsx",
@@ -254,7 +254,7 @@ AFTER TAG
// This simulates what cleanFullResponse should do
const cleanedInput = cleanFullResponse(inputWithNestedInMultipleAttrs);
- const result = getDyadWriteTags(cleanedInput);
+ const result = getMoreMinimoreWriteTags(cleanedInput);
expect(result).toEqual([
{
path: "src/οΌcomponentοΌ.tsx",
@@ -265,7 +265,7 @@ AFTER TAG
});
it("should return an array of dyad-write tags", () => {
- const result = getDyadWriteTags(
+ const result = getMoreMinimoreWriteTags(
`I'll create a simple todo list app using React, TypeScript, and shadcn/ui components. Let's get started!
First, I'll create the necessary files for our todo list application:
@@ -597,14 +597,14 @@ I've created a complete todo list application with the ability to add, complete,
});
});
-describe("getDyadRenameTags", () => {
+describe("getMoreMinimoreRenameTags", () => {
it("should return an empty array when no dyad-rename tags are found", () => {
- const result = getDyadRenameTags("No dyad-rename tags here");
+ const result = getMoreMinimoreRenameTags("No dyad-rename tags here");
expect(result).toEqual([]);
});
it("should return an array of dyad-rename tags", () => {
- const result = getDyadRenameTags(
+ const result = getMoreMinimoreRenameTags(
``,
);
@@ -618,14 +618,14 @@ describe("getDyadRenameTags", () => {
});
});
-describe("getDyadDeleteTags", () => {
+describe("getMoreMinimoreDeleteTags", () => {
it("should return an empty array when no dyad-delete tags are found", () => {
- const result = getDyadDeleteTags("No dyad-delete tags here");
+ const result = getMoreMinimoreDeleteTags("No dyad-delete tags here");
expect(result).toEqual([]);
});
it("should return an array of dyad-delete paths", () => {
- const result = getDyadDeleteTags(
+ const result = getMoreMinimoreDeleteTags(
``,
);
@@ -963,39 +963,39 @@ describe("processFullResponse", () => {
});
});
-describe("removeDyadTags", () => {
+describe("removeMoreMinimoreTags", () => {
it("should return empty string when input is empty", () => {
- const result = removeDyadTags("");
+ const result = removeMoreMinimoreTags("");
expect(result).toBe("");
});
it("should return the same text when no dyad tags are present", () => {
const text = "This is a regular text without any dyad tags.";
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe(text);
});
it("should remove a single dyad-write tag", () => {
const text = `Before text console.log('hello'); After text`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Before text After text");
});
it("should remove a single dyad-delete tag", () => {
const text = `Before text After text`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Before text After text");
});
it("should remove a single dyad-rename tag", () => {
const text = `Before text After text`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Before text After text");
});
it("should remove multiple different dyad tags", () => {
const text = `Start code here middle end finish`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Start middle end finish");
});
@@ -1011,19 +1011,19 @@ const Component = () => {
export default Component;
After`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Before\n\nAfter");
});
it("should handle dyad tags with complex attributes", () => {
const text = `Text const x = "hello world"; more text`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Text more text");
});
it("should remove dyad tags and trim whitespace", () => {
const text = ` code `;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("");
});
@@ -1032,19 +1032,19 @@ After`;
const html = '
Hello
';
const component = ;
`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("");
});
it("should handle self-closing dyad tags", () => {
const text = `Before After`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe('Before After');
});
it("should handle malformed dyad tags gracefully", () => {
const text = `Before unclosed tag After`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe('Before unclosed tag After');
});
@@ -1053,51 +1053,51 @@ const component = ;
const regex = /
]*>.*?
/g;
const special = "Special chars: @#$%^&*()[]{}|\\";
`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("");
});
it("should handle multiple dyad tags of the same type", () => {
const text = `code1 between code2`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("between");
});
it("should handle dyad tags with custom tag names", () => {
const text = `Before content After`;
- const result = removeDyadTags(text);
+ const result = removeMoreMinimoreTags(text);
expect(result).toBe("Before After");
});
});
-describe("hasUnclosedDyadWrite", () => {
+describe("hasUnclosedMoreMinimoreWrite", () => {
it("should return false when there are no dyad-write tags", () => {
const text = "This is just regular text without any dyad tags.";
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(false);
});
it("should return false when dyad-write tag is properly closed", () => {
const text = `console.log('hello');`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(false);
});
it("should return true when dyad-write tag is not closed", () => {
const text = `console.log('hello');`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(true);
});
it("should return false when dyad-write tag with attributes is properly closed", () => {
const text = `console.log('hello');`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(false);
});
it("should return true when dyad-write tag with attributes is not closed", () => {
const text = `console.log('hello');`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(true);
});
@@ -1105,7 +1105,7 @@ describe("hasUnclosedDyadWrite", () => {
const text = `code1
Some text in between
code2`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(false);
});
@@ -1113,7 +1113,7 @@ describe("hasUnclosedDyadWrite", () => {
const text = `code1
Some text in between
code2`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(true);
});
@@ -1121,7 +1121,7 @@ describe("hasUnclosedDyadWrite", () => {
const text = `code1
Some text in between
code2`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(false);
});
@@ -1139,7 +1139,7 @@ const Component = () => {
export default Component;
`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(false);
});
@@ -1156,7 +1156,7 @@ const Component = () => {
};
export default Component;`;
- const result = hasUnclosedDyadWrite(text);
+ const result = hasUnclosedMoreMinimoreWrite(text);
expect(result).toBe(true);
});
@@ -1165,7 +1165,7 @@ export default Component;`;
const message = "Hello 'world'";
const regex = /