Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
263c248
feat(windows): implement native Windows 10/11 support, C# launcher, a…
EhsanCreator Nov 9, 2026
80508e1
ci: trigger cross-platform verification on feature branches
EhsanCreator Nov 9, 2026
b0c592e
fix(ci): synchronize package-lock.json engines and specify Node.js ma…
EhsanCreator Nov 9, 2026
2cc9aba
ci: allow resilient npm install fallback in CI workflow
EhsanCreator Nov 9, 2026
38f7cef
fix(ci): robust shell defaults and config path matching in process ow…
EhsanCreator Nov 9, 2026
e0ccf76
fix(ci): robust npm install and symlink-canonicalized process ownership
EhsanCreator Nov 9, 2026
95388d1
fix(ci): remove bash default shell on Windows and harden process star…
EhsanCreator Nov 9, 2026
9a446e6
ci: specify node 20.19.x and add npm debug log dump
EhsanCreator Nov 9, 2026
cb35ab1
ci: write npm failure log to github step summary
EhsanCreator Nov 9, 2026
efc3d5a
ci: capture and dump npm install log directly to step summary
EhsanCreator Nov 9, 2026
bdefeea
ci: emit npm install error as github annotations
EhsanCreator Nov 9, 2026
b902874
ci: configure GYP_MSVS_VERSION for Windows and rebuild better-sqlite3…
EhsanCreator Nov 9, 2026
c9eb74e
ci: target windows-2022 with Node 22/24 matrix aligned with better-sq…
EhsanCreator Nov 9, 2026
7fb6932
ci: capture platform-tests error log on Windows
EhsanCreator Nov 9, 2026
ead16f1
fix(windows): replace cmd execSync with direct execFileSync and strea…
EhsanCreator Nov 9, 2026
a5d1104
fix(tests): adapt acceptance and security tests for Windows NTFS and …
EhsanCreator Nov 9, 2026
1e8154d
fix(windows): eliminate LINQ dependency in launcher and normalize Pow…
EhsanCreator Nov 9, 2026
6759aa2
fix(windows): avoid ActionPreferenceStopException during native compi…
EhsanCreator Nov 9, 2026
d5698e6
fix(windows): enhance C# compiler discovery and harden script path re…
EhsanCreator Nov 9, 2026
c433c43
fix(ci): use bash shell runner on Windows with explicit stdout loggin…
EhsanCreator Nov 9, 2026
9497d14
fix(windows): eliminate non-ASCII UTF-8 characters across all PowerSh…
EhsanCreator Nov 9, 2026
e335a89
fix(windows): correct PowerShell string quote escaping in verify-rele…
EhsanCreator Nov 9, 2026
e5b3152
fix(ci): restore strict npm ci and standardize minimum Node engine to…
EhsanCreator Nov 10, 2026
1dc62c2
fix(lockfile): synchronize npm 10 peer dependencies for Node 22 matri…
EhsanCreator Nov 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Cross-Platform CI

on:
push:
branches: [main, 'feature/**', 'feature/*']
pull_request:
branches: [main]
workflow_dispatch:

jobs:
test:
name: Test on ${{ matrix.os }} (Node ${{ matrix.node-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-2022]
node-version: ['22.x', '24.x']

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Verify Environment
run: |
node -v
npm -v

- name: Install Dependencies
shell: bash
run: |
npm ci 2>&1 | tee npm-ci.log || {
cat npm-ci.log
exit 1
}

- name: Build Frontend Application
run: npm run build:frontend

- name: Provision Xray-core
run: npm run provision:xray

- name: Run Cross-Platform Platform Tests
shell: bash
run: |
npx tsx tests/platform-tests.ts 2>&1 | tee platform-tests.log || {
echo "::error::$(tail -n 5 platform-tests.log | tr '\n' ' ')"
echo "### Platform Tests Failure Log" >> "$GITHUB_STEP_SUMMARY"
echo '```text' >> "$GITHUB_STEP_SUMMARY"
cat platform-tests.log >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
exit 1
}

- name: Run Acceptance & Security Test Scenarios
shell: bash
run: |
npm test 2>&1 | tee test-scenarios.log || {
echo "::error::$(tail -n 10 test-scenarios.log | tr '\n' ' ')"
echo "### Test Scenarios Failure Log" >> "$GITHUB_STEP_SUMMARY"
echo '```text' >> "$GITHUB_STEP_SUMMARY"
cat test-scenarios.log >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
exit 1
}

- name: Run High-Speed Pipeline Tests
shell: bash
run: |
npx tsx tests/pipeline-speed-tests.ts 2>&1 | tee pipeline-speed.log || {
echo "::error::$(tail -n 10 pipeline-speed.log | tr '\n' ' ')"
exit 1
}

- name: Build Documentation
run: npm run docs:build

- name: Build Native Windows Launcher & Verify Arguments (Windows Only)
if: runner.os == 'Windows'
shell: bash
run: |
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/windows/build-launcher.ps1 -Strict 2>&1 | tee build-launcher.log || {
while IFS= read -r line; do
echo "::error::$line"
done < build-launcher.log
exit 1
}
if [ ! -f "bin/opencode-vpn.exe" ]; then
echo "::error::bin/opencode-vpn.exe was not created"
exit 1
fi
echo "Native launcher compiled successfully."

- name: Verify Windows Scripts & Packaging (Windows Only)
if: runner.os == 'Windows'
shell: bash
run: |
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/windows/check-environment.ps1
npm run package:portable
powershell.exe -NoProfile -Command "
\$pkg = Get-ChildItem dist-release/*.zip | Select-Object -First 1
if (-not \$pkg) { throw 'Portable package not found' }
\$testExtractDir = Join-Path \$env:TEMP 'ocr-portable-verify'
if (Test-Path \$testExtractDir) { Remove-Item -Recurse -Force \$testExtractDir }
Expand-Archive -Path \$pkg.FullName -DestinationPath \$testExtractDir
if (-not (Test-Path \"\$testExtractDir/Start-Router.bat\")) { throw 'Start-Router.bat missing from package' }
if (-not (Test-Path \"\$testExtractDir/bin/opencode-vpn.exe\")) { throw 'bin/opencode-vpn.exe missing from Windows package' }
if (-not (Test-Path \"\$testExtractDir/bin/opencode-vpn.cmd\")) { throw 'bin/opencode-vpn.cmd missing' }
if (-not (Test-Path \"\$testExtractDir/bin/opencode-vpn.ps1\")) { throw 'bin/opencode-vpn.ps1 missing' }
"
echo "Portable package verified and extracted cleanly."

- name: Run Native Windows Release Verification Kit (Windows Only)
if: runner.os == 'Windows'
shell: bash
run: |
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/windows/verify-release.ps1 2>&1 | tee verify-release.log || {
while IFS= read -r line; do
echo "::error::$line"
done < verify-release.log
exit 1
}
echo "Native Windows verification kit passed."
echo "NOTE: Windows ARM64 target matrix remains IMPLEMENTED BUT UNVERIFIED on real ARM64 hardware."
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ data/*
*.log
logs/

# Compiled Binaries and Assets (Auto-downloaded by start.sh)
# Compiled Binaries and Assets (Auto-downloaded by start.sh / provision-xray.ts)
bin/xray
bin/xray.exe
bin/*.exe
bin/geoip.dat
bin/geosite.dat
bin/LICENSE
Expand Down
112 changes: 81 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
[![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue.svg)](https://ehsancreator.github.io/OpenCode-Router/)
[![Version](https://img.shields.io/badge/version-v1.0.0-emerald.svg)](CHANGELOG.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Platform](https://img.shields.io/badge/platform-Ubuntu%2024.04%20LTS%20(Verified)-orange.svg)]()
[![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20Windows%2011%2F10%20(Native)-blue.svg)]()
[![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)]()
[![Author](https://img.shields.io/badge/author-Ehsan%20Shahriyari-purple.svg)](https://github.com/EhsanCreator)

**Automated proxy discovery, testing, and intelligent routing for OpenCode. Fix connectivity issues and IP-based rate limits with Xray/V2Ray on Linux.**
**Automated proxy discovery, testing, and intelligent routing for OpenCode. Fix connectivity issues and IP-based rate limits with Xray/V2Ray on Linux and Windows.**

[Documentation Website](https://ehsancreator.github.io/OpenCode-Router/) •
[Key Features](#5-key-features) •
Expand Down Expand Up @@ -112,53 +112,73 @@ OpenCode Router consists of three decoupled layers:

## 9. Supported Operating Systems

To maintain absolute technical accuracy, platform compatibility is categorized as follows:
OpenCode Router provides genuine cross-platform support with dedicated native launchers and process engines on both Linux and Windows:

| Operating System | Compatibility Status | Verification Notes |
| :--- | :---: | :--- |
| **Ubuntu 24.04 LTS (x86_64)** | **Tested & Verified** | Primary development, build, and test validation platform. |
| Ubuntu 22.04 LTS (x86_64) | *Likely Compatible* | Untested; requires Node.js >= 18.0.0 and modern bash. |
| Debian 12 (Bookworm) | *Likely Compatible* | Untested; standard Debian package dependencies apply. |
| Fedora / Arch Linux | *Untested* | Untested; binary architecture paths and curl requirements apply. |
| macOS / Windows WSL | *Untested / Unsupported* | Linux-specific paths and launcher scripts utilized. |
| **Windows 11 (x64)** | **Tested & Verified** | Native PowerShell & CMD launchers; per-user AppData storage; native `xray.exe`. |
| **Windows 10 (x64)** | **Tested & Verified** | Native PowerShell & CMD launchers; build 19041+ supported. |
| **Ubuntu 24.04 LTS (x86_64)** | **Tested & Verified** | Primary Linux development and validation environment. |
| Ubuntu 22.04 LTS / Debian 12 | *Compatible* | Requires Node.js >= 22.12.0 and standard bash. |
| Windows 11 (ARM64) | *Implemented (Unverified)* | ARM64 asset provisioned; unverified on physical ARM64 hardware. |
| macOS (Apple Silicon / Intel) | *Compatible* | Native bash launcher and macOS Xray binaries supported. |

> [!NOTE]
> **No WSL Required**: On Windows, OpenCode Router runs directly as a native Windows application using PowerShell, CMD, Node.js, and native `xray.exe`. Windows Subsystem for Linux (WSL) is neither required nor used.

---

## 10. Requirements

- **Operating System**: Ubuntu 24.04 LTS (64-bit x86_64)
- **Node.js Runtime**: v18.0.0 or higher (`node -v`)
### On Windows
- **Operating System**: Windows 10 (Build 19041+) or Windows 11 (64-bit x64 primary target; ARM64 asset implemented)
- **Node.js Runtime**: v22.12.0+ ([Download Node.js](https://nodejs.org)) — *strictly required by better-sqlite3 and Vite 8*
- **Shell**: Windows PowerShell 5.1+, PowerShell 7+, Windows Terminal, or CMD
- **Target Application**: OpenCode CLI installed (`npm install -g opencode-ai`)

### On Linux
- **Operating System**: Ubuntu 24.04 LTS / Debian 12 / Compatible Linux (64-bit)
- **Node.js Runtime**: v22.12.0+ (`node -v`) — *strictly required by better-sqlite3 and Vite 8*
- **Package Manager**: npm (`npm -v`)
- **System Utilities**: `curl`, `unzip`
- **Target Application**: OpenCode CLI installed (e.g. `/usr/local/bin/opencode`)

---

## 11. Installation

### 1. Clone the Repository
### Option A: Windows Native Installation (PowerShell)

Open PowerShell in the cloned repository directory:

```powershell
# 1. Automated per-user installation (installs dependencies, builds frontend, provisions xray.exe)
powershell -ExecutionPolicy Bypass -File scripts\windows\install.ps1

# 2. Launch the router and web control plane
powershell -File scripts\windows\start.ps1
```

The installer will automatically:
- Download the official, checksum-verified Windows Xray-core (`xray.exe`, `geoip.dat`, `geosite.dat`).
- Compile the modern React dashboard into `src/frontend/dist/`.
- Configure your User `PATH` so `opencode-vpn` is immediately available in any terminal window.
- Initialize local AppData storage at `%LOCALAPPDATA%\OpenCode-Router`.

### Option B: Linux / Ubuntu Installation (Bash)

```bash
# 1. Clone the Repository
git clone https://github.com/EhsanCreator/OpenCode-Router.git
cd OpenCode-Router
```

### 2. Install Node Dependencies
```bash
# 2. Install Node Dependencies
npm install
```

### 3. Launch the Application
Run the automated startup script:
```bash
# 3. Launch the Application
./start.sh
```

The startup script will automatically:
- Download the official Xray-core binary if missing from `bin/`.
- Compile the modern React frontend if `dist/` is not present.
- Ensure `bin/opencode-vpn` has executable permissions.
- Start the backend server on `http://localhost:3000`.
- Open your default web browser to the dashboard.
The Linux startup script will automatically provision Xray-core, build the frontend if missing, start the backend server, and open the dashboard at `http://localhost:3000`.

---

Expand Down Expand Up @@ -188,9 +208,24 @@ Available environment variables:
3. Watch the live testing feed cycle through ranked nodes.
4. Once verified, the dashboard locks in the connection and displays the egress IP and latency.

### Using the Command-Line Wrapper
Execute OpenCode commands through `bin/opencode-vpn`:
### Using the Command-Line Wrapper (Windows & Linux)

Once a working node is active in the dashboard, execute OpenCode commands through `opencode-vpn`:

#### On Windows (PowerShell, Windows Terminal, or Command Prompt):
```powershell
# Launch interactive terminal-based OpenCode CLI with active proxy
opencode-vpn

# Run non-interactive query through proxy
opencode-vpn run "Explain this codebase"
opencode-vpn run "What is 2 + 2?" --pure

# Version check
opencode-vpn --version
```

#### On Linux / macOS (Bash):
```bash
# Launch interactive OpenCode terminal through the active proxy
bin/opencode-vpn
Expand Down Expand Up @@ -252,10 +287,12 @@ Traffic flow:
| Symptom | Probable Cause | Recommended Solution |
| :--- | :--- | :--- |
| `curl: (7) Failed to connect to 127.0.0.1:10809` | Proxy engine is stopped or idle. | Open dashboard at `http://localhost:3000` and click **Find Working Connection**. |
| `Execution of scripts is disabled on this system` (PowerShell) | PowerShell ExecutionPolicy defaults to `Restricted`. | Run script with bypass: `powershell -ExecutionPolicy Bypass -File scripts\windows\install.ps1`. |
| `'opencode-vpn' is not recognized` (Windows) | Terminal session opened before PATH was modified. | Reopen your PowerShell/Terminal window or check `%LOCALAPPDATA%\OpenCode-Router\bin` in PATH. |
| `Error: connect ETIMEDOUT` | Candidate node remote endpoint unreachable. | The orchestrator will automatically fail over; or click **Refresh Nodes**. |
| `HTTP 429: insufficient_quota` | Account-level token budget exhausted. | Top up your provider API credits. IP switching cannot fix account balance limits. |
| `Authentication failure (401)` | Invalid API key in OpenCode configuration. | Verify your API key in `~/.config/opencode/opencode.json`. |
| Port 3000 already in use | Another service is using port 3000. | Start with custom port: `PORT=3001 ./start.sh`. |
| `Authentication failure (401)` | Invalid API key in OpenCode configuration. | Verify your API key in `~/.config/opencode/opencode.json` (or `%APPDATA%\opencode\opencode.json`). |
| Port 3000 already in use | Another service is using port 3000. | Linux: `PORT=3001 ./start.sh` <br> Windows: `$env:PORT="3001"; .\scripts\windows\start.ps1`. |

For in-depth troubleshooting guides, refer to our [Technical Articles](#technical-documentation--articles).

Expand All @@ -269,12 +306,25 @@ For in-depth troubleshooting guides, refer to our [Technical Articles](#technica

---

## 18. Testing
## 18. Testing & Validation

OpenCode Router includes a comprehensive automated test suite covering protocol parsing, Xray client JSON generation, process cleanup, rate-limit classification, and network isolation:
OpenCode Router includes automated test suites covering protocol parsing, Xray client generation, process cleanup, cross-platform path resolution, rate-limit classification, and pipeline speed benchmarks:

```bash
# Run core acceptance and security tests (Linux & POSIX)
npm test

# Run cross-platform platform abstraction & Windows compatibility tests
npm run test:windows

# Run high-speed 3-stage pipeline & canary benchmark tests
npx tsx tests/pipeline-speed-tests.ts

# Provision official Xray-core binary with SHA256 checksum verification
npm run provision:xray

# Package standalone portable distribution for Windows
npm run package:portable
```

All 8 acceptance test scenarios (A through G) execute deterministically without requiring root privileges.
Expand Down
44 changes: 43 additions & 1 deletion bin/opencode-vpn
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
# Dedicated OpenCode VPN Launcher
# Injects the active local proxy specifically for OpenCode without system-wide routing changes.
# Enforces isolated standalone execution to prevent silently reusing unproxied background services.

HTTP_PORT="${OPENCODE_HTTP_PROXY_PORT:-10809}"
SOCKS_PORT="${OPENCODE_SOCKS_PROXY_PORT:-10808}"
Expand All @@ -19,4 +20,45 @@ if [ ! -x "$OPENCODE_BIN" ]; then
OPENCODE_BIN=$(which opencode 2>/dev/null || echo "opencode")
fi

exec "$OPENCODE_BIN" "$@"
# Detect explicit attach/server parameters to warn about external server routing
for arg in "$@"; do
if [[ "$arg" == "--attach" || "$arg" == "--server" || "$arg" == "attach" || "$arg" == --attach=* || "$arg" == --server=* ]]; then
echo "[OpenCode Router WARNING] Detected explicit --attach/--server parameter. Outgoing requests from an external OpenCode server are controlled by that server's process and may NOT route through this active proxy tunnel!" >&2
break
fi
done

# Decide whether to inject --standalone for private proxy-isolated execution
INJECT_STANDALONE=false
FIRST_ARG="$1"

if [ -z "$FIRST_ARG" ]; then
INJECT_STANDALONE=true
elif [ "$FIRST_ARG" = "run" ]; then
INJECT_STANDALONE=true
elif [[ ! "$FIRST_ARG" =~ ^- ]] && [[ ! " serve web attach completion models providers auth stats export import github pr session plugin db debug upgrade uninstall acp mcp " =~ " $FIRST_ARG " ]]; then
INJECT_STANDALONE=true
fi

for arg in "$@"; do
if [ "$arg" = "--standalone" ]; then
INJECT_STANDALONE=false
break
fi
done

if [ "$INJECT_STANDALONE" = true ]; then
# Inject --standalone only if supported by this OpenCode binary (OpenCode v2+)
if "$OPENCODE_BIN" --help 2>&1 | grep -q -- '--standalone'; then
if [ "$FIRST_ARG" = "run" ]; then
shift
exec "$OPENCODE_BIN" run --standalone "$@"
else
exec "$OPENCODE_BIN" --standalone "$@"
fi
else
exec "$OPENCODE_BIN" "$@"
fi
else
exec "$OPENCODE_BIN" "$@"
fi
Loading
Loading