20 Commits

Author SHA1 Message Date
@aaronjmars
8d3c2dc9fc Merge pull request #18 from felixrieseberg/felixr/fix-manifest
fix: manifest.json for dxt
2025-10-21 13:46:10 -04:00
@aaronjmars
eede8cdee5 Update README.md 2025-10-09 17:14:15 +02:00
Felix Rieseberg
8783ae0dc2 fix: manifest.json for dxt 2025-07-28 21:26:16 +02:00
@aaronjmars
9ad89e7248 Update README.md 2025-07-27 16:36:51 +02:00
@aaronjmars
9dcbd230c5 Update README.md 2025-07-20 23:51:26 +02:00
Aaron Elijah Mars
daa4b55ee5 Update to version 1.1.0 with tab_list timeout fixes and enhanced documentation
- Fixed tab_list timeout issue on Chrome by increasing content script timeout from 1s to 3s
- Updated all package.json and manifest files to version 1.1.0
- Set check_content_script default to false to avoid timeouts
- Enhanced DXT build script with comprehensive installation guide and GitHub repo links
- Fixed OpenDia logo path in README.md
- Updated tool examples and documentation to reflect timeout improvements

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-20 23:43:30 +02:00
Aaron Elijah Mars
0b09201160 Update to version 1.0.6 with Firefox support and improved extension management
- Add Firefox extension support with Manifest V2
- Update all version numbers to 1.0.6
- Build Chrome and Firefox extension packages
- Clean up extension directory structure
- Update README with Firefox installation instructions
- Update server messages to mention Chrome/Firefox support
- Add .gitignore for extension directory
- Create release packages for both browsers

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-16 22:57:39 +02:00
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
Aaron Elijah Mars
f57010971a Bump version to 1.0.4
Updated version in package.json and manifest.json for release 1.0.4

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-12 21:18:09 +02:00
Aaron Elijah Mars
e40805801a fix port assignment + license 2025-07-12 21:04:26 +02:00
Aaron Elijah Mars
c3c77c1e04 hosted mode w/ Ngrok + SSE 2025-07-12 20:30:15 +02:00
@aaronjmars
23eda72d91 Update README.md 2025-06-29 07:35:49 +02:00
@aaronjmars
b131e05513 Update README.md 2025-06-28 21:34:49 +02:00
Aaron Elijah Mars
019df3b3b0 v1 2025-06-28 21:28:52 +02:00
Aaron Elijah Mars
42e465045c v1 2025-06-28 21:27:42 +02:00
29 changed files with 9983 additions and 1302 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 OpenDia Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

150
README.md
View File

@@ -1,9 +1,12 @@
# OpenDia <img src="opendia-extension/icon-128.png" alt="OpenDia" width="32" height="32">
# OpenDia <img src="opendia-extension/icons/icon-128.png" alt="OpenDia" width="32" height="32">
> **The open alternative to Dia**
> Connect your browser to AI models. No browser switching needed—works seamlessly with any Chromium browser including Chrome & Arc.
**The open alternative to Dia / Perplexity Comet**
Connect your browser to AI models.
No browser switching needed—works seamlessly with Chrome, Firefox, and any Chromium browser. Private, local-first & MCP focused.
If you are not technical / never used MCPs before, we recommend using **[Perplexity Comet](https://pplx.ai/leosimon)**.
[![npm version](https://badge.fury.io/js/opendia.svg)](https://badge.fury.io/js/opendia)
[![npm version](https://img.shields.io/npm/v/opendia)](https://www.npmjs.com/package/opendia)
[![GitHub release](https://img.shields.io/github/release/aaronjmars/opendia.svg)](https://github.com/aaronjmars/opendia/releases/latest)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
## 📺 See it in Action
@@ -15,7 +18,7 @@
OpenDia lets AI models control your browser automatically. **The key advantage? It leverages everything you already have**—your logged-in accounts, saved passwords, cookies, wallets, and browsing history. No need to start from scratch or switch contexts.
**🔑 Use Your Existing Digital Life:**
-**Logged-in accounts**: Post to Twitter / X, LinkedIn, Facebook with your existing sessions
-**Logged-in accounts**: Post to Twitter/X, LinkedIn, Facebook with your existing sessions
-**Browser data**: Access your bookmarks, history, and saved passwords
-**Extensions & wallets**: Use MetaMask, password managers, or any installed extensions
-**Cookies & sessions**: Stay authenticated across all your favorite sites
@@ -30,16 +33,16 @@ OpenDia lets AI models control your browser automatically. **The key advantage?
## 🌐 Browser Support
Works with **any Chromium-based browser**:
Works with **Chrome, Firefox, and any Chromium-based browser**:
-**Google Chrome**
-**Arc Browser**
-**Arc**
-**Mozilla Firefox**
-**Microsoft Edge**
-**Brave Browser**
-**Brave**
-**Opera**
-**Vivaldi**
-**Any Chromium variant**
-**Any Chromium based browser**
Perfect for **Cursor users** who want to automate their local testing and development workflows!
Also perfect for **Cursor users** who want to automate their local testing and development workflows!
## 🎬 What You Can Do
@@ -69,21 +72,42 @@ Perfect for **Cursor users** who want to automate their local testing and develo
- **"Monitor this webpage and notify me when the content changes"**
- **"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
### 1. Start the Server
```bash
npx opendia
```
### 1. Install the Browser Extension
### 2. Install the Browser Extension
1. Download from [releases](https://github.com/aaronjmars/opendia/releases)
2. Go to `chrome://extensions/` (or your browser's extension page)
3. Enable "Developer mode"
4. Click "Load unpacked" and select the extension folder
**For Chrome/Chromium browsers:**
1. Download `opendia-chrome-1.1.0.zip` from [releases](https://github.com/aaronjmars/opendia/releases)
2. Extract the zip file to a folder
3. Go to `chrome://extensions/` (or your browser's extension page)
4. Enable "Developer mode"
5. Click "Load unpacked" and select the extracted folder
### 3. Connect to Your AI
**For Claude Desktop**, add to your configuration:
**For Firefox:**
1. Download `opendia-firefox-1.1.0.zip` from [releases](https://github.com/aaronjmars/opendia/releases)
2. Extract the zip file to a folder
3. Go to `about:debugging#/runtime/this-firefox`
4. Click "Load Temporary Add-on..."
5. Select the `manifest.json` file from the extracted folder
> **Note**: Firefox extensions are loaded as temporary add-ons and will be removed when Firefox restarts. This is a Firefox limitation for unsigned extensions.
### 2. Connect to Your AI
**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
{
"mcpServers": {
@@ -97,9 +121,67 @@ npx opendia
**For Cursor or other AI tools**, use the same configuration or follow their specific setup instructions.
## Usage Modes
### Local Mode (Default)
```bash
npx opendia
```
- Chrome extension: ws://localhost:5555 (auto-discovery enabled)
- Claude Desktop: stdio (existing config)
- Local SSE: http://localhost:5556/sse
### Port Configuration
```bash
# Use custom ports
npx opendia --port=6000 # Uses 6000 (WebSocket) + 6001 (HTTP)
npx opendia --ws-port=5555 --http-port=5556 # Specify individually
# Handle port conflicts
# Note: Existing OpenDia processes are automatically terminated on startup
```
### Auto-Tunnel Mode
```bash
npx opendia --tunnel
```
- Automatically creates ngrok tunnel
- Copy URL for ChatGPT/online AI services
- Local functionality preserved
**Note**: For auto-tunneling to work, you need ngrok installed:
**macOS:**
```bash
brew install ngrok
```
**Windows:**
```bash
# Using Chocolatey
choco install ngrok
# Or download from https://ngrok.com/download
```
**Linux:**
```bash
# Ubuntu/Debian
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list
sudo apt update && sudo apt install ngrok
# Or download from https://ngrok.com/download
```
Then get your free authtoken from https://dashboard.ngrok.com/get-started/your-authtoken and run:
```bash
ngrok config add-authtoken YOUR_TOKEN_HERE
```
## 🛠️ Capabilities
OpenDia gives AI models **17 powerful browser tools**:
OpenDia gives AI models **18 powerful browser tools**:
### 🎯 Smart Page Understanding
- **Analyze any webpage** - AI automatically finds buttons, forms, and interactive elements
@@ -127,6 +209,13 @@ OpenDia gives AI models **17 powerful browser tools**:
- **Natural interactions** - Mimics human behavior to avoid triggering security measures
- **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
Once everything is set up, try asking your AI:
@@ -149,6 +238,15 @@ Once everything is set up, try asking your AI:
**Personal Assistant:**
> *"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
```mermaid
@@ -188,8 +286,10 @@ cd opendia-mcp
npm install
npm start
# Load extension in your browser
# Go to chrome://extensions/ → Developer mode → Load unpacked: ./opendia-extension
# Load extension in your browser
# Chrome: Go to chrome://extensions/ → Developer mode → Load unpacked: ./opendia-extension/dist/chrome
# Firefox: Go to about:debugging#/runtime/this-firefox → Load Temporary Add-on → ./opendia-extension/dist/firefox/manifest.json
# Extension will auto-connect to server on localhost:5555
```
### Ways to Contribute

401
build-dxt.sh Executable file
View File

@@ -0,0 +1,401 @@
#!/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.1.0",
"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",
"firefox",
"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.1.0",
"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", "firefox", "extension", "twitter", "linkedin", "facebook", "anti-detection"],
"icon": "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/Firefox extension connection",
"default": 5555,
"min": 1024,
"max": 65535
},
"http_port": {
"type": "number",
"title": "HTTP Port",
"description": "Port for HTTP/SSE server",
"default": 5556,
"min": 1024,
"max": 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"
}
]
}
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 Browser Extension Installation
**🔗 Official Repository:** https://github.com/aaronjmars/opendia
## Complete Installation Guide
### Step 1: Install the DXT Package (Already Done!)
✅ You've successfully installed the OpenDia DXT package in Claude Desktop
### Step 2: Install Browser Extension
**📦 Get Latest Extension:**
Download the latest extension from: https://github.com/aaronjmars/opendia/releases
**Or use the included extension in this DXT package:**
#### For Chrome/Chromium Browsers
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 with OpenDia icon
#### For Firefox
1. **Load Temporary Add-on**
- Go to `about:debugging#/runtime/this-firefox`
- Click "Load Temporary Add-on..."
- Select the `manifest-firefox.json` file from the `extension/` folder
> **Firefox Note**: Extensions are loaded as temporary add-ons and will be removed when Firefox restarts. For permanent installation, use the signed extension from GitHub releases.
### Step 3: Verify Everything Works
1. **Check Extension Status**
- Click the OpenDia extension icon in your browser
- Should show "Connected to MCP server"
- Green status indicator means ready to use
2. **Test in Claude Desktop**
- Ask Claude: "List my open browser tabs"
- Should return your current tabs if working correctly
## Supported Browsers
- ✅ **Mozilla Firefox** (Manifest V2)
- ✅ **Google Chrome** (Manifest V3)
- ✅ **Arc Browser, Microsoft Edge, Brave Browser, Opera**
- ✅ **Any Chromium-based browser**
## Key Features
🎯 **Anti-detection bypass** for Twitter/X, LinkedIn, Facebook
📱 **Smart automation** and intelligent page analysis
🔧 **Form filling** with enhanced compatibility
📊 **Multi-tab workflows** and background operations
🎨 **Page styling** and visual customization
🔒 **Privacy-first** - everything runs locally
## Getting Help
- **📖 Full Documentation:** https://github.com/aaronjmars/opendia
- **🐛 Report Issues:** https://github.com/aaronjmars/opendia/issues
- **💬 Discussions:** https://github.com/aaronjmars/opendia/discussions
## What's Next?
Try these example prompts in Claude Desktop:
- "List my open browser tabs"
- "Analyze the content of my current tab"
- "Apply a dark theme to this webpage"
- "Extract the main article text from this page"
**🚀 Ready to supercharge your browser with AI!**
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/Firefox extension from extension/ folder"
echo ""
echo "🎯 Features ready: Anti-detection bypass + universal automation"

2
opendia-extension/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
dist/

312
opendia-extension/README.md Normal file
View File

@@ -0,0 +1,312 @@
# OpenDia Cross-Browser Extension
A dual-manifest browser extension supporting both Chrome MV3 and Firefox MV2 for comprehensive browser automation through the Model Context Protocol (MCP).
## 🌐 Browser Support
| Browser | Manifest | Background | Connection | Store |
|---------|----------|------------|------------|-------|
| Chrome | V3 | Service Worker | Temporary | Chrome Web Store |
| Firefox | V2 | Background Page | Persistent | Firefox Add-ons |
| Edge | V3 | Service Worker | Temporary | Microsoft Store |
| Safari | - | - | - | Coming Soon |
## 🚀 Quick Start
### Development Setup
```bash
# Install dependencies
npm install
# Build for all browsers
npm run build
# Build for specific browser
npm run build:chrome
npm run build:firefox
# Create distribution packages
npm run package:chrome
npm run package:firefox
# Test builds
node test-extension.js
```
### Installation
#### Chrome/Edge/Brave
1. Build the extension: `npm run build:chrome`
2. Open `chrome://extensions/` (or equivalent)
3. Enable "Developer mode"
4. Click "Load unpacked" and select `dist/chrome`
#### Firefox
1. Build the extension: `npm run build:firefox`
2. Open `about:debugging#/runtime/this-firefox`
3. Click "Load Temporary Add-on"
4. Select any file in `dist/firefox` directory
## 🏗️ Architecture
### Dual-Manifest Strategy
OpenDia uses a dual-manifest approach to maximize browser compatibility:
- **Chrome MV3**: Required for Chrome Web Store, uses service workers
- **Firefox MV2**: Enhanced capabilities, persistent background pages
### Connection Management
```javascript
// Chrome MV3: Temporary connections
class ServiceWorkerManager {
async ensureConnection() {
// Create fresh connection for each operation
await this.createTemporaryConnection();
}
}
// Firefox MV2: Persistent connections
class BackgroundPageManager {
constructor() {
this.persistentSocket = null;
this.setupPersistentConnection();
}
}
```
### Cross-Browser Compatibility
The extension uses WebExtension polyfill for consistent API usage:
```javascript
// Polyfill setup
if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
globalThis.browser = chrome;
}
// Unified API usage
const tabs = await browser.tabs.query({active: true, currentWindow: true});
```
## 🔧 Build System
### Build Configuration
The build system creates browser-specific packages:
```javascript
// build.js
async function buildForBrowser(browser) {
// Copy common files
await fs.copy('src', path.join(buildDir, 'src'));
// Copy browser-specific manifest
await fs.copy(`manifest-${browser}.json`, path.join(buildDir, 'manifest.json'));
// Copy WebExtension polyfill
await fs.copy('node_modules/webextension-polyfill/dist/browser-polyfill.min.js',
path.join(buildDir, 'src/polyfill/browser-polyfill.min.js'));
}
```
### Build Validation
```bash
# Validate all builds
npm run build && node build.js validate
# Check specific browser
node build.js validate chrome
node build.js validate firefox
```
## 🧪 Testing
### Automated Testing
```bash
# Run comprehensive tests
node test-extension.js
# Test specific components
node test-extension.js --manifest
node test-extension.js --background
node test-extension.js --content
```
### Manual Testing
1. **Connection Test**: Extension popup should show "Connected to MCP server"
2. **Background Tab Test**: Use `tab_list` with `check_content_script: true`
3. **Cross-Browser Test**: Same functionality on both Chrome and Firefox
## 📁 Directory Structure
```
opendia-extension/
├── src/
│ ├── background/
│ │ └── background.js # Cross-browser background script
│ ├── content/
│ │ └── content.js # Content script with polyfill
│ ├── popup/
│ │ ├── popup.html # Extension popup
│ │ └── popup.js # Popup logic with browser APIs
│ └── polyfill/
│ └── browser-polyfill.min.js # WebExtension polyfill
├── icons/ # Extension icons
├── dist/ # Build output
│ ├── chrome/ # Chrome MV3 build
│ ├── firefox/ # Firefox MV2 build
│ ├── opendia-chrome.zip # Chrome package
│ └── opendia-firefox.zip # Firefox package
├── manifest-chrome.json # Chrome MV3 manifest
├── manifest-firefox.json # Firefox MV2 manifest
├── build.js # Build system
├── test-extension.js # Test suite
└── package.json # Dependencies and scripts
```
## 🔗 Integration
### MCP Server Connection
The extension automatically discovers and connects to the MCP server:
```javascript
// Port discovery
const commonPorts = [5556, 5557, 5558, 3001, 6001, 6002, 6003];
const response = await fetch(`http://localhost:${port}/ports`);
const portInfo = await response.json();
```
### Background Tab Support
All tools support background tab targeting:
```javascript
// Target specific tab
await browser.tabs.sendMessage(tabId, {
action: 'page_analyze',
data: { intent_hint: 'login', tab_id: 12345 }
});
```
## 🛠️ Development
### Adding New Features
1. **Cross-Browser First**: Use `browser` API throughout
2. **Connection Aware**: Handle both temporary and persistent connections
3. **Test Both Browsers**: Validate on Chrome and Firefox
4. **Update Both Manifests**: Ensure compatibility
### Browser-Specific Handling
```javascript
// Detect browser environment
const browserInfo = {
isFirefox: typeof browser !== 'undefined' && browser.runtime.getManifest().applications?.gecko,
isChrome: typeof chrome !== 'undefined' && !browser.runtime.getManifest().applications?.gecko,
isServiceWorker: typeof importScripts === 'function',
manifestVersion: browser.runtime.getManifest().manifest_version
};
// Handle differences
if (browserInfo.isServiceWorker) {
// Chrome MV3 service worker behavior
} else {
// Firefox MV2 background page behavior
}
```
### API Compatibility
| Feature | Chrome MV3 | Firefox MV2 | Implementation |
|---------|------------|-------------|----------------|
| Background | Service Worker | Background Page | Connection Manager |
| Script Injection | `browser.scripting` | `browser.tabs.executeScript` | Feature detection |
| Persistent State | ❌ | ✅ | Browser-specific storage |
| WebRequest Blocking | Limited | Full | Firefox advantage |
| Store Distribution | Required | Optional | Both supported |
## 🚀 Distribution
### Chrome Web Store
```bash
# Build and package
npm run package:chrome
# Upload dist/opendia-chrome.zip to Chrome Web Store
```
### Firefox Add-ons (AMO)
```bash
# Build and package
npm run package:firefox
# Upload dist/opendia-firefox.zip to addons.mozilla.org
```
### GitHub Releases
```bash
# Create both packages
npm run package:chrome
npm run package:firefox
# Upload both files to GitHub releases
```
## 🤝 Contributing
1. **Test Both Browsers**: Always test Chrome and Firefox
2. **Use Browser APIs**: Avoid `chrome.*` direct usage
3. **Update Both Manifests**: Keep manifests in sync
4. **Validate Builds**: Run test suite before committing
## 📚 Resources
- [WebExtension API Documentation](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions)
- [Chrome Extension MV3 Guide](https://developer.chrome.com/docs/extensions/mv3/)
- [Firefox Extension Development](https://extensionworkshop.com/)
- [WebExtension Polyfill](https://github.com/mozilla/webextension-polyfill)
## 🔧 Troubleshooting
### Common Issues
1. **Connection Fails**: Check MCP server is running (`npm start` in `opendia-mcp/`)
2. **Chrome Service Worker**: Extensions may need manual restart in `chrome://extensions`
3. **Firefox Temporary**: Extension reloads required after Firefox restart
4. **Build Errors**: Ensure all dependencies installed (`npm install`)
### Debug Commands
```bash
# Check server status
curl http://localhost:5556/ping
# Validate builds
node build.js validate
# Test extension compatibility
node test-extension.js
# Check extension logs
# Chrome: chrome://extensions -> OpenDia -> service worker
# Firefox: about:debugging -> OpenDia -> Inspect
```
## 🎯 Future Enhancements
- [ ] Safari extension support
- [ ] Edge-specific optimizations
- [ ] WebExtension Manifest V3 migration for Firefox
- [ ] Enhanced anti-detection features
- [ ] Performance optimizations for service workers

File diff suppressed because it is too large Load Diff

193
opendia-extension/build.js Normal file
View File

@@ -0,0 +1,193 @@
const fs = require('fs-extra');
const path = require('path');
async function buildForBrowser(browser) {
const buildDir = `dist/${browser}`;
console.log(`🔧 Building ${browser} extension...`);
// Clean and create build directory
await fs.remove(buildDir);
await fs.ensureDir(buildDir);
// Copy common files
await fs.copy('src', path.join(buildDir, 'src'));
await fs.copy('icons', path.join(buildDir, 'icons'));
// Copy logo files for animated popup
if (await fs.pathExists('logo.mp4')) {
await fs.copy('logo.mp4', path.join(buildDir, 'logo.mp4'));
}
if (await fs.pathExists('logo.webm')) {
await fs.copy('logo.webm', path.join(buildDir, 'logo.webm'));
}
// Copy browser-specific manifest
await fs.copy(
`manifest-${browser}.json`,
path.join(buildDir, 'manifest.json')
);
// Copy polyfill
await fs.copy(
'node_modules/webextension-polyfill/dist/browser-polyfill.min.js',
path.join(buildDir, 'src/polyfill/browser-polyfill.min.js')
);
// Browser-specific post-processing
if (browser === 'chrome') {
console.log('📦 Chrome MV3: Service worker mode enabled');
// No additional processing needed for Chrome
} else if (browser === 'firefox') {
console.log('🦊 Firefox MV2: Background page mode enabled');
// No additional processing needed for Firefox
}
console.log(`${browser} extension built successfully in ${buildDir}`);
}
async function buildAll() {
console.log('🚀 Building extensions for all browsers...');
try {
await buildForBrowser('chrome');
await buildForBrowser('firefox');
console.log('🎉 All extensions built successfully!');
console.log('');
console.log('📁 Build outputs:');
console.log(' Chrome MV3: dist/chrome/');
console.log(' Firefox MV2: dist/firefox/');
console.log('');
console.log('🧪 Testing instructions:');
console.log(' Chrome: Load dist/chrome in chrome://extensions (Developer mode)');
console.log(' Firefox: Load dist/firefox in about:debugging#/runtime/this-firefox');
} catch (error) {
console.error('❌ Build failed:', error);
process.exit(1);
}
}
async function createPackages() {
console.log('📦 Creating distribution packages...');
const { execSync } = require('child_process');
try {
// Create Chrome package
console.log('Creating Chrome package...');
execSync('cd dist/chrome && zip -r ../opendia-chrome.zip .', { stdio: 'inherit' });
// Create Firefox package (using web-ext if available)
console.log('Creating Firefox package...');
try {
execSync('cd dist/firefox && web-ext build --overwrite-dest', { stdio: 'inherit' });
console.log('✅ Firefox package created with web-ext');
} catch (e) {
// Fallback to zip if web-ext is not available
console.log('⚠️ web-ext not available, using zip fallback');
execSync('cd dist/firefox && zip -r ../opendia-firefox.zip .', { stdio: 'inherit' });
}
console.log('📦 Distribution packages created:');
console.log(' Chrome: dist/opendia-chrome.zip');
console.log(' Firefox: dist/opendia-firefox.zip (or .xpi)');
} catch (error) {
console.error('❌ Package creation failed:', error);
process.exit(1);
}
}
async function validateBuild(browser) {
const buildDir = `dist/${browser}`;
const manifestPath = path.join(buildDir, 'manifest.json');
console.log(`🔍 Validating ${browser} build...`);
try {
// Check manifest exists and is valid JSON
const manifest = await fs.readJson(manifestPath);
// Check required files exist
const requiredFiles = [
'src/background/background.js',
'src/content/content.js',
'src/popup/popup.html',
'src/popup/popup.js',
'src/polyfill/browser-polyfill.min.js'
];
for (const file of requiredFiles) {
const filePath = path.join(buildDir, file);
if (!await fs.pathExists(filePath)) {
throw new Error(`Missing required file: ${file}`);
}
}
// Browser-specific validation
if (browser === 'chrome') {
if (manifest.manifest_version !== 3) {
throw new Error('Chrome build must use manifest version 3');
}
if (!manifest.background?.service_worker) {
throw new Error('Chrome build must specify service_worker in background');
}
} else if (browser === 'firefox') {
if (manifest.manifest_version !== 2) {
throw new Error('Firefox build must use manifest version 2');
}
if (!manifest.background?.scripts) {
throw new Error('Firefox build must specify scripts in background');
}
}
console.log(`${browser} build validation passed`);
return true;
} catch (error) {
console.error(`${browser} build validation failed:`, error.message);
return false;
}
}
async function validateAllBuilds() {
console.log('🔍 Validating all builds...');
const chromeValid = await validateBuild('chrome');
const firefoxValid = await validateBuild('firefox');
if (chromeValid && firefoxValid) {
console.log('✅ All builds validated successfully');
return true;
} else {
console.error('❌ Build validation failed');
return false;
}
}
// CLI usage
if (require.main === module) {
const args = process.argv.slice(2);
const command = args[0];
switch (command) {
case 'chrome':
buildForBrowser('chrome');
break;
case 'firefox':
buildForBrowser('firefox');
break;
case 'validate':
validateAllBuilds();
break;
case 'package':
buildAll().then(() => createPackages());
break;
default:
buildAll();
}
}
module.exports = { buildForBrowser, buildAll, createPackages, validateBuild, validateAllBuilds };

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,46 @@
{
"manifest_version": 3,
"name": "OpenDia",
"version": "1.1.0",
"description": "Connect your browser to AI models",
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
},
"permissions": [
"tabs",
"activeTab",
"storage",
"scripting",
"webNavigation",
"notifications",
"bookmarks",
"history"
],
"host_permissions": [
"<all_urls>"
],
"background": {
"service_worker": "src/background/background.js",
"type": "module"
},
"action": {
"default_popup": "src/popup/popup.html",
"default_title": "OpenDia"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["src/polyfill/browser-polyfill.min.js", "src/content/content.js"],
"run_at": "document_idle"
}
],
"web_accessible_resources": [
{
"resources": ["src/polyfill/browser-polyfill.min.js"],
"matches": ["<all_urls>"]
}
]
}

View File

@@ -0,0 +1,51 @@
{
"manifest_version": 2,
"name": "OpenDia",
"version": "1.1.0",
"description": "Connect your browser to AI models",
"applications": {
"gecko": {
"id": "opendia@aaronjmars.com",
"strict_min_version": "109.0"
}
},
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
},
"permissions": [
"tabs",
"activeTab",
"storage",
"webNavigation",
"notifications",
"bookmarks",
"history",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
"background": {
"scripts": [
"src/polyfill/browser-polyfill.min.js",
"src/background/background.js"
],
"persistent": false
},
"browser_action": {
"default_popup": "src/popup/popup.html",
"default_title": "OpenDia"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["src/polyfill/browser-polyfill.min.js", "src/content/content.js"],
"run_at": "document_idle"
}
],
"web_accessible_resources": [
"src/polyfill/browser-polyfill.min.js"
]
}

View File

@@ -1,8 +1,8 @@
{
"manifest_version": 3,
"name": "OpenDia",
"version": "1.0.0",
"description": "Browser automation through Model Context Protocol",
"version": "1.1.0",
"description": "Connect your browser to AI models",
"icons": {
"16": "icon-16.png",
"32": "icon-32.png",

4319
opendia-extension/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
{
"name": "opendia-extension",
"version": "1.1.0",
"description": "Connect your browser to AI models",
"scripts": {
"build": "node build.js",
"build:chrome": "node build.js chrome",
"build:firefox": "node build.js firefox",
"dev:chrome": "npm run build:chrome && echo 'Load dist/chrome in Chrome'",
"dev:firefox": "npm run build:firefox && web-ext run --source-dir=dist/firefox",
"package:chrome": "npm run build:chrome && cd dist/chrome && zip -r ../opendia-chrome.zip .",
"package:firefox": "npm run build:firefox && cd dist/firefox && web-ext build --overwrite-dest"
},
"keywords": [
"webextension",
"mcp",
"browser-automation"
],
"author": "Aaron J Mars",
"license": "MIT",
"dependencies": {
"webextension-polyfill": "^0.12.0"
},
"devDependencies": {
"fs-extra": "^11.3.0",
"web-ext": "^8.8.0"
}
}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,15 @@
// Enhanced Browser Automation Content Script with Anti-Detection
// Import WebExtension polyfill for cross-browser compatibility
if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
globalThis.browser = chrome;
}
// Prevent multiple injections - especially important for Firefox
if (typeof window.OpenDiaContentScriptLoaded !== 'undefined') {
console.log("OpenDia content script already loaded, skipping re-injection");
} else {
window.OpenDiaContentScriptLoaded = true;
console.log("OpenDia enhanced content script loaded");
// Enhanced Pattern Database with Twitter-First Priority
@@ -228,7 +239,7 @@ class BrowserAutomation {
}
setupMessageListener() {
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
this.handleMessage(message)
.then(sendResponse)
.catch((error) => {
@@ -283,6 +294,13 @@ class BrowserAutomation {
case "page_scroll":
result = await this.scrollPage(data);
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:
throw new Error(`Unknown action: ${action}`);
}
@@ -2503,7 +2521,377 @@ 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
const browserAutomation = new BrowserAutomation();
} // End of injection guard

File diff suppressed because one or more lines are too long

View File

@@ -236,14 +236,88 @@
button:active {
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>
</head>
<body>
<div class="header">
<div class="logo">
<video autoplay loop muted playsinline>
<source src="logo.webm" type="video/webm">
<source src="logo.mp4" type="video/mp4">
<source src="../../logo.webm" type="video/webm">
<source src="../../logo.mp4" type="video/mp4">
<span>OD</span>
</video>
</div>
@@ -255,9 +329,9 @@
<span id="statusText" class="tooltip">
Checking connection...
<span class="tooltip-content">
Make sure your MCP server is connected.
If it's the case, click on Reconnect.
If it still don't work, kill your 3000 port & try again.
Start server with: npx opendia
Auto-discovery will find the correct ports.
Existing processes are automatically terminated on startup
</span>
</span>
</div>
@@ -265,7 +339,7 @@
<div class="info">
<div class="info-row">
<span class="info-label">Server</span>
<span class="info-value" id="serverUrl">ws://localhost:3000</span>
<span class="info-value" id="serverUrl">Auto-Discovery</span>
</div>
<div class="info-row">
<span class="info-label">Available Tools</span>
@@ -277,6 +351,21 @@
</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">
<button id="reconnectBtn">Reconnect</button>
</div>

View File

@@ -1,8 +1,18 @@
// OpenDia Popup
// Import WebExtension polyfill for cross-browser compatibility
if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
globalThis.browser = chrome;
}
// Cross-browser compatibility layer
const runtimeAPI = browser.runtime;
const tabsAPI = browser.tabs;
const storageAPI = browser.storage;
let statusIndicator = document.getElementById("statusIndicator");
let statusText = document.getElementById("statusText");
let toolCount = document.getElementById("toolCount");
let currentPage = document.getElementById("currentPage");
let serverUrl = document.getElementById("serverUrl");
// Get dynamic tool count from background script
function updateToolCount() {
@@ -13,9 +23,9 @@ function updateToolCount() {
"get_bookmarks", "add_bookmark", "get_history", "get_selected_text", "get_page_links"
];
if (chrome.runtime?.id) {
chrome.runtime.sendMessage({ action: "getToolCount" }, (response) => {
if (!chrome.runtime.lastError && response?.toolCount) {
if (runtimeAPI?.id) {
runtimeAPI.sendMessage({ action: "getToolCount" }, (response) => {
if (!runtimeAPI.lastError && response?.toolCount) {
toolCount.innerHTML = `<span class="tooltip">${response.toolCount}
<span class="tooltip-content">Available MCP Tools:\npage_analyze page_extract_content element_click element_fill element_get_state page_navigate page_wait_for page_scroll tab_create tab_close tab_list tab_switch get_bookmarks add_bookmark get_history get_selected_text get_page_links</span>
</span>`;
@@ -31,9 +41,9 @@ function updateToolCount() {
// Check connection status and get page info
function checkStatus() {
if (chrome.runtime?.id) {
chrome.runtime.sendMessage({ action: "getStatus" }, (response) => {
if (chrome.runtime.lastError) {
if (runtimeAPI?.id) {
runtimeAPI.sendMessage({ action: "getStatus" }, (response) => {
if (runtimeAPI.lastError) {
updateStatus(false);
} else {
updateStatus(response?.connected || false);
@@ -44,7 +54,7 @@ function checkStatus() {
updateToolCount();
// Get current page info
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
tabsAPI.query({active: true, currentWindow: true}, (tabs) => {
if (tabs[0]) {
const url = new URL(tabs[0].url);
currentPage.textContent = url.hostname;
@@ -59,24 +69,39 @@ function checkStatus() {
checkStatus();
setInterval(checkStatus, 2000);
// Update server URL display
function updateServerUrl() {
if (runtimeAPI?.id) {
runtimeAPI.sendMessage({ action: "getPorts" }, (response) => {
if (!runtimeAPI.lastError && response?.websocketUrl) {
serverUrl.textContent = response.websocketUrl;
}
});
}
}
// Update server URL periodically
updateServerUrl();
setInterval(updateServerUrl, 5000);
// Update UI based on connection status
function updateStatus(connected) {
if (connected) {
statusIndicator.className = "status-indicator connected";
statusText.innerHTML = `Connected to MCP server
<span class="tooltip-content">Make sure your MCP server is connected. If it's the case, click on Reconnect. If it still don't work, kill your 3000 port & try again.</span>`;
<span class="tooltip-content">Connected successfully! Server auto-discovery is working. Default ports: WebSocket=5555, HTTP=5556</span>`;
} else {
statusIndicator.className = "status-indicator disconnected";
statusText.innerHTML = `Disconnected from MCP server
<span class="tooltip-content">Make sure your MCP server is connected. If it's the case, click on Reconnect. If it still don't work, kill your 3000 port & try again.</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>`;
}
}
// Reconnect button
document.getElementById("reconnectBtn").addEventListener("click", () => {
if (chrome.runtime?.id) {
chrome.runtime.sendMessage({ action: "reconnect" }, (response) => {
if (!chrome.runtime.lastError) {
if (runtimeAPI?.id) {
runtimeAPI.sendMessage({ action: "reconnect" }, (response) => {
if (!runtimeAPI.lastError) {
setTimeout(checkStatus, 1000);
}
});
@@ -84,8 +109,31 @@ document.getElementById("reconnectBtn").addEventListener("click", () => {
});
// Safety Mode Management
const safetyModeToggle = document.getElementById("safetyMode");
// Load safety mode state from storage
storageAPI.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
storageAPI.local.set({ safetyMode: safetyEnabled });
// Notify background script
runtimeAPI.sendMessage({
action: "setSafetyMode",
enabled: safetyEnabled
});
});
// Listen for updates from background script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
runtimeAPI.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "statusUpdate") {
updateStatus(message.connected);
}

View File

@@ -0,0 +1,182 @@
// Simple test script to verify browser extension compatibility
const fs = require('fs');
const path = require('path');
function testManifestStructure(browser) {
console.log(`\n🔍 Testing ${browser} extension structure...`);
const buildDir = `dist/${browser}`;
const manifestPath = path.join(buildDir, 'manifest.json');
try {
// Read and parse manifest
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
// Check manifest version
console.log(` Manifest version: ${manifest.manifest_version}`);
// Check background configuration
if (browser === 'chrome') {
console.log(` Background: Service Worker (${manifest.background.service_worker})`);
console.log(` Action: ${manifest.action ? 'Present' : 'Missing'}`);
console.log(` Host permissions: ${manifest.host_permissions ? manifest.host_permissions.length : 0}`);
} else {
console.log(` Background: Scripts (${manifest.background.scripts.length} files)`);
console.log(` Browser action: ${manifest.browser_action ? 'Present' : 'Missing'}`);
console.log(` Gecko ID: ${manifest.applications?.gecko?.id || 'Not set'}`);
}
// Check permissions
console.log(` Permissions: ${manifest.permissions.length} total`);
// Check content scripts
console.log(` Content scripts: ${manifest.content_scripts?.length || 0} configured`);
// Check polyfill inclusion
const polyfillPath = path.join(buildDir, 'src/polyfill/browser-polyfill.min.js');
const polyfillExists = fs.existsSync(polyfillPath);
console.log(` WebExtension polyfill: ${polyfillExists ? 'Present' : 'Missing'}`);
// Check if polyfill is included in content scripts
const hasPolyfillInContent = manifest.content_scripts?.[0]?.js?.includes('src/polyfill/browser-polyfill.min.js');
console.log(` Polyfill in content scripts: ${hasPolyfillInContent ? 'Yes' : 'No'}`);
// Check if polyfill is included in background (Firefox only)
if (browser === 'firefox') {
const hasPolyfillInBackground = manifest.background?.scripts?.includes('src/polyfill/browser-polyfill.min.js');
console.log(` Polyfill in background: ${hasPolyfillInBackground ? 'Yes' : 'No'}`);
}
console.log(`${browser} extension structure looks good!`);
return true;
} catch (error) {
console.error(`❌ Error testing ${browser} extension:`, error.message);
return false;
}
}
function testBackgroundScript(browser) {
console.log(`\n🔍 Testing ${browser} background script...`);
const scriptPath = `dist/${browser}/src/background/background.js`;
try {
const script = fs.readFileSync(scriptPath, 'utf8');
// Check for browser polyfill usage
const usesBrowserAPI = script.includes('browser.') || script.includes('globalThis.browser');
console.log(` Uses browser API: ${usesBrowserAPI ? 'Yes' : 'No'}`);
// Check for connection manager
const hasConnectionManager = script.includes('ConnectionManager');
console.log(` Has connection manager: ${hasConnectionManager ? 'Yes' : 'No'}`);
// Check for browser detection
const hasBrowserDetection = script.includes('browserInfo') || script.includes('isFirefox') || script.includes('isServiceWorker');
console.log(` Has browser detection: ${hasBrowserDetection ? 'Yes' : 'No'}`);
// Check for WebSocket management
const hasWebSocketManagement = script.includes('WebSocket') && script.includes('connect');
console.log(` Has WebSocket management: ${hasWebSocketManagement ? 'Yes' : 'No'}`);
console.log(`${browser} background script looks good!`);
return true;
} catch (error) {
console.error(`❌ Error testing ${browser} background script:`, error.message);
return false;
}
}
function testContentScript(browser) {
console.log(`\n🔍 Testing ${browser} content script...`);
const scriptPath = `dist/${browser}/src/content/content.js`;
try {
const script = fs.readFileSync(scriptPath, 'utf8');
// Check for browser polyfill usage
const usesBrowserAPI = script.includes('browser.') || script.includes('globalThis.browser');
console.log(` Uses browser API: ${usesBrowserAPI ? 'Yes' : 'No'}`);
// Check for message handling
const hasMessageHandling = script.includes('onMessage') && script.includes('sendResponse');
console.log(` Has message handling: ${hasMessageHandling ? 'Yes' : 'No'}`);
console.log(`${browser} content script looks good!`);
return true;
} catch (error) {
console.error(`❌ Error testing ${browser} content script:`, error.message);
return false;
}
}
function testPopupScript(browser) {
console.log(`\n🔍 Testing ${browser} popup script...`);
const scriptPath = `dist/${browser}/src/popup/popup.js`;
try {
const script = fs.readFileSync(scriptPath, 'utf8');
// Check for browser polyfill usage
const usesBrowserAPI = script.includes('browser.') || script.includes('globalThis.browser');
console.log(` Uses browser API: ${usesBrowserAPI ? 'Yes' : 'No'}`);
// Check for API abstraction
const hasAPIAbstraction = script.includes('runtimeAPI') || script.includes('tabsAPI') || script.includes('storageAPI');
console.log(` Has API abstraction: ${hasAPIAbstraction ? 'Yes' : 'No'}`);
console.log(`${browser} popup script looks good!`);
return true;
} catch (error) {
console.error(`❌ Error testing ${browser} popup script:`, error.message);
return false;
}
}
function runAllTests() {
console.log('🚀 Testing cross-browser extension compatibility...\n');
const browsers = ['chrome', 'firefox'];
let allPassed = true;
for (const browser of browsers) {
console.log(`\n🌐 Testing ${browser.toUpperCase()} extension:`);
console.log('='.repeat(40));
const tests = [
testManifestStructure,
testBackgroundScript,
testContentScript,
testPopupScript
];
for (const test of tests) {
if (!test(browser)) {
allPassed = false;
}
}
}
console.log('\n' + '='.repeat(50));
if (allPassed) {
console.log('🎉 All tests passed! Cross-browser extension is ready.');
console.log('\n📦 Distribution packages:');
console.log(' Chrome: dist/opendia-chrome.zip');
console.log(' Firefox: dist/opendia-firefox.zip');
console.log('\n🧪 Manual testing:');
console.log(' 1. Chrome: Load dist/chrome in chrome://extensions');
console.log(' 2. Firefox: Load dist/firefox in about:debugging');
console.log(' 3. Both should connect to MCP server on localhost:5555/5556');
} else {
console.log('❌ Some tests failed. Please check the output above.');
}
}
// Run tests
runAllTests();

208
opendia-mcp/README.md Normal file
View File

@@ -0,0 +1,208 @@
# OpenDia <img src="opendia-extension/icon-128.png" alt="OpenDia" width="32" height="32">
> **The open alternative to Dia**
> Connect your browser to AI models. No browser switching needed—works seamlessly with any Chromium browser including Chrome & Arc.
[![npm version](https://badge.fury.io/js/opendia.svg)](https://badge.fury.io/js/opendia)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
## 📺 See it in Action
![OpenDia Demo](./preview.gif)
## 🚀 What is OpenDia?
OpenDia lets AI models control your browser automatically. **The key advantage? It leverages everything you already have**—your logged-in accounts, saved passwords, cookies, wallets, and browsing history. No need to start from scratch or switch contexts.
**🔑 Use Your Existing Digital Life:**
-**Logged-in accounts**: Post to Twitter / X, LinkedIn, Facebook with your existing sessions
-**Browser data**: Access your bookmarks, history, and saved passwords
-**Extensions & wallets**: Use MetaMask, password managers, or any installed extensions
-**Cookies & sessions**: Stay authenticated across all your favorite sites
-**Local testing**: Perfect for development with Cursor - test with real user sessions
**✨ Key Benefits:**
- 🔄 **Universal AI Support**: Works with Claude, ChatGPT, Cursor and even local models
- 🎯 **Anti-Detection**: Specialized bypasses for Twitter/X, LinkedIn, Facebook
- 📱 **Smart Automation**: AI understands your pages and finds the right elements
- 🛡️ **Privacy-First**: Everything runs locally, your data stays with you
-**Zero Setup**: Get started with one command
## 🌐 Browser Support
Works with **any Chromium-based browser**:
-**Google Chrome**
-**Arc Browser**
-**Microsoft Edge**
-**Brave Browser**
-**Opera**
-**Vivaldi**
-**Any Chromium variant**
Perfect for **Cursor users** who want to automate their local testing and development workflows!
## 🎬 What You Can Do
**Real workflows you can try today:**
### 📰 Content & Social Media
- **"Summarize all the articles I read today and post a Twitter thread about the key insights"**
- **"Find interesting articles related to AI from my bookmarks and create a reading list"**
- **"Read this article and post a thoughtful comment on the LinkedIn version"**
- **"Check my recent Twitter bookmarks and summarize the main themes"**
### 📧 Productivity & Research
- **"Browse my latest emails and tell me what needs urgent attention"**
- **"Find all the GitHub repos I visited this week and create a summary report"**
- **"Extract the main points from this research paper and save them to my notes"**
- **"Search my browsing history for that article about AI safety I read last month"**
### 🤖 Development & Testing (Perfect for Cursor!)
- **"Test my web app's signup flow and take screenshots at each step"**
- **"Fill out this form with test data and check if validation works"**
- **"Navigate through my app and check if all the buttons work properly"**
- **"Use my connected wallet to test this DeFi interface"**
### 🔄 Advanced Automation
- **"Open tabs for all my daily news sources and summarize the top stories"**
- **"Draft replies to my unread messages based on the context"**
- **"Monitor this webpage and notify me when the content changes"**
- **"Automatically bookmark interesting articles I'm reading"**
## ⚡ Quick Start
### 1. Start the Server
```bash
npx opendia
```
### 2. Install the Browser Extension
1. Download from [releases](https://github.com/aaronjmars/opendia/releases)
2. Go to `chrome://extensions/` (or your browser's extension page)
3. Enable "Developer mode"
4. Click "Load unpacked" and select the extension folder
### 3. Connect to Your AI
**For Claude Desktop**, add to your configuration:
```json
{
"mcpServers": {
"opendia": {
"command": "npx",
"args": ["opendia"]
}
}
}
```
**For Cursor or other AI tools**, use the same configuration or follow their specific setup instructions.
## 🛠️ Capabilities
OpenDia gives AI models **17 powerful browser tools**:
### 🎯 Smart Page Understanding
- **Analyze any webpage** - AI automatically finds buttons, forms, and interactive elements
- **Extract content intelligently** - Get clean text from articles, social posts, or search results
- **Understand context** - AI knows what type of page it's looking at and how to interact with it
### 🖱️ Natural Interactions
- **Click anything** - Buttons, links, menus - AI finds and clicks the right elements
- **Fill forms smartly** - Works even on complex sites like Twitter, LinkedIn, Facebook
- **Navigate seamlessly** - Go to pages, scroll, wait for content to load
- **Handle modern web apps** - Bypasses detection on social platforms
### 📑 Tab & Window Management
- **Multi-tab workflows** - Open, close, switch between tabs automatically
- **Organize your workspace** - Let AI manage your browser tabs efficiently
- **Coordinate complex tasks** - Work across multiple sites simultaneously
### 📊 Access Your Browser Data
- **Bookmarks & History** - Find that article you read last week
- **Current page content** - Get selected text, links, or full page content
- **Real-time information** - Work with whatever's currently on your screen
### 🛡️ Anti-Detection Features
- **Social media posting** - Bypass automation detection on Twitter/X, LinkedIn, Facebook
- **Natural interactions** - Mimics human behavior to avoid triggering security measures
- **Reliable automation** - Works consistently even on sites that block typical automation tools
## 💬 Example Prompts to Try
Once everything is set up, try asking your AI:
**Content Creation:**
> *"Read the article on this page and create a Twitter thread summarizing the main points"*
**Research & Analysis:**
> *"Look through my browser history from this week and find articles about machine learning. Summarize the key trends."*
**Social Media Management:**
> *"Check my Twitter bookmarks and organize them into categories. Create a summary of each category."*
**Productivity:**
> *"Open tabs for my usual morning reading sites and give me a briefing of today's top stories"*
**Development Testing:**
> *"Fill out this contact form with test data and check if the submission works properly"*
**Personal Assistant:**
> *"Find that GitHub repo I was looking at yesterday about React components and bookmark it for later"*
## 🏗️ How It Works
```mermaid
graph LR
A[AI Model] --> B[OpenDia Server]
B --> C[Browser Extension]
C --> D[Your Browser]
D --> E[Any Website]
```
1. **You ask** your AI to do something browser-related
2. **AI calls** OpenDia tools to understand and interact with pages
3. **OpenDia controls** your browser through the extension
4. **You get results** - AI can see what happened and respond intelligently
## 🔒 Security & Privacy
**Your data stays private**:
-**Everything runs locally** - No cloud processing of your browsing data
-**You control access** - Extension only works when you want it to
-**Open source** - Full transparency of what the code does
-**No tracking** - We don't collect or store any of your information
**Important**: This tool requires broad browser permissions to function. Only use with AI models you trust, and in environments where you're comfortable with browser automation.
## 🤝 Contributing
Love to have your help making OpenDia better!
### Quick Development Setup
```bash
git clone https://github.com/aaronjmars/opendia.git
cd opendia
# Start the server
cd opendia-mcp
npm install
npm start
# Load extension in your browser
# Go to chrome://extensions/ → Developer mode → Load unpacked: ./opendia-extension
```
### Ways to Contribute
- 🐛 **Report bugs** via [GitHub Issues](https://github.com/aaronjmars/opendia/issues)
- 💡 **Share it on social medias**
- 🔧 **Add new browser capabilities**
- 📖 **Improve documentation**
- 🧪 **Test with different AI models**
## 📝 License
MIT License - see [LICENSE](LICENSE) for details.
---
**Ready to supercharge your browser with AI? Get started with `npx opendia`! 🚀**

View File

@@ -1,15 +1,23 @@
{
"name": "opendia-server",
"version": "1.0.0",
"name": "opendia",
"version": "1.0.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "opendia-server",
"version": "1.0.0",
"name": "opendia",
"version": "1.0.6",
"license": "MIT",
"dependencies": {
"express": "^4.x.x",
"ws": "^8.x.x"
"cors": "^2.8.5",
"express": "^4.21.2",
"ws": "^8.18.0"
},
"bin": {
"opendia": "server.js"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/accepts": {
@@ -78,7 +86,7 @@
}
},
"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",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
@@ -129,6 +137,19 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -522,6 +543,15 @@
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",

View File

@@ -1,13 +1,51 @@
{
"name": "opendia-server",
"version": "1.0.0",
"description": "MCP Server for OpenDia Browser Bridge",
"name": "opendia",
"version": "1.1.0",
"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",
"bin": {
"opendia": "./server.js"
},
"scripts": {
"start": "node server.js"
"start": "node server.js",
"tunnel": "node server.js --tunnel",
"sse-only": "node server.js --sse-only",
"tunnel-sse": "node server.js --tunnel --sse-only",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"mcp",
"browser",
"automation",
"ai",
"claude",
"chrome",
"extension",
"twitter",
"linkedin",
"facebook",
"anti-detection"
],
"author": "OpenDia Team",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/aaronjmars/opendia.git"
},
"homepage": "https://github.com/aaronjmars/opendia",
"bugs": {
"url": "https://github.com/aaronjmars/opendia/issues"
},
"dependencies": {
"ws": "^8.x.x",
"express": "^4.x.x"
}
}
"cors": "^2.8.5",
"express": "^4.21.2",
"ws": "^8.18.0"
},
"engines": {
"node": ">=16.0.0"
},
"files": [
"server.js",
"README.md"
]
}

1499
opendia-mcp/server.js Normal file → Executable file

File diff suppressed because it is too large Load Diff

BIN
opendia.dxt Normal file

Binary file not shown.