6 Commits

Author SHA1 Message Date
Aaron Elijah Mars
99d31b15c8 Update opendia.dxt to version 1.0.5
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 22:11:29 +02:00
Aaron Elijah Mars
a83df06513 Bump version to 1.0.5 and update installation instructions
- Update version to 1.0.5 in all package files and build script
- Add double-click .dxt installation as recommended option in README
- Keep npx option as alternative installation method

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 22:11:00 +02:00
Aaron Elijah Mars
05559b8b1d styling features 2025-07-15 20:15:02 +02:00
Aaron Elijah Mars
ca1a88776d bulk tabs (open + query + act) 2025-07-15 19:52:39 +02:00
Aaron Elijah Mars
14be38dd16 safety mode 2025-07-15 17:43:08 +02:00
Aaron Elijah Mars
aa78576ad7 autokill port + prompts 2025-07-15 17:33:03 +02:00
11 changed files with 2657 additions and 111 deletions

View File

@@ -69,6 +69,13 @@ Perfect for **Cursor users** who want to automate their local testing and develo
- **"Monitor this webpage and notify me when the content changes"** - **"Monitor this webpage and notify me when the content changes"**
- **"Automatically bookmark interesting articles I'm reading"** - **"Automatically bookmark interesting articles I'm reading"**
### 🎨 Visual Customization & Fun
- **"Apply a cyberpunk theme to this documentation site to make it more engaging"**
- **"Make this page dark mode with green text for late-night reading"**
- **"Add rainbow party effects to celebrate finishing this project"**
- **"Transform this boring form with a retro 80s theme while I fill it out"**
- **"Use high contrast styling so I can read this better"**
## ⚡ Quick Start ## ⚡ Quick Start
### 1. Install the Browser Extension ### 1. Install the Browser Extension
@@ -78,7 +85,14 @@ Perfect for **Cursor users** who want to automate their local testing and develo
4. Click "Load unpacked" and select the extension folder 4. Click "Load unpacked" and select the extension folder
### 2. Connect to Your AI ### 2. Connect to Your AI
**For Claude Desktop**, add to your configuration:
**Option 1: Double-click Installation (Recommended)**
1. Download the `opendia.dxt` file from [releases](https://github.com/aaronjmars/opendia/releases)
2. Double-click the `.dxt` file to install automatically
3. The MCP will be added to your Claude Desktop configuration
**Option 2: Manual Configuration**
Add to your Claude Desktop configuration:
```json ```json
{ {
"mcpServers": { "mcpServers": {
@@ -109,7 +123,7 @@ npx opendia --port=6000 # Uses 6000 (WebSocket) + 6001 (HTTP)
npx opendia --ws-port=5555 --http-port=5556 # Specify individually npx opendia --ws-port=5555 --http-port=5556 # Specify individually
# Handle port conflicts # Handle port conflicts
npx opendia --kill-existing # Safely terminate existing OpenDia processes # Note: Existing OpenDia processes are automatically terminated on startup
``` ```
### Auto-Tunnel Mode ### Auto-Tunnel Mode
@@ -152,7 +166,7 @@ ngrok config add-authtoken YOUR_TOKEN_HERE
## 🛠️ Capabilities ## 🛠️ Capabilities
OpenDia gives AI models **17 powerful browser tools**: OpenDia gives AI models **18 powerful browser tools**:
### 🎯 Smart Page Understanding ### 🎯 Smart Page Understanding
- **Analyze any webpage** - AI automatically finds buttons, forms, and interactive elements - **Analyze any webpage** - AI automatically finds buttons, forms, and interactive elements
@@ -180,6 +194,13 @@ OpenDia gives AI models **17 powerful browser tools**:
- **Natural interactions** - Mimics human behavior to avoid triggering security measures - **Natural interactions** - Mimics human behavior to avoid triggering security measures
- **Reliable automation** - Works consistently even on sites that block typical automation tools - **Reliable automation** - Works consistently even on sites that block typical automation tools
### 🎨 Page Styling & Customization
- **Transform any website** - Apply fun themes, custom colors, and visual effects
- **Preset themes** - Dark hacker, retro 80s, rainbow party, minimalist zen, and more
- **AI mood styling** - Describe a mood and get matching visual design
- **Interactive effects** - Matrix rain, floating particles, neon glow, and cursor trails
- **Accessibility themes** - High contrast and readable designs for better visibility
## 💬 Example Prompts to Try ## 💬 Example Prompts to Try
Once everything is set up, try asking your AI: Once everything is set up, try asking your AI:
@@ -202,6 +223,15 @@ Once everything is set up, try asking your AI:
**Personal Assistant:** **Personal Assistant:**
> *"Find that GitHub repo I was looking at yesterday about React components and bookmark it for later"* > *"Find that GitHub repo I was looking at yesterday about React components and bookmark it for later"*
**Page Styling & Fun:**
> *"Apply a dark hacker theme to this page to make it look more interesting"*
> *"Make this boring documentation page feel like a cozy coffee shop"*
> *"Add some matrix rain effects to this page for 30 seconds for a cool screenshot"*
> *"Transform this page with a high contrast theme for better readability"*
## 🏗️ How It Works ## 🏗️ How It Works
```mermaid ```mermaid

380
build-dxt.sh Executable file
View File

@@ -0,0 +1,380 @@
#!/bin/bash
# OpenDia DXT Build Script - Fixed Version
# Run this from the OpenDia project root directory
set -e # Exit on any error
echo "🚀 Building OpenDia DXT package..."
# Check if we're in the right directory
if [ ! -f "opendia-mcp/package.json" ]; then
echo "❌ Error: Please run this script from the OpenDia project root directory"
echo " Expected to find: opendia-mcp/package.json"
echo " Current directory: $(pwd)"
exit 1
fi
if [ ! -d "opendia-extension" ]; then
echo "❌ Error: opendia-extension directory not found"
exit 1
fi
# Clean and create dist directory
echo "🧹 Cleaning previous build..."
rm -rf dist
mkdir -p dist/opendia-dxt
echo "📦 Setting up package..."
# Copy server files
cp opendia-mcp/server.js dist/opendia-dxt/
# Create optimized package.json for DXT
cat > dist/opendia-dxt/package.json << 'EOF'
{
"name": "opendia",
"version": "1.0.5",
"description": "🎯 OpenDia - The open alternative to Dia. Connect your browser to AI models with anti-detection bypass for Twitter/X, LinkedIn, Facebook",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"keywords": [
"mcp",
"browser",
"automation",
"ai",
"claude",
"chrome",
"extension",
"twitter",
"linkedin",
"facebook",
"anti-detection",
"dxt"
],
"author": "Aaron Elijah Mars <aaronjmars@proton.me>",
"license": "MIT",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.21.2",
"ws": "^8.18.0"
},
"engines": {
"node": ">=16.0.0"
}
}
EOF
# Install dependencies
echo "⬇️ Installing dependencies..."
cd dist/opendia-dxt
npm install --production --silent
cd ../..
# Copy browser extension
echo "🌐 Copying browser extension..."
cp -r opendia-extension dist/opendia-dxt/extension
# Copy logo/icon files for DXT - try multiple sources
echo "🎨 Copying logo files..."
LOGO_COPIED=false
# Try different icon files from the extension
for icon_file in "icon-128.png" "icon-48.png" "icon-32.png" "icon-16.png" "icon.png"; do
if [ -f "opendia-extension/$icon_file" ]; then
cp "opendia-extension/$icon_file" dist/opendia-dxt/icon.png
echo "✅ Logo copied from extension/$icon_file"
LOGO_COPIED=true
break
fi
done
# If no extension icon found, check root directory
if [ "$LOGO_COPIED" = false ]; then
for icon_file in "icon.png" "logo.png" "opendia.png"; do
if [ -f "$icon_file" ]; then
cp "$icon_file" dist/opendia-dxt/icon.png
echo "✅ Logo copied from $icon_file"
LOGO_COPIED=true
break
fi
done
fi
# Create a simple placeholder if no icon found
if [ "$LOGO_COPIED" = false ]; then
echo "⚠️ No logo file found, you may need to add icon.png manually to dist/opendia-dxt/"
fi
# Create DXT manifest - CORRECT FORMAT BASED ON WORKING EXAMPLES
echo "📋 Creating DXT manifest..."
cat > dist/opendia-dxt/manifest.json << 'EOF'
{
"dxt_version": "0.1",
"name": "opendia",
"display_name": "OpenDia - Browser Automation",
"version": "1.0.5",
"description": "🎯 OpenDia - The open alternative to Dia. Connect your browser to AI models with anti-detection bypass for Twitter/X, LinkedIn, Facebook + universal automation",
"author": {
"name": "Aaron Elijah Mars",
"email": "aaronjmars@proton.me",
"url": "https://github.com/aaronjmars/opendia"
},
"homepage": "https://github.com/aaronjmars/opendia",
"license": "MIT",
"keywords": ["browser", "automation", "mcp", "ai", "claude", "chrome", "extension", "twitter", "linkedin", "facebook", "anti-detection"],
"icon": "icon.png",
"icons": {
"128": "icon.png"
},
"server": {
"type": "node",
"entry_point": "server.js",
"mcp_config": {
"command": "node",
"args": ["${__dirname}/server.js"],
"env": {
"NODE_ENV": "production",
"WS_PORT": "${user_config.ws_port}",
"HTTP_PORT": "${user_config.http_port}",
"ENABLE_TUNNEL": "${user_config.enable_tunnel}",
"SAFETY_MODE": "${user_config.safety_mode}"
}
}
},
"user_config": {
"ws_port": {
"type": "number",
"title": "WebSocket Port",
"description": "Port for Chrome extension connection",
"default": 5555,
"minimum": 1024,
"maximum": 65535
},
"http_port": {
"type": "number",
"title": "HTTP Port",
"description": "Port for HTTP/SSE server",
"default": 5556,
"minimum": 1024,
"maximum": 65535
},
"enable_tunnel": {
"type": "boolean",
"title": "Auto-Tunnel",
"description": "Automatically create ngrok tunnel for online AI access (requires ngrok)",
"default": false
},
"safety_mode": {
"type": "boolean",
"title": "Safety Mode",
"description": "Block write/edit tools (element_click, element_fill) by default",
"default": false
}
},
"tools": [
{
"name": "page_analyze",
"description": "🔍 Analyze any tab without switching! Two-phase intelligent page analysis"
},
{
"name": "page_extract_content",
"description": "📄 Extract content from any tab without switching!"
},
{
"name": "element_click",
"description": "🖱️ Click elements with anti-detection bypass for social platforms"
},
{
"name": "element_fill",
"description": "✏️ Fill forms with anti-detection bypass for Twitter/X, LinkedIn, Facebook"
},
{
"name": "page_navigate",
"description": "🧭 Navigate to URLs with wait conditions"
},
{
"name": "page_wait_for",
"description": "⏳ Wait for elements or conditions"
},
{
"name": "tab_create",
"description": "📱 Create single or multiple tabs with batch support"
},
{
"name": "tab_close",
"description": "❌ Close specific tab(s) by ID"
},
{
"name": "tab_list",
"description": "📋 Get list of all open tabs with IDs"
},
{
"name": "tab_switch",
"description": "🔄 Switch to specific tab by ID"
},
{
"name": "element_get_state",
"description": "🔍 Get detailed element state information"
},
{
"name": "get_bookmarks",
"description": "📚 Get all bookmarks or search for specific ones"
},
{
"name": "add_bookmark",
"description": " Add new bookmark"
},
{
"name": "get_history",
"description": "🕒 Search browser history with comprehensive filters"
},
{
"name": "get_selected_text",
"description": "📝 Get selected text from any tab"
},
{
"name": "page_scroll",
"description": "📜 Scroll any tab without switching"
},
{
"name": "get_page_links",
"description": "🔗 Get all hyperlinks with smart filtering"
},
{
"name": "page_style",
"description": "🎨 Transform page appearance with themes and effects"
}
],
"capabilities": {
"browser_automation": true,
"anti_detection": true,
"background_tabs": true,
"multi_tab_workflows": true,
"content_extraction": true,
"form_filling": true,
"social_media_posting": true,
"page_styling": true,
"bookmark_management": true,
"history_search": true,
"tab_management": true
},
"requirements": {
"chrome_extension": {
"name": "OpenDia Browser Extension",
"description": "Required Chrome extension for browser automation by Aaron Elijah Mars",
"version": "1.0.5",
"auto_install": false
}
}
}
EOF
# Validate JSON syntax
echo "🔍 Validating manifest.json..."
if ! python3 -m json.tool dist/opendia-dxt/manifest.json > /dev/null 2>&1; then
echo "❌ Error: Invalid JSON in manifest.json"
exit 1
fi
echo "✅ Manifest JSON is valid"
# Copy documentation
echo "📝 Adding documentation..."
cp README.md dist/opendia-dxt/ 2>/dev/null || echo "⚠️ README.md not found, skipping"
cp LICENSE dist/opendia-dxt/ 2>/dev/null || echo "⚠️ LICENSE not found, skipping"
# Create extension installation guide
cat > dist/opendia-dxt/EXTENSION_INSTALL.md << 'EOF'
# OpenDia Chrome Extension Installation
## Quick Setup
1. **Enable Developer Mode**
- Go to `chrome://extensions/`
- Toggle "Developer mode" in the top right
2. **Install Extension**
- Click "Load unpacked"
- Select the `extension/` folder from this DXT package
- Extension should appear in your extensions list
3. **Verify Connection**
- Click the OpenDia extension icon
- Should show "Connected to MCP server"
- Green status indicator means ready to use
## Supported Browsers
- Google Chrome, Arc Browser, Microsoft Edge, Brave Browser, Opera
- Any Chromium-based browser
## Features
🎯 Anti-detection bypass for Twitter/X, LinkedIn, Facebook
📱 Smart automation and page analysis
🔧 Form filling with enhanced compatibility
📊 Multi-tab workflows and background operations
🎨 Page styling and visual customization
For more help, visit: https://github.com/aaronjmars/opendia
EOF
# Verify structure before zipping
echo "🔍 Verifying DXT structure..."
echo "📋 Files in DXT directory:"
ls -la dist/opendia-dxt/
# Check if icon exists and show its details
if [ -f "dist/opendia-dxt/icon.png" ]; then
echo "✅ Icon file found:"
file dist/opendia-dxt/icon.png
ls -lh dist/opendia-dxt/icon.png
else
echo "❌ Icon file missing!"
fi
# Verify manifest.json exists and is at root level
if [ ! -f "dist/opendia-dxt/manifest.json" ]; then
echo "❌ Error: manifest.json not found!"
exit 1
fi
echo "✅ Structure verified"
# Create the DXT archive - CRITICAL: ZIP from inside the directory
echo "🗜️ Creating DXT archive..."
cd dist/opendia-dxt
zip -r ../opendia.dxt . -q
cd ../..
# Verify the DXT file structure
echo "🔍 Verifying DXT file contents..."
if ! unzip -l dist/opendia.dxt | grep -q "manifest.json"; then
echo "❌ Error: manifest.json not found in DXT file!"
echo "DXT contents:"
unzip -l dist/opendia.dxt
exit 1
fi
# Get file size
DXT_SIZE=$(du -h dist/opendia.dxt | cut -f1)
echo ""
echo "✅ DXT package created successfully!"
echo "📦 File: dist/opendia.dxt"
echo "💾 Size: $DXT_SIZE"
echo ""
echo "📋 DXT Contents:"
unzip -l dist/opendia.dxt | head -10
echo ""
echo "🚀 Installation:"
echo "1. Double-click the .dxt file"
echo "2. Or: Claude Desktop Settings → Extensions → Install Extension"
echo "3. Install Chrome extension from extension/ folder"
echo ""
echo "🎯 Features ready: Anti-detection bypass + universal automation"

File diff suppressed because it is too large Load Diff

View File

@@ -283,6 +283,13 @@ class BrowserAutomation {
case "page_scroll": case "page_scroll":
result = await this.scrollPage(data); result = await this.scrollPage(data);
break; break;
case "page_style":
result = await this.handlePageStyle(data);
break;
case "ping":
// Health check for background tab content script readiness
result = { status: "ready", timestamp: Date.now(), url: window.location.href };
break;
default: default:
throw new Error(`Unknown action: ${action}`); throw new Error(`Unknown action: ${action}`);
} }
@@ -2503,7 +2510,375 @@ class BrowserAutomation {
}; };
} }
} }
// 🎨 Page Styling System
async handlePageStyle(data) {
const { mode, theme, background, text_color, font, font_size, mood, intensity, effect, duration, remember } = data;
// Remove existing custom styles
const existingStyle = document.getElementById('opendia-custom-style');
if (existingStyle) existingStyle.remove();
let css = '';
let description = '';
try {
switch (mode) {
case 'preset':
const themeData = THEME_PRESETS[theme];
if (!themeData) throw new Error(`Unknown theme: ${theme}`);
css = themeData.css;
description = `Applied ${themeData.name} theme`;
break;
case 'custom':
css = this.buildCustomCSS({ background, text_color, font, font_size });
description = 'Applied custom styling';
break;
case 'ai_mood':
css = this.generateMoodCSS(mood, intensity);
description = `Applied AI-generated style for mood: "${mood}"`;
break;
case 'effect':
css = this.applyEffect(effect, duration);
description = `Applied ${effect} effect for ${duration}s`;
break;
case 'reset':
// CSS already removed above
description = 'Reset page to original styling';
break;
default:
throw new Error(`Unknown styling mode: ${mode}`);
}
if (css) {
const styleElement = document.createElement('style');
styleElement.id = 'opendia-custom-style';
styleElement.textContent = css;
document.head.appendChild(styleElement);
}
// Remember preference if requested
if (remember && mode !== 'reset') {
const domain = window.location.hostname;
chrome.storage.local.set({ [`style_${domain}`]: { mode, theme, css } });
}
return {
success: true,
description,
applied_css: css.length,
mode,
theme: theme || 'custom',
remember_enabled: remember,
effect_duration: duration,
mood,
intensity
};
} catch (error) {
return {
success: false,
error: error.message,
mode,
theme,
applied_css: 0
};
}
}
buildCustomCSS({ background, text_color, font, font_size }) {
let css = '';
if (background || text_color || font || font_size) {
css += '* { ';
if (background) css += `background: ${background} !important; `;
if (text_color) css += `color: ${text_color} !important; `;
if (font) css += `font-family: ${font} !important; `;
if (font_size) css += `font-size: ${font_size} !important; `;
css += '}';
}
return css;
}
generateMoodCSS(mood, intensity) {
const moodMap = {
'cozy coffee shop': {
background: '#2c1810',
text: '#f4e4bc',
accent: '#d4af37',
font: 'Georgia, serif'
},
'energetic': {
background: 'linear-gradient(45deg, #ff6b35, #f7931e)',
text: '#ffffff',
effects: 'animation: energyPulse 1s infinite;'
},
'calm ocean': {
background: 'linear-gradient(to bottom, #87ceeb, #4682b4)',
text: '#ffffff',
effects: 'animation: gentleWave 4s ease-in-out infinite;'
},
'dark professional': {
background: '#1a1a1a',
text: '#e0e0e0',
accent: '#0066cc'
},
'warm sunset': {
background: 'linear-gradient(to bottom, #ff7e5f, #feb47b)',
text: '#ffffff'
}
};
const style = moodMap[mood.toLowerCase()] || moodMap['cozy coffee shop'];
return this.buildMoodCSS(style, intensity);
}
buildMoodCSS(style, intensity) {
const opacity = intensity === 'subtle' ? '0.3' : intensity === 'medium' ? '0.6' : '0.9';
let css = `
body {
background: ${style.background} !important;
color: ${style.text} !important;
${style.font ? `font-family: ${style.font} !important;` : ''}
}
* {
color: ${style.text} !important;
}
a {
color: ${style.accent || style.text} !important;
}
`;
if (style.effects) {
css += style.effects;
}
// Add animation keyframes if needed
if (style.effects && style.effects.includes('energyPulse')) {
css += `
@keyframes energyPulse {
0%, 100% { filter: hue-rotate(0deg); }
50% { filter: hue-rotate(180deg); }
}
`;
}
if (style.effects && style.effects.includes('gentleWave')) {
css += `
@keyframes gentleWave {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
`;
}
return css;
}
applyEffect(effect, duration) {
const effects = {
matrix_rain: `
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y="10" font-size="8" fill="%2300ff00">0</text><text y="20" font-size="8" fill="%2300ff00">1</text><text y="30" font-size="8" fill="%2300ff00">0</text><text y="40" font-size="8" fill="%2300ff00">1</text></svg>');
animation: matrixFall 2s linear infinite;
pointer-events: none;
z-index: 9999;
opacity: 0.7;
}
@keyframes matrixFall {
from { transform: translateY(-100px); }
to { transform: translateY(100vh); }
}
`,
floating_particles: `
body::before {
content: '✨ 🌟 ⭐ 💫';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
animation: floatParticles 6s ease-in-out infinite;
pointer-events: none;
z-index: 9999;
font-size: 20px;
}
@keyframes floatParticles {
0%, 100% { transform: translateY(100vh) rotate(0deg); }
50% { transform: translateY(-100px) rotate(180deg); }
}
`,
cursor_trail: `
body {
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><circle cx="10" cy="10" r="8" fill="rgba(255,0,255,0.5)"/></svg>'), auto !important;
}
`,
neon_glow: `
* {
text-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff, 0 0 30px #00ffff !important;
}
a, button {
box-shadow: 0 0 15px #ff00ff !important;
}
`,
typing_effect: `
* {
animation: typewriter 2s steps(40, end) infinite !important;
}
@keyframes typewriter {
from { width: 0; }
to { width: 100%; }
}
`
};
const css = effects[effect] || '';
// Auto-remove effect after duration
if (duration && duration > 0) {
setTimeout(() => {
const effectStyle = document.getElementById('opendia-custom-style');
if (effectStyle) effectStyle.remove();
}, duration * 1000);
}
return css;
}
} }
// Theme Presets Database
const THEME_PRESETS = {
"dark_hacker": {
name: "🖤 Dark Hacker",
css: `
* {
background: #0a0a0a !important;
color: #00ff00 !important;
font-family: 'Courier New', monospace !important;
}
a { color: #00ffff !important; }
body::before {
content: ''; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y="50" font-size="10" fill="%23003300">01010101</text></svg>');
opacity: 0.1; pointer-events: none; z-index: -1;
}
`
},
"retro_80s": {
name: "📼 Retro 80s",
css: `
* {
background: linear-gradient(45deg, #ff0080, #8000ff) !important;
color: #ffffff !important;
font-family: 'Arial Black', sans-serif !important;
text-shadow: 2px 2px 4px #000000 !important;
}
body { animation: retroPulse 2s infinite; }
@keyframes retroPulse { 0%, 100% { filter: hue-rotate(0deg); } 50% { filter: hue-rotate(180deg); } }
`
},
"rainbow_party": {
name: "🌈 Rainbow Party",
css: `
body {
background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) !important;
background-size: 400% 400% !important;
animation: rainbowShift 3s ease infinite !important;
}
@keyframes rainbowShift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
* { color: white !important; text-shadow: 1px 1px 2px black !important; }
`
},
"minimalist_zen": {
name: "🧘 Minimalist Zen",
css: `
* {
background: #f8f8f8 !important;
color: #333333 !important;
font-family: 'Georgia', serif !important;
line-height: 1.6 !important;
}
body { max-width: 800px; margin: 0 auto; padding: 20px; }
`
},
"high_contrast": {
name: "🔍 High Contrast",
css: `
* {
background: #000000 !important;
color: #ffffff !important;
font-family: Arial, sans-serif !important;
font-weight: bold !important;
}
a { color: #ffff00 !important; }
`
},
"cyberpunk": {
name: "🤖 Cyberpunk",
css: `
* {
background: #0d1117 !important;
color: #ff006e !important;
font-family: 'Courier New', monospace !important;
}
a { color: #00ffff !important; }
body {
background-image:
linear-gradient(90deg, transparent 79px, #abced4 79px, #abced4 81px, transparent 81px),
linear-gradient(#eee .1em, transparent .1em);
background-size: 81px 1.2em;
}
`
},
"pastel_dream": {
name: "🌸 Pastel Dream",
css: `
* {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: #2c3e50 !important;
font-family: 'Comic Sans MS', cursive !important;
}
body { filter: sepia(20%) saturate(80%); }
`
},
"newspaper": {
name: "📰 Newspaper",
css: `
* {
background: #ffffff !important;
color: #000000 !important;
font-family: 'Times New Roman', serif !important;
line-height: 1.4 !important;
}
body {
column-count: 2;
column-gap: 2em;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
`
}
};
// Initialize the automation system // Initialize the automation system
const browserAutomation = new BrowserAutomation(); const browserAutomation = new BrowserAutomation();

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "OpenDia", "name": "OpenDia",
"version": "1.0.4", "version": "1.0.5",
"description": "Browser automation through Model Context Protocol", "description": "Browser automation through Model Context Protocol",
"icons": { "icons": {
"16": "icon-16.png", "16": "icon-16.png",

View File

@@ -236,6 +236,80 @@
button:active { button:active {
transform: translateY(0); transform: translateY(0);
} }
.safety-mode {
background: rgba(255, 255, 255, 0.6);
padding: 16px;
border-radius: 10px;
margin-bottom: 16px;
border: 1px solid rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.safety-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.safety-label {
color: #374151;
font-weight: 600;
font-size: 0.875rem;
}
.safety-toggle {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.safety-toggle input {
opacity: 0;
width: 0;
height: 0;
}
.safety-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #e5e7eb;
transition: 0.3s;
border-radius: 24px;
border: 1px solid rgba(0, 129, 247, 0.2);
}
.safety-slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 2px;
bottom: 2px;
background-color: white;
transition: 0.3s;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
input:checked + .safety-slider {
background: linear-gradient(135deg, #0081F7, #1d4ed8);
border-color: rgba(0, 129, 247, 0.4);
}
input:checked + .safety-slider:before {
transform: translateX(26px);
}
.safety-slider:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
</style> </style>
</head> </head>
<body> <body>
@@ -257,7 +331,7 @@
<span class="tooltip-content"> <span class="tooltip-content">
Start server with: npx opendia Start server with: npx opendia
Auto-discovery will find the correct ports. Auto-discovery will find the correct ports.
If issues persist, try: npx opendia --kill-existing Existing processes are automatically terminated on startup
</span> </span>
</span> </span>
</div> </div>
@@ -277,6 +351,21 @@
</div> </div>
</div> </div>
<div class="safety-mode">
<div class="safety-row">
<span class="safety-label tooltip">
Safety Mode
<span class="tooltip-content">
When enabled, blocks write/edit tools: element_click, element_fill
</span>
</span>
<label class="safety-toggle">
<input type="checkbox" id="safetyMode">
<span class="safety-slider"></span>
</label>
</div>
</div>
<div class="button-group"> <div class="button-group">
<button id="reconnectBtn">Reconnect</button> <button id="reconnectBtn">Reconnect</button>
</div> </div>

View File

@@ -84,7 +84,7 @@ function updateStatus(connected) {
} else { } else {
statusIndicator.className = "status-indicator disconnected"; statusIndicator.className = "status-indicator disconnected";
statusText.innerHTML = `Disconnected from MCP server statusText.innerHTML = `Disconnected from MCP server
<span class="tooltip-content">Start server with: npx opendia. Auto-discovery will find the correct ports. If issues persist, try: npx opendia --kill-existing</span>`; <span class="tooltip-content">Start server with: npx opendia. Auto-discovery will find the correct ports. Existing processes are automatically terminated on startup</span>`;
} }
} }
@@ -100,6 +100,29 @@ document.getElementById("reconnectBtn").addEventListener("click", () => {
}); });
// Safety Mode Management
const safetyModeToggle = document.getElementById("safetyMode");
// Load safety mode state from storage
chrome.storage.local.get(['safetyMode'], (result) => {
const safetyEnabled = result.safetyMode || false; // Default to false (safety off)
safetyModeToggle.checked = safetyEnabled;
});
// Handle safety mode toggle changes
safetyModeToggle.addEventListener('change', () => {
const safetyEnabled = safetyModeToggle.checked;
// Save to storage
chrome.storage.local.set({ safetyMode: safetyEnabled });
// Notify background script
chrome.runtime.sendMessage({
action: "setSafetyMode",
enabled: safetyEnabled
});
});
// Listen for updates from background script // Listen for updates from background script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "statusUpdate") { if (message.type === "statusUpdate") {

View File

@@ -1,12 +1,12 @@
{ {
"name": "opendia", "name": "opendia",
"version": "1.0.3", "version": "1.0.5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "opendia", "name": "opendia",
"version": "1.0.3", "version": "1.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cors": "^2.8.5", "cors": "^2.8.5",
@@ -86,7 +86,7 @@
} }
}, },
"node_modules/call-bound": { "node_modules/call-bound": {
"version": "1.0.4", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT", "license": "MIT",

View File

@@ -1,6 +1,6 @@
{ {
"name": "opendia", "name": "opendia",
"version": "1.0.4", "version": "1.0.5",
"description": "🎯 OpenDia - The open alternative to Dia. Connect your browser to AI models with anti-detection bypass for Twitter/X, LinkedIn, Facebook", "description": "🎯 OpenDia - The open alternative to Dia. Connect your browser to AI models with anti-detection bypass for Twitter/X, LinkedIn, Facebook",
"main": "server.js", "main": "server.js",
"bin": { "bin": {

File diff suppressed because it is too large Load Diff

BIN
opendia.dxt Normal file

Binary file not shown.