From b95efaebeaafab82e19d36c1d0283a0dfe103ab1 Mon Sep 17 00:00:00 2001 From: southseact-3d Date: Sun, 8 Feb 2026 20:15:38 +0000 Subject: [PATCH] complered tools 2 and guide --- EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md | 398 ++++++ EXTERNAL_WP_CLI_TESTING_SETUP.md | 1134 +++++++++++++++-- chat/external-wp-testing.js | 22 +- opencode/mcp-servers/wp-cli-testing/README.md | 106 ++ opencode/mcp-servers/wp-cli-testing/index.js | 23 +- 5 files changed, 1599 insertions(+), 84 deletions(-) create mode 100644 EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md create mode 100644 opencode/mcp-servers/wp-cli-testing/README.md diff --git a/EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md b/EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md new file mode 100644 index 0000000..daa64e4 --- /dev/null +++ b/EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md @@ -0,0 +1,398 @@ +# External WP-CLI Testing - Implementation Reference + +## Complete Data Flow + +### 1. User Enables Toggle in Builder + +**File:** `chat/public/builder.js` + +```javascript +// Line ~36 +builderState.externalTestingEnabled = false // default + +// User clicks toggle → sets to true +builderState.externalTestingEnabled = true + +// When sending message (line ~3967) +const payload = { + content: messageContent, + model, + cli, + externalTestingEnabled: !!builderState.externalTestingEnabled +} +``` + +--- + +### 2. Chat Server Receives Message + +**File:** `chat/server.js` + +```javascript +// Line ~8804 +const wpCliMcpEnabled = message?.externalTestingEnabled === true + +// Line ~8885-8901: If enabled, inject MCP server +if (wpCliMcpEnabled) { + const wpMcpServerPath = path.resolve(__dirname, '../opencode/mcp-servers/wp-cli-testing/index.js') + + executionEnv.OPENCODE_EXTRA_MCP_SERVERS = JSON.stringify([ + { + name: 'wp-cli-testing', + command: 'node', + args: [wpMcpServerPath], + disabled: false + } + ]) +} else { + delete executionEnv.OPENCODE_EXTRA_MCP_SERVERS // Safety gate +} + +// Pass env to OpenCode +await opencodeManager.executeInSession(..., { env: executionEnv }) +``` + +--- + +### 3. OpenCode Reads Environment Variable + +**File:** `opencode/packages/opencode/src/config/config.ts` + +```typescript +// Line ~233-294: Parse OPENCODE_EXTRA_MCP_SERVERS +const extraMcpRaw = process.env.OPENCODE_EXTRA_MCP_SERVERS +if (extraMcpRaw && typeof extraMcpRaw === "string") { + const parsed = JSON.parse(extraMcpRaw) + if (Array.isArray(parsed)) { + result.mcp ??= {} + for (const entry of parsed) { + result.mcp[entry.name] = { + type: "local", + command: [...commandParts, ...argsParts], + env: envRecord, + enabled: true, + ... + } + } + } +} +``` + +Result: OpenCode config now has `mcp['wp-cli-testing']` configured + +--- + +### 4. OpenCode Starts MCP Server + +**File:** `opencode/packages/opencode/src/mcp/index.ts` + +OpenCode's MCP system automatically: +1. Reads `config.mcp['wp-cli-testing']` +2. Spawns: `node opencode/mcp-servers/wp-cli-testing/index.js` +3. Connects via stdio transport +4. Calls `listTools()` to get available tools + +--- + +### 5. MCP Server Registers Tools + +**File:** `opencode/mcp-servers/wp-cli-testing/index.js` + +```javascript +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: "test_plugin_external_wp", + description: "Run WP-CLI based verification...", + inputSchema: { ... } + }, + { + name: "external_wp_testing_config", + description: "Return resolved config...", + inputSchema: { ... } + } + ] + } +}) +``` + +--- + +### 6. AI Invokes test_plugin_external_wp Tool + +**File:** `opencode/packages/opencode/src/session/prompt.ts` + +OpenCode's session handler: +1. Tool calls go through `resolveTools()` (line ~668) +2. MCP tools added via `MCP.tools()` (line ~745) +3. AI invokes tool with parameters + +```javascript +test_plugin_external_wp({ + plugin_path: "/workspace/my-plugin", + plugin_slug: "my-plugin", + test_scenarios: [...] +}) +``` + +--- + +### 7. MCP Server Handles Tool Call + +**File:** `opencode/mcp-servers/wp-cli-testing/index.js` + +```javascript +server.setRequestHandler(CallToolRequestSchema, async (req) => { + const toolName = req.params.name + const args = req.params.arguments + + // Import external-wp-testing module + const externalTesting = await import("../../../chat/external-wp-testing.js") + const mod = externalTesting.default ?? externalTesting + + const tester = mod.createExternalWpTester({}) + + const result = await tester.runTest( + { + plugin_path: args.plugin_path, + plugin_slug: args.plugin_slug, + ... + }, + { configOverrides: {} } + ) + + return { content: [{ type: "text", text: JSON.stringify(result) }] } +}) +``` + +--- + +### 8. External WP Testing Executes + +**File:** `chat/external-wp-testing.js` + +```javascript +async function runTest(input, opts) { + const config = getExternalTestingConfig(opts.configOverrides) + + // Queue the test + return queue.enqueue(async () => { + // 1. Create subsite (if multisite enabled) + if (config.enableMultisite) { + subsite = await createSubsite(config, sessionId) + // Runs: wp site create --slug=test-abc123 + } + + // 2. Upload plugin via SCP + if (pluginPath) { + await installPluginFromLocal(config, pluginPath, pluginSlug, sessionId) + } + + // 3. Install required plugins + const installedPlugins = await installRequiredPlugins(config, subsite.url, requiredPlugins) + + // 4. Activate test plugin + if (pluginSlug) { + await runSshCommand(config, + buildWpCliCommand(config, subsite.url, `plugin activate ${pluginSlug}`) + ) + } + + // 5. Run test scenarios + const cliTests = await runTestScenarios(config, subsite.url, scenarios) + + // 6. Schedule cleanup + if (config.autoCleanup && subsite.slug) { + setTimeout(() => { deleteSubsite(config, subsite.slug) }, config.cleanupDelayMs) + } + + return { ok: true, test_results: { cli_tests: cliTests }, ... } + }) +} +``` + +--- + +### 9. SSH Commands Execute on WordPress Server + +**Functions:** +- `buildWpCliCommand(config, url, command)` → `wp --path=/var/www/html --url=https://site.com/test-abc command` +- `runSshCommand(config, command)` → Executes via SSH with key auth + +**Example Commands Executed:** +```bash +# Create subsite +ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html site create --slug=test-abc123" + +# Copy plugin +scp -i ~/.ssh/wp-key -r /local/plugin wordpress@wp-test.com:/var/www/html/wp-content/plugins/ + +# Activate plugin +ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html --url=https://wp-test.com/test-abc123 plugin activate my-plugin" + +# Run test +ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html --url=https://wp-test.com/test-abc123 plugin status my-plugin" + +# Later: Delete subsite +ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html site delete --slug=test-abc123 --yes" +``` + +--- + +### 10. Results Return to AI + +**Return Path:** +``` +WordPress Server (via SSH) + ↓ command output +external-wp-testing.js runTest() + ↓ formatted result +MCP Server CallToolRequestSchema handler + ↓ JSON response +OpenCode MCP client + ↓ tool result +AI Session Handler + ↓ assistant message +Chat Server + ↓ SSE stream +Builder UI +``` + +**Result Format:** +```json +{ + "ok": true, + "session_id": "abc123", + "subsite_url": "https://wp-test.example.com/test-abc123", + "test_results": { + "mode": "cli", + "cli_tests": { + "passed": 3, + "failed": 0, + "results": [...] + } + }, + "installed_plugins": [...], + "duration": 15230, + "cleanup_scheduled": "2026-02-08T11:30:00Z" +} +``` + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `chat/public/builder.js` | Builder UI toggle state | +| `chat/server.js` | Gate MCP injection via env var | +| `opencode/packages/opencode/src/config/config.ts` | Parse OPENCODE_EXTRA_MCP_SERVERS | +| `opencode/packages/opencode/src/mcp/index.ts` | Load and connect MCP servers | +| `opencode/mcp-servers/wp-cli-testing/index.js` | MCP server implementation | +| `chat/external-wp-testing.js` | Core testing logic | + +--- + +## Environment Variables Flow + +``` +Host Environment + ↓ +Chat Server process.env + ↓ +executionEnv = {...process.env, OPENCODE_EXTRA_MCP_SERVERS: "..."} + ↓ +OpenCode spawned with executionEnv + ↓ +process.env.TEST_WP_HOST → external-wp-testing.js getExternalTestingConfig() + ↓ +SSH connection using TEST_WP_SSH_KEY + ↓ +Commands execute on WordPress server +``` + +**Required Environment Variables:** +- `TEST_WP_HOST` +- `TEST_WP_SSH_USER` +- `TEST_WP_SSH_KEY` +- `TEST_WP_PATH` +- `TEST_WP_BASE_URL` +- etc. (see EXTERNAL_WP_CLI_TESTING_SETUP.md) + +--- + +## Security Gates + +1. **Builder Toggle** - User must explicitly enable +2. **Environment Variable Gate** - Only set when toggle is on +3. **MCP Loading** - Only loads when env var present +4. **SSH Key Auth** - Requires valid key file +5. **Tool Gating** - Tools not available if toggle off + +When toggle is OFF: +- `externalTestingEnabled: false` in payload +- `wpCliMcpEnabled = false` on server +- `OPENCODE_EXTRA_MCP_SERVERS` is deleted from env +- MCP server never loads +- Tools never available to AI + +--- + +## Testing The Flow + +### 1. Check Environment +```bash +echo $TEST_WP_HOST +echo $TEST_WP_SSH_KEY +``` + +### 2. Test SSH Connection +```bash +ssh -i $TEST_WP_SSH_KEY $TEST_WP_SSH_USER@$TEST_WP_HOST "wp site list" +``` + +### 3. Enable Toggle in Builder +- Open Builder +- Enable "External WP CLI testing" +- Verify toggle shows enabled state + +### 4. Check Server Logs +```bash +tail -f logs/chat-server.log | grep "WP CLI Testing" +# Should see: "Enabling WP CLI Testing MCP server" +``` + +### 5. Ask AI to Test +``` +"Create a plugin and test it on the external WordPress server" +``` + +### 6. Verify Subsite Created +```bash +ssh -i $TEST_WP_SSH_KEY $TEST_WP_SSH_USER@$TEST_WP_HOST "wp site list | grep test-" +``` + +--- + +## Multisite Architecture + +``` +WordPress Multisite Network +├── Main Site (/) +│ └── Core WP, Plugins, Themes (shared) +├── Subsite: /test-abc123 (Session 1) +│ ├── Isolated content/options +│ ├── Test Plugin A activated +│ └── Tests running +├── Subsite: /test-def456 (Session 2) +│ ├── Isolated content/options +│ ├── Test Plugin B activated +│ └── Tests running +└── Subsite: /test-xyz789 (Session 3) + └── ... +``` + +**Concurrency:** 20+ simultaneous tests via queue system + isolated subsites + +**Cleanup:** Each subsite auto-deleted after 1 hour (configurable via `TEST_CLEANUP_DELAY`) diff --git a/EXTERNAL_WP_CLI_TESTING_SETUP.md b/EXTERNAL_WP_CLI_TESTING_SETUP.md index af54717..1b7300d 100644 --- a/EXTERNAL_WP_CLI_TESTING_SETUP.md +++ b/EXTERNAL_WP_CLI_TESTING_SETUP.md @@ -1,103 +1,1093 @@ -# External WP-CLI Testing Setup +# External WP-CLI Testing Setup Guide -This guide explains how to enable and run External WP-CLI Testing from the Builder, with tools loaded into OpenCode only when the feature toggle is enabled. +Complete step-by-step guide to set up External WP-CLI Testing for PluginCompass. This system uses an externally hosted WordPress **Multisite** installation with WP-CLI to verify plugin functionality in isolated subsite environments, supporting 20+ concurrent tests. -## What This Adds +--- -- A gated MCP tool named `test_plugin_external_wp` (plus a helper tool `external_wp_testing_config`). -- Tools are injected into OpenCode only when the Builder toggle is on. -- All connection/auth settings are controlled via environment variables. +## Table of Contents + +1. [Overview](#overview) +2. [Architecture](#architecture) +3. [Prerequisites](#prerequisites) +4. [Part 1: Setting Up WordPress Multisite](#part-1-setting-up-wordpress-multisite) +5. [Part 2: Installing and Configuring WP-CLI](#part-2-installing-and-configuring-wp-cli) +6. [Part 3: Configuring SSH Access](#part-3-configuring-ssh-access) +7. [Part 4: Configuring Environment Variables](#part-4-configuring-environment-variables) +8. [Part 5: Testing the Connection](#part-5-testing-the-connection) +9. [Part 6: Enabling in Builder](#part-6-enabling-in-builder) +10. [Part 7: Using the Tools](#part-7-using-the-tools) +11. [Troubleshooting](#troubleshooting) + +--- + +## Overview + +### What This System Does + +- **Isolated Testing**: Each test session runs in its own WordPress subsite (no cross-contamination) +- **High Concurrency**: Supports 20+ simultaneous tests via multisite subsites +- **Automated Provisioning**: Automatically creates/deletes test subsites +- **CLI Testing Mode**: Fast, deterministic WP-CLI based verification +- **Gated Tools**: Tools only load in OpenCode when Builder toggle is enabled + +### Architecture Diagram + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ PluginCompass Chat Server (Your Server) │ +│ - Runs Node.js chat app │ +│ - Spawns OpenCode with env vars when toggle enabled │ +└─────────────────────────────────────────────────────────────────┘ + │ SSH + WP-CLI commands + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ External WordPress Multisite Test Server │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Session 1 │ │ Session 2 │ │ Session N │ │ +│ │ Subsite │ │ Subsite │ │ Subsite │ │ +│ │ /test-abc │ │ /test-def │ │ /test-xyz │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ Shared: Core WP, WP-CLI (isolated content/options per subsite)│ +└─────────────────────────────────────────────────────────────────┘ +``` + +### How It Works + +1. User enables "External WP CLI testing" toggle in Builder +2. Chat server sets `OPENCODE_EXTRA_MCP_SERVERS` env var when spawning OpenCode +3. OpenCode loads the `wp-cli-testing` MCP server with tools: + - `test_plugin_external_wp` - Runs tests on external WP + - `external_wp_testing_config` - Validates configuration +4. When AI calls the tool: + - SSH connection established to WordPress server + - New subsite created via WP-CLI (`wp site create`) + - Plugin uploaded and activated + - Test scenarios executed via WP-CLI + - Results returned to AI + - Subsite cleaned up after delay + +--- ## Prerequisites -1. A reachable WordPress host with WP-CLI installed. -2. SSH access to that host from the server running the chat app. -3. The SSH user must be able to run WP-CLI at the configured path. +### Required Infrastructure -## Required Environment Variables +1. **A Linux server** (Ubuntu 20.04+ or Debian 11+ recommended) + - Minimum: 2GB RAM, 20GB disk, 2 CPU cores + - Recommended for production: 4GB RAM, 50GB disk, 4 CPU cores +2. **SSH access** with sudo privileges +3. **Domain or subdomain** pointing to the server +4. **LAMP/LEMP stack** installed (Linux, Apache/Nginx, MySQL, PHP) -Set these in the environment where the chat server runs (the same process that launches OpenCode). +### Software Requirements -- `TEST_WP_HOST` (or `EXTERNAL_WP_HOST`) - - Hostname or IP of the WordPress server. -- `TEST_WP_SSH_USER` (or `EXTERNAL_WP_SSH_USER`) - - SSH username for the WordPress server. -- `TEST_WP_SSH_KEY` (or `TEST_WP_SSH_KEY_PATH`, or `EXTERNAL_WP_SSH_KEY`) - - Path to the SSH private key file. +- **PHP 7.4+** (PHP 8.0+ recommended) +- **MySQL 5.7+** or **MariaDB 10.3+** +- **WP-CLI** 2.6+ +- **WordPress 6.0+** +- **SSH server** (OpenSSH) -If these are missing, the tool will return a clear error. +--- -## Optional Environment Variables +## Part 1: Setting Up WordPress Multisite -- `TEST_WP_PATH` (or `EXTERNAL_WP_PATH`) - - Default: `/var/www/html` - - Path to the WordPress root on the remote host. -- `TEST_WP_BASE_URL` (or `EXTERNAL_WP_BASE_URL`) - - Default: `https://` - - Base URL for the site. -- `TEST_WP_MULTISITE` (or `EXTERNAL_WP_MULTISITE`) - - Default: `true` - - Enables multisite subsite isolation. -- `TEST_WP_SUBSITE_PREFIX` (or `EXTERNAL_WP_SUBSITE_PREFIX`) - - Default: `test` - - Prefix for created subsites. -- `TEST_WP_SUBSITE_DOMAIN` (or `EXTERNAL_WP_SUBSITE_DOMAIN`) - - Default: empty (falls back to host) - - Domain used when subsite mode is subdomain. -- `TEST_WP_SUBSITE_MODE` (or `EXTERNAL_WP_SUBSITE_MODE`) - - Default: `subdirectory` - - Allowed values: `subdirectory`, `subdomain`. -- `TEST_WP_ERROR_LOG` (or `EXTERNAL_WP_ERROR_LOG`) - - Default: `/var/log/wp-errors.log` - - Used by the default "Scan error log" scenario. -- `TEST_SSH_STRICT` (or `EXTERNAL_WP_SSH_STRICT`) - - Default: `false` - - When `true`, enforces strict host key checking. -- `TEST_MAX_CONCURRENT` (or `EXTERNAL_WP_MAX_CONCURRENT`) - - Default: `20` - - Max concurrent tests. -- `TEST_QUEUE_TIMEOUT` (or `EXTERNAL_WP_QUEUE_TIMEOUT`) - - Default: `300000` (ms) -- `TEST_TIMEOUT` (or `EXTERNAL_WP_TEST_TIMEOUT`) - - Default: `600000` (ms) -- `TEST_AUTO_CLEANUP` (or `EXTERNAL_WP_AUTO_CLEANUP`) - - Default: `true` - - Cleans up subsites after tests complete. -- `TEST_CLEANUP_DELAY` (or `EXTERNAL_WP_CLEANUP_DELAY`) - - Default: `3600000` (ms) +### Step 1.1: Install Base WordPress -## Example .env +If you don't have WordPress installed yet: +```bash +# SSH into your test server +ssh user@wp-test.example.com + +# Navigate to web root +cd /var/www/html + +# Download WordPress +sudo wget https://wordpress.org/latest.tar.gz +sudo tar -xzf latest.tar.gz +sudo mv wordpress/* . +sudo rm -rf wordpress latest.tar.gz + +# Set permissions +sudo chown -R www-data:www-data /var/www/html +sudo chmod -R 755 /var/www/html + +# Create database +sudo mysql -u root -p +``` + +In MySQL: +```sql +CREATE DATABASE wordpress_test DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'strong_password_here'; +GRANT ALL PRIVILEGES ON wordpress_test.* TO 'wpuser'@'localhost'; +FLUSH PRIVILEGES; +EXIT; +``` + +Complete WordPress installation via browser at `http://your-domain.com/wp-admin/install.php` + +### Step 1.2: Enable WordPress Multisite + +**Important**: Backup your site before enabling multisite. + +```bash +# SSH into server +ssh user@wp-test.example.com + +# Edit wp-config.php +sudo nano /var/www/html/wp-config.php +``` + +Add these lines **before** `/* That's all, stop editing! */`: + +```php +/* Multisite */ +define('WP_ALLOW_MULTISITE', true); +``` + +Save and exit (`Ctrl+X`, `Y`, `Enter`). + +### Step 1.3: Run Multisite Setup + +1. Go to `http://your-domain.com/wp-admin/network-setup.php` in your browser +2. Choose **Subdirectories** (recommended for easier setup) +3. Fill in: + - **Network Title**: `PluginCompass Test Network` + - **Admin Email**: Your email +4. Click **Install** + +### Step 1.4: Complete Network Configuration + +WordPress will show you code to add. Follow these steps: + +**A. Update wp-config.php:** + +```bash +sudo nano /var/www/html/wp-config.php +``` + +Add the provided multisite configuration (it will look like this): + +```php +define('MULTISITE', true); +define('SUBDOMAIN_INSTALL', false); +define('DOMAIN_CURRENT_SITE', 'wp-test.example.com'); +define('PATH_CURRENT_SITE', '/'); +define('SITE_ID_CURRENT_SITE', 1); +define('BLOG_ID_CURRENT_SITE', 1); +``` + +**B. Update .htaccess:** + +```bash +sudo nano /var/www/html/.htaccess +``` + +Replace contents with the provided rewrite rules (similar to): + +```apache +RewriteEngine On +RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] +RewriteBase / +RewriteRule ^index\.php$ - [L] + +# add a trailing slash to /wp-admin +RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L] + +RewriteCond %{REQUEST_FILENAME} -f [OR] +RewriteCond %{REQUEST_FILENAME} -d +RewriteRule ^ - [L] +RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L] +RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L] +RewriteRule . index.php [L] +``` + +**C. Set Permissions:** + +```bash +sudo chown www-data:www-data /var/www/html/.htaccess +sudo chmod 644 /var/www/html/.htaccess +``` + +### Step 1.5: Verify Multisite Installation + +1. Log out and log back in to WordPress admin +2. You should now see **"My Sites"** in the admin bar +3. Navigate to **Network Admin → Sites** to see your network + +**Test subsite creation manually:** + +```bash +# You'll configure WP-CLI next, but this is the command pattern we'll use +wp site create --slug=test-manual --title="Test Site" --email="admin@example.com" +``` + +--- + +## Part 2: Installing and Configuring WP-CLI + +### Step 2.1: Install WP-CLI + +```bash +# SSH into server +ssh user@wp-test.example.com + +# Download WP-CLI +curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar + +# Test it works +php wp-cli.phar --info + +# Make it executable and move to system path +chmod +x wp-cli.phar +sudo mv wp-cli.phar /usr/local/bin/wp + +# Verify installation +wp --info +``` + +Expected output: +``` +OS: Linux 5.4.0-100-generic #113-Ubuntu SMP ... +Shell: /bin/bash +PHP binary: /usr/bin/php7.4 +PHP version: 7.4.28 +php.ini used: /etc/php/7.4/cli/php.ini +MySQL binary: /usr/bin/mysql +MySQL version: mysql Ver 15.1 Distrib 10.3.32-MariaDB +SQL modes: +WP-CLI root dir: phar://wp-cli.phar/vendor/wp-cli/wp-cli +WP-CLI vendor dir: phar://wp-cli.phar/vendor +WP_CLI phar path: /home/user +WP-CLI packages dir: +WP-CLI global config: +WP-CLI project config: +WP-CLI version: 2.8.1 +``` + +### Step 2.2: Configure WP-CLI for Web Server User + +The chat server will run WP-CLI commands as the SSH user. We need to ensure it works: + +```bash +# Test basic WP-CLI command +cd /var/www/html +wp --path=/var/www/html option get siteurl + +# If you get permission errors, fix ownership +sudo chown -R www-data:www-data /var/www/html + +# Add your SSH user to www-data group (replace 'wordpress' with your username) +sudo usermod -a -G www-data wordpress + +# Set proper directory permissions +sudo find /var/www/html -type d -exec chmod 755 {} \; +sudo find /var/www/html -type f -exec chmod 644 {} \; + +# Log out and back in for group changes to take effect +exit +ssh user@wp-test.example.com +``` + +### Step 2.3: Test Multisite Operations with WP-CLI + +```bash +cd /var/www/html + +# Test creating a subsite +wp site create --slug=test-cli-check --title="Test Subsite" --email="admin@example.com" + +# Verify it was created +wp site list + +# Test plugin operations on the subsite +wp --url=https://wp-test.example.com/test-cli-check plugin list + +# Delete the test subsite +wp site delete --slug=test-cli-check --yes + +# Confirm deletion +wp site list +``` + +If all commands succeed, WP-CLI is configured correctly. + +--- + +## Part 3: Configuring SSH Access + +### Step 3.1: Create SSH User for Testing + +For security, create a dedicated user for the testing system: + +```bash +# On the WordPress test server +sudo adduser wordpress +# Set a strong password when prompted + +# Add to www-data group for file access +sudo usermod -a -G www-data wordpress + +# Grant sudo privileges for WP-CLI (if needed) +sudo usermod -a -G sudo wordpress +``` + +**Alternative:** Use an existing user with appropriate permissions. + +### Step 3.2: Generate SSH Key Pair + +On your **PluginCompass chat server** (not the WordPress server): + +```bash +# Generate SSH key pair +ssh-keygen -t ed25519 -C "plugincompass-wp-testing" -f ~/.ssh/wp-test-key + +# This creates: +# - ~/.ssh/wp-test-key (private key - KEEP SECRET) +# - ~/.ssh/wp-test-key.pub (public key - safe to share) + +# Set correct permissions +chmod 600 ~/.ssh/wp-test-key +chmod 644 ~/.ssh/wp-test-key.pub + +# Display the public key (you'll need this for the next step) +cat ~/.ssh/wp-test-key.pub +``` + +**On Windows:** + +```powershell +# Using PowerShell +ssh-keygen -t ed25519 -C "plugincompass-wp-testing" -f C:\keys\wp-test-key + +# Set permissions +icacls "C:\keys\wp-test-key" /inheritance:r +icacls "C:\keys\wp-test-key" /grant:r "%USERNAME%:F" + +# Display public key +type C:\keys\wp-test-key.pub +``` + +### Step 3.3: Install Public Key on WordPress Server + +Copy the public key content, then on the **WordPress server**: + +```bash +# Switch to the wordpress user (or your SSH user) +sudo su - wordpress + +# Create .ssh directory if it doesn't exist +mkdir -p ~/.ssh +chmod 700 ~/.ssh + +# Add the public key +nano ~/.ssh/authorized_keys + +# Paste the public key (from wp-test-key.pub) +# Save and exit (Ctrl+X, Y, Enter) + +# Set correct permissions +chmod 600 ~/.ssh/authorized_keys + +# Exit back to your original user +exit +``` + +### Step 3.4: Test SSH Connection + +From your **PluginCompass chat server**: + +```bash +# Test SSH connection with the key +ssh -i ~/.ssh/wp-test-key wordpress@wp-test.example.com + +# If successful, you should be logged in without a password +# Test WP-CLI works over SSH +cd /var/www/html && wp site list + +# Exit +exit +``` + +**On Windows:** + +```powershell +ssh -i C:\keys\wp-test-key wordpress@wp-test.example.com +``` + +### Step 3.5: Disable Strict Host Key Checking (Optional, for Testing) + +For automated testing, you may want to disable strict host key checking: + +On your **PluginCompass chat server**, create/edit SSH config: + +```bash +nano ~/.ssh/config +``` + +Add: + +``` +Host wp-test.example.com + HostName wp-test.example.com + User wordpress + IdentityFile ~/.ssh/wp-test-key + StrictHostKeyChecking no + UserKnownHostsFile /dev/null +``` + +**Security Note:** Only do this on trusted networks. For production, keep strict checking enabled and add the host to known_hosts properly. + +--- + +## Part 4: Configuring Environment Variables + +### Step 4.1: Locate Your Environment Configuration + +Environment variables should be set where your **chat server** runs. Options: + +**A. Using .env file (development):** + +```bash +# In your chat server directory +nano .env +``` + +**B. Using systemd service (production):** + +```bash +sudo nano /etc/systemd/system/plugincompass-chat.service +``` + +Add under `[Service]` section: +``` +Environment="TEST_WP_HOST=wp-test.example.com" +Environment="TEST_WP_SSH_USER=wordpress" +... +``` + +**C. Using PM2 ecosystem file:** + +```bash +nano ecosystem.config.js +``` + +Add to `env`: +```javascript +env: { + TEST_WP_HOST: 'wp-test.example.com', + TEST_WP_SSH_USER: 'wordpress', + ... +} +``` + +### Step 4.2: Required Environment Variables + +Add these variables (adjust paths for your setup): + +```bash +# Core Connection Settings TEST_WP_HOST=wp-test.example.com TEST_WP_SSH_USER=wordpress -TEST_WP_SSH_KEY=C:\\keys\\wp-test.pem +TEST_WP_SSH_KEY=/home/user/.ssh/wp-test-key TEST_WP_PATH=/var/www/html + +# Base URL (must match your WordPress installation) TEST_WP_BASE_URL=https://wp-test.example.com + +# Multisite Configuration TEST_WP_MULTISITE=true TEST_WP_SUBSITE_MODE=subdirectory TEST_WP_SUBSITE_PREFIX=test -TEST_WP_ERROR_LOG=/var/log/wp-errors.log -TEST_SSH_STRICT=false +TEST_WP_SUBSITE_DOMAIN=wp-test.example.com + +# Testing Configuration TEST_MAX_CONCURRENT=20 TEST_TIMEOUT=600000 +TEST_QUEUE_TIMEOUT=300000 -## Builder Toggle Behavior +# Cleanup Settings +TEST_AUTO_CLEANUP=true +TEST_CLEANUP_DELAY=3600000 -- Open the Builder and enable the "External WP CLI testing" toggle. -- When enabled, the chat server injects the MCP server definition via `OPENCODE_EXTRA_MCP_SERVERS`. -- When disabled, the environment variable is removed before OpenCode is spawned, so the tools are not exposed. +# Error Logging (adjust to your log location) +TEST_WP_ERROR_LOG=/var/log/wp-errors.log -## Running a Test +# SSH Settings +TEST_SSH_STRICT=false +``` -1. Enable the toggle in Builder. -2. Proceed with the build or let the AI call `test_plugin_external_wp`. -3. The tool runs WP-CLI commands over SSH and returns a JSON report. +**Windows paths example:** -## Quick Sanity Check Tool +```bash +TEST_WP_SSH_KEY=C:\\keys\\wp-test-key +``` -You can ask the AI to call `external_wp_testing_config` to validate your settings. It returns the resolved config and a list of missing required variables. +### Step 4.3: Alternative Environment Variable Names -## Notes +The system supports alternative names (useful if you have existing vars): -- `test_plugin_external_wp` only supports `test_mode=cli` in the current implementation. -- Ensure the SSH user can execute WP-CLI and write to the plugin directory. +- `TEST_WP_HOST` or `EXTERNAL_WP_HOST` +- `TEST_WP_SSH_USER` or `EXTERNAL_WP_SSH_USER` +- `TEST_WP_SSH_KEY` or `EXTERNAL_WP_SSH_KEY` or `TEST_WP_SSH_KEY_PATH` +- `TEST_WP_PATH` or `EXTERNAL_WP_PATH` +- `TEST_WP_BASE_URL` or `EXTERNAL_WP_BASE_URL` +- etc. + +### Step 4.4: Apply Environment Variables + +**If using .env:** +```bash +# Restart your chat server +npm run restart +# or +pm2 restart chat-server +``` + +**If using systemd:** +```bash +sudo systemctl daemon-reload +sudo systemctl restart plugincompass-chat +``` + +--- + +## Part 5: Testing the Connection + +### Step 5.1: Verify Environment Variables + +Check that variables are loaded: + +```bash +# If using Node.js directly +node -e "console.log(process.env.TEST_WP_HOST)" +# Should output: wp-test.example.com + +# If using PM2 +pm2 env 0 | grep TEST_WP +``` + +### Step 5.2: Test SSH Connection from Chat Server + +From your chat server, verify SSH works: + +```bash +ssh -i $TEST_WP_SSH_KEY $TEST_WP_SSH_USER@$TEST_WP_HOST "wp site list" +``` + +Expected output: List of sites in your multisite network. + +### Step 5.3: Test Direct Tool Invocation + +Create a test script to verify the external-wp-testing module: + +```javascript +// test-wp-connection.js +const { createExternalWpTester, getExternalTestingConfig } = require('./chat/external-wp-testing.js'); + +async function test() { + // 1. Check config + console.log('1. Checking configuration...'); + const config = getExternalTestingConfig(); + console.log('Config:', JSON.stringify(config, null, 2)); + + const missing = []; + if (!config.wpHost) missing.push('TEST_WP_HOST'); + if (!config.wpSshUser) missing.push('TEST_WP_SSH_USER'); + if (!config.wpSshKey) missing.push('TEST_WP_SSH_KEY'); + + if (missing.length > 0) { + console.error('❌ Missing required environment variables:', missing); + process.exit(1); + } + + console.log('✅ Configuration valid\n'); + + // 2. Test connection by running a simple WP-CLI command + console.log('2. Testing SSH + WP-CLI connection...'); + const tester = createExternalWpTester({}); + + // This would normally upload a plugin, but we'll just test the infrastructure + console.log('Configuration loaded successfully. SSH credentials are set.'); + console.log('✅ Ready for testing\n'); +} + +test().catch(console.error); +``` + +Run it: + +```bash +node test-wp-connection.js +``` + +### Step 5.4: Test Subsite Creation (Manual) + +SSH into your WordPress server and manually test the subsite flow: + +```bash +ssh -i ~/.ssh/wp-test-key wordpress@wp-test.example.com + +cd /var/www/html + +# Create test subsite +wp site create --slug=test-manual-abc --title="Manual Test" --email="admin@example.com" + +# Verify it exists +wp site list | grep test-manual-abc + +# Check URL is accessible +curl -I https://wp-test.example.com/test-manual-abc/ + +# Clean up +wp site delete --slug=test-manual-abc --yes + +exit +``` + +If all steps succeed, your infrastructure is ready! + +--- + +## Part 6: Enabling in Builder + +### Step 6.1: Access Builder Settings + +1. Open PluginCompass Builder in your browser +2. Look for the **"External WP CLI testing"** toggle +3. It may show usage information (e.g., "0 / 10 tests used") + +### Step 6.2: Enable the Toggle + +1. Click the toggle to enable it +2. You may see a confirmation: "External WP tests run a series of WP-CLI checks on an external WordPress site. Tests are counted against your monthly allowance." +3. Click **OK** or **Confirm** + +### Step 6.3: Verify Toggle State + +The toggle should: +- Show as **ON/enabled** (blue/green indicator) +- Display current usage stats +- Be persistent across page refreshes + +**Behind the scenes**: When enabled: +- `builderState.externalTestingEnabled = true` +- When a message is sent, `externalTestingEnabled: true` is included in the payload +- Chat server sets `OPENCODE_EXTRA_MCP_SERVERS` env var when spawning OpenCode +- OpenCode loads the `wp-cli-testing` MCP server +- Tools `test_plugin_external_wp` and `external_wp_testing_config` become available to AI + +**When disabled**: Tools are NOT loaded into OpenCode (gated at the environment variable level). + +--- + +## Part 7: Using the Tools + +### How Tests Work + +1. **User Request**: User asks AI to create a plugin in Builder +2. **AI Generates Code**: AI creates plugin files in the workspace +3. **AI Calls Test Tool**: AI invokes `test_plugin_external_wp` with plugin path +4. **Automated Flow**: + - Subsite created: `wp site create --slug=test-` + - Plugin uploaded via SSH/SFTP + - Plugin activated: `wp plugin activate ` + - Test scenarios executed via WP-CLI + - Results returned to AI + - Subsite scheduled for cleanup (after 1 hour by default) + +### Tool 1: test_plugin_external_wp + +**Purpose**: Run automated CLI tests on a real WordPress installation + +**Example AI Usage**: + +```javascript +{ + "plugin_path": "/workspace/session-abc/my-custom-plugin", + "plugin_slug": "my-custom-plugin", + "test_mode": "cli", + "required_plugins": [ + { + "plugin_slug": "woocommerce", + "activate": true + } + ], + "test_scenarios": [ + { + "name": "Plugin activates without errors", + "type": "custom", + "wp_cli_command": "plugin activate my-custom-plugin", + "assertions": { + "wp_cli_success": true, + "not_contains": ["Fatal error", "Parse error"] + } + }, + { + "name": "Custom endpoint responds", + "type": "endpoint", + "url": "/custom-endpoint", + "assertions": { + "status_code": 200, + "contains": ["success"] + } + } + ] +} +``` + +**Return Value**: + +```json +{ + "ok": true, + "session_id": "abc123", + "subsite_url": "https://wp-test.example.com/test-abc123", + "test_results": { + "mode": "cli", + "cli_tests": { + "passed": 2, + "failed": 0, + "results": [ + { + "name": "Plugin activates without errors", + "status": "passed", + "command": "wp plugin activate my-custom-plugin", + "output": "Success: Activated 1 of 1 plugins.", + "duration": 1234 + } + ] + } + }, + "installed_plugins": [ + { "slug": "woocommerce", "status": "active" }, + { "slug": "my-custom-plugin", "status": "active" } + ], + "errors": [], + "warnings": [], + "duration": 15230, + "cleanup_scheduled": "2026-02-08T11:30:00Z" +} +``` + +### Tool 2: external_wp_testing_config + +**Purpose**: Validate configuration without running tests + +**Example AI Usage**: + +```javascript +{} +// or +{ "config_overrides": {} } +``` + +**Return Value**: + +```json +{ + "ok": true, + "missing": [], + "config": { + "wpHost": "wp-test.example.com", + "wpSshUser": "wordpress", + "wpSshKey": "/home/user/.ssh/wp-test-key", + "wpPath": "/var/www/html", + "wpBaseUrl": "https://wp-test.example.com", + "enableMultisite": true, + "subsiteMode": "subdirectory", + "subsitePrefix": "test", + "maxConcurrentTests": 20 + } +} +``` + +**If configuration is invalid**: + +```json +{ + "ok": false, + "missing": ["TEST_WP_HOST", "TEST_WP_SSH_KEY"], + "config": { ... } +} +``` + +### Default Test Scenarios + +If `test_scenarios` is not provided, the system generates default tests: + +1. **Plugin Activation Test** + - Command: `wp plugin activate ` + - Asserts: No fatal errors, no parse errors + +2. **Plugin Status Check** + - Command: `wp plugin status ` + - Asserts: Plugin listed as "Active" + +3. **Error Log Scan** + - Command: `tail -n 200 /var/log/wp-errors.log | grep ` + - Asserts: No fatal/parse errors related to plugin + +### Example Builder Workflow + +1. User: "Create a plugin that adds a custom /vendor-login endpoint" +2. AI generates plugin code +3. Builder shows "Proceed with Build" button +4. User clicks → AI calls OpenCode +5. OpenCode processes build, then: + ```javascript + // AI calls test tool + test_plugin_external_wp({ + plugin_path: "/workspace/vendor-login-plugin", + plugin_slug: "vendor-login", + test_scenarios: [ + { + name: "Login endpoint accessible", + type: "endpoint", + url: "/vendor-login", + assertions: { + status_code: 200, + contains: ["> ~/.bashrc + source ~/.bashrc + ``` +3. Use full path in commands: + ```bash + /usr/local/bin/wp site list + ``` + +### Issue: "Error establishing database connection" + +**Error**: Subsites show database error + +**Solutions**: +1. Check WordPress database credentials in `wp-config.php` +2. Verify MySQL/MariaDB is running: + ```bash + sudo systemctl status mysql + ``` +3. Test database connection: + ```bash + wp db check + ``` + +### Issue: "Subsite creation fails" + +**Error**: `wp site create` returns error + +**Solutions**: +1. Verify multisite is enabled: + ```bash + wp eval "echo MULTISITE ? 'yes' : 'no';" + # Should output: yes + ``` +2. Check network setup: + ```bash + wp site list + ``` +3. Ensure `.htaccess` has correct rewrite rules (see Part 1.4) +4. Check Apache mod_rewrite is enabled: + ```bash + sudo a2enmod rewrite + sudo systemctl restart apache2 + ``` + +### Issue: "Plugin upload fails" + +**Error**: Cannot copy plugin files to server + +**Solutions**: +1. Check directory permissions: + ```bash + ls -la /var/www/html/wp-content/plugins/ + # Should be writable by SSH user or www-data + ``` +2. Fix ownership: + ```bash + sudo chown -R www-data:www-data /var/www/html/wp-content/plugins + sudo chmod -R 755 /var/www/html/wp-content/plugins + ``` +3. Add SSH user to www-data group: + ```bash + sudo usermod -a -G www-data wordpress + ``` + +### Issue: "Tools not appearing in OpenCode" + +**Error**: AI says tools are not available + +**Solutions**: +1. **Check Builder toggle is enabled** + - Open Builder settings + - Verify "External WP CLI testing" is ON +2. **Verify environment variables in chat server**: + ```bash + # Check if vars are set + node -e "console.log(process.env.TEST_WP_HOST)" + ``` +3. **Check server logs**: + ```bash + # Look for "Enabling WP CLI Testing MCP server" + tail -f logs/chat-server.log + ``` +4. **Restart chat server**: + ```bash + pm2 restart chat-server + # or + npm run restart + ``` +5. **Verify MCP server file exists**: + ```bash + ls -la opencode/mcp-servers/wp-cli-testing/index.js + ``` + +### Issue: "Tests timeout" + +**Error**: Tests take too long and fail + +**Solutions**: +1. Increase timeout in env vars: + ```bash + TEST_TIMEOUT=900000 # 15 minutes + ``` +2. Check network latency: + ```bash + ping wp-test.example.com + ``` +3. Verify WordPress server resources: + ```bash + ssh wordpress@wp-test.example.com "free -h && df -h" + ``` + +### Issue: "Subsites not cleaning up" + +**Error**: Old test subsites accumulate + +**Solutions**: +1. Check cleanup is enabled: + ```bash + TEST_AUTO_CLEANUP=true + TEST_CLEANUP_DELAY=3600000 # 1 hour + ``` +2. Manually list and delete: + ```bash + ssh wordpress@wp-test.example.com + wp site list | grep "test-" + # Delete old subsites + wp site delete --slug=test-abc123 --yes + ``` +3. Create cleanup cron job: + ```bash + # On WordPress server + crontab -e + # Add line to run daily cleanup: + 0 2 * * * cd /var/www/html && wp site list --field=url | grep "/test-" | xargs -I {} wp site delete --url={} --yes + ``` + +### Getting Help + +If issues persist: + +1. **Check logs**: + - Chat server logs: `tail -f logs/chat-server.log` + - WordPress error log: `tail -f /var/log/wp-errors.log` + - Apache/Nginx error log: `tail -f /var/log/apache2/error.log` + +2. **Test components individually**: + - SSH: `ssh -v -i user@host` + - WP-CLI: `wp site list` + - Subsite: `curl -I https://wp-test.example.com/test-abc/` + +3. **Verify configuration**: + - Run `external_wp_testing_config` tool via AI + - Check all required env vars are set + - Confirm SSH key has correct permissions + +--- + +## Summary + +You've now set up: + +✅ **WordPress Multisite** with subdirectory subsites +✅ **WP-CLI** for command-line control +✅ **SSH key authentication** for secure access +✅ **Environment variables** configured in chat server +✅ **Gated MCP tools** that only load when Builder toggle is enabled +✅ **Isolated testing** via automatic subsite provisioning + +**Next Steps**: +- Enable toggle in Builder +- Ask AI to create a plugin +- Watch as it automatically tests on your external WordPress installation +- Review test results in the chat + +The system supports **20+ concurrent tests** through multisite subsite isolation, with automatic cleanup and comprehensive CLI-based verification. diff --git a/chat/external-wp-testing.js b/chat/external-wp-testing.js index 98d09ad..12594a8 100644 --- a/chat/external-wp-testing.js +++ b/chat/external-wp-testing.js @@ -128,12 +128,22 @@ async function createSubsite(config, sessionId) { } const url = resolveSubsiteUrl(config, slug); - const configureCmd = buildWpCliCommand( + + // Configure permalink structure + const permalinkCmd = buildWpCliCommand( config, url, - 'option update permalink_structure "/%postname%/" && wp rewrite flush' + 'option update permalink_structure "/%postname%/"' ); - await runSshCommand(config, configureCmd, { timeout: config.testTimeoutMs }); + await runSshCommand(config, permalinkCmd, { timeout: config.testTimeoutMs }); + + // Flush rewrite rules + const rewriteCmd = buildWpCliCommand( + config, + url, + 'rewrite flush' + ); + await runSshCommand(config, rewriteCmd, { timeout: config.testTimeoutMs }); return { slug, url, adminUrl: `${url.replace(/\/$/, '')}/wp-admin` }; } @@ -460,7 +470,11 @@ function createExternalWpTester(options = {}) { const installedPlugins = await installRequiredPlugins(config, subsite.url, requiredPlugins); if (pluginSlug) { - await runSshCommand(config, buildWpCliCommand(config, subsite.url, `plugin activate ${pluginSlug}`)); + const activateCmd = buildWpCliCommand(config, subsite.url, `plugin activate ${pluginSlug}`); + const activateRes = await runSshCommand(config, activateCmd, { timeout: config.testTimeoutMs }); + if (activateRes.code !== 0) { + errors.push(`Failed to activate plugin ${pluginSlug}: ${activateRes.stderr || activateRes.stdout}`); + } } const scenarios = normalizeTestScenarios(input, pluginSlug, config); diff --git a/opencode/mcp-servers/wp-cli-testing/README.md b/opencode/mcp-servers/wp-cli-testing/README.md new file mode 100644 index 0000000..fdcfed0 --- /dev/null +++ b/opencode/mcp-servers/wp-cli-testing/README.md @@ -0,0 +1,106 @@ +# WP-CLI Testing MCP Server + +This MCP server provides tools for testing WordPress plugins on an external WordPress multisite installation via WP-CLI over SSH. + +## Tools Provided + +### 1. test_plugin_external_wp + +Runs automated CLI tests on an external WordPress installation with full isolation via multisite subsites. + +**Features:** +- Automatic subsite provisioning (`wp site create`) +- Plugin upload and activation +- Dependency installation (WooCommerce, ACF, etc.) +- WP-CLI based test execution +- Automatic cleanup after delay + +**Example:** +```json +{ + "plugin_path": "/workspace/my-plugin", + "plugin_slug": "my-plugin", + "test_mode": "cli", + "required_plugins": [ + {"plugin_slug": "woocommerce", "activate": true} + ], + "test_scenarios": [ + { + "name": "Plugin activates", + "type": "custom", + "wp_cli_command": "plugin activate my-plugin", + "assertions": {"wp_cli_success": true} + } + ] +} +``` + +### 2. external_wp_testing_config + +Returns the resolved configuration and validates required environment variables. + +**Example:** +```json +{} +``` + +**Returns:** +```json +{ + "ok": true, + "missing": [], + "config": { + "wpHost": "wp-test.example.com", + "wpSshUser": "wordpress", + "enableMultisite": true, + ... + } +} +``` + +## How It's Loaded + +This server is **NOT** loaded automatically. It's injected dynamically by the chat server only when: +1. The Builder "External WP CLI testing" toggle is enabled +2. The chat server sets `OPENCODE_EXTRA_MCP_SERVERS` environment variable +3. OpenCode reads that variable and adds this MCP server to its configuration + +## Configuration + +All configuration is via environment variables (see EXTERNAL_WP_CLI_TESTING_SETUP.md): + +- `TEST_WP_HOST` - WordPress server hostname +- `TEST_WP_SSH_USER` - SSH username +- `TEST_WP_SSH_KEY` - Path to SSH private key +- `TEST_WP_PATH` - WordPress installation path +- `TEST_WP_BASE_URL` - Base URL of site +- `TEST_WP_MULTISITE` - Enable multisite (default: true) +- etc. + +## Architecture + +``` +OpenCode (when toggle enabled) + ↓ loads MCP server via OPENCODE_EXTRA_MCP_SERVERS +wp-cli-testing MCP Server + ↓ imports ../../../chat/external-wp-testing.js +External WP Testing Module + ↓ SSH connection +WordPress Multisite Test Server + ↓ creates subsite +Isolated Test Environment +``` + +## Dependencies + +This MCP server relies on: +- `@modelcontextprotocol/sdk` (provided by OpenCode) +- `zod` (provided by OpenCode) +- `../../../chat/external-wp-testing.js` (CommonJS module) + +## Notes + +- Only `test_mode: "cli"` is implemented (visual mode not yet supported) +- Requires WordPress multisite configured on external server +- All plugin operations happen on isolated subsites +- Automatic cleanup scheduled after test completion diff --git a/opencode/mcp-servers/wp-cli-testing/index.js b/opencode/mcp-servers/wp-cli-testing/index.js index d5195e8..01d520a 100644 --- a/opencode/mcp-servers/wp-cli-testing/index.js +++ b/opencode/mcp-servers/wp-cli-testing/index.js @@ -153,19 +153,26 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => { const args = (req.params.arguments ?? {}) // Lazy-load to avoid paying cost unless tool is actually invoked. - // Note: external-wp-testing.js is CommonJS; import default gives module.exports. - const externalTesting = await import("../../../chat/external-wp-testing.js") - const mod = externalTesting.default ?? externalTesting - const createExternalWpTester = mod?.createExternalWpTester - const getExternalTestingConfig = mod?.getExternalTestingConfig + // Note: external-wp-testing.js is CommonJS; when imported from ESM, + // exports are on .default for Node.js CommonJS modules + let createExternalWpTester + let getExternalTestingConfig + + try { + const externalTesting = await import("../../../chat/external-wp-testing.js") + const mod = externalTesting.default ?? externalTesting + createExternalWpTester = mod?.createExternalWpTester + getExternalTestingConfig = mod?.getExternalTestingConfig - if (typeof createExternalWpTester !== "function" || typeof getExternalTestingConfig !== "function") { + if (typeof createExternalWpTester !== "function" || typeof getExternalTestingConfig !== "function") { + throw new Error("Required exports not found on module") + } + } catch (error) { return { content: [ { type: "text", - text: - "wp-cli-testing MCP server misconfigured: could not load chat/external-wp-testing.js exports.", + text: `wp-cli-testing MCP server error: Failed to load chat/external-wp-testing.js - ${error.message}`, }, ], isError: true,