收敛微信 sidecar 到官方单链路并同步文档与回归测试。

移除 weixin 安装与启动脚本中的 legacy/localSource 分支,只保留 official_runner 路径,统一开源安装命令并更新 RUNBOOK/Quickstart/README,确保脚本行为与测试预期一致。

Made-with: Cursor
This commit is contained in:
oliver 2026-04-29 01:10:25 +08:00
parent 3122b8a16c
commit 853dc1812f
7 changed files with 43 additions and 116 deletions

View file

@ -33,13 +33,13 @@ powershell -ExecutionPolicy Bypass -File .\scripts\stop_gateway.ps1 -Force
### 3) Weixin (Personal WeChat): install → login → start
```powershell
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_install.ps1 -UseOpenclawCli
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_install.ps1
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_login.ps1
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_start.ps1
```
Notes:
- `weixin_install.ps1 -UseOpenclawCli` does **not** require global `openclaw` CLI installation; runtime deps are installed locally in sidecar workspace.
- `weixin_install.ps1` does **not** require global `openclaw` CLI installation; runtime deps are installed locally in sidecar workspace.
- `.\scripts\start_all.ps1 -Background` now skips missing Weixin/WhatsApp sidecars gracefully (warn + continue), so Admin/Chat can still boot on fresh installs.
- Admin supports channel dispatch controls for Weixin/WhatsApp (bind specialist / comprehensive), with default `generalist`.

View file

@ -35,7 +35,7 @@ Notes:
## Path B: Enable Weixin (Personal WeChat)
```powershell
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_install.ps1 -UseOpenclawCli
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_install.ps1
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_login.ps1
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_start.ps1
```

View file

@ -78,7 +78,7 @@ powershell -ExecutionPolicy Bypass -File .\scripts\stop_gateway.ps1 -Force
> 这一步会安装/更新官方插件到:`%USERPROFILE%\.openclaw\extensions\openclaw-weixin\`
```powershell
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_install.ps1 -UseOpenclawCli
powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_install.ps1
```
### 1.1.5 扫码登录(绑定账号)
@ -89,8 +89,8 @@ powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_log
按提示扫码完成绑定(会写入账号 ID / token 等状态到 `%USERPROFILE%\.openclaw\openclaw-weixin\`)。
> 说明:这里的 `-UseOpenclawCli` **不要求你全局安装 openclaw**(不需要 `npm install -g openclaw`)。
> 脚本会在 `data/channel_sidecar/oclaw-weixin/` 下本地安装 `openclaw` npm 包,并用 `npx openclaw ...` 驱动官方插件完成扫码与状态写入。
> 说明:`weixin_install.ps1` **不要求你全局安装 openclaw**(不需要 `npm install -g openclaw`)。
> 脚本会在 `data/channel_sidecar/oclaw-weixin/` 下安装本地运行时依赖,并完成官方插件安装。
### 1.1.6 启动微信 sidecar(原生模式)
@ -114,7 +114,7 @@ powershell -ExecutionPolicy Bypass -File .\runtime\operations\scripts\weixin_sta
- **启动网关提示端口占用 / 你以为重启了但没生效**
- 用 `stop_gateway.ps1 -Force` 强制按端口清理旧监听进程,然后再启动。
- **Node 版本不对**
- 官方插件要求 `node >=22`;请升级 Node 后重新执行 `weixin_install.ps1 -UseOpenclawCli`。
- 官方插件要求 `node >=22`;请升级 Node 后重新执行 `weixin_install.ps1`。
---
@ -222,17 +222,15 @@ Linux/macOS:
- 本仓库宿主适配负责:
- 把官方入站消息转换成 `oclaw` 可消费的本地 payload
- 通过本地 `/weixin/native/reply` 同步生成回复
- 保留一个历史 `runner.ts` fallback,便于短期回滚
对应脚本行为:
- `runtime/operations/scripts/weixin_install.ps1 -UseOpenclawCli`
- `runtime/operations/scripts/weixin_install.ps1`
- 安装官方 `openclaw-weixin` 插件
- 安装运行官方模块所需的本地 Node 依赖
- 同步 `runtime/operations/weixin_bridge/official_runner.ts` / `runner.ts` / `login.ts`
- 同步 `runtime/operations/weixin_bridge/official_runner.ts` / `login.ts`
- `runtime/operations/scripts/weixin_start.ps1`
- 默认启动 `official_runner.ts`
- 设置 `AIA_WEIXIN_RUNNER_MODE=legacy` 时,临时回退到历史 `runner.ts`
- 仅启动 `official_runner.ts`(官方单链路)
现阶段主路径建议:
@ -549,25 +547,7 @@ npm install images-mcp
powershell -ExecutionPolicy Bypass -File .\scripts\weixin_install.ps1
```
注意:
- 脚本支持两种模式:
- 官方插件模式:`-UseOpenclawCli`(不校验 `runner.ts/login.ts`)
- 本地 sidecar 模式:`-LocalSourcePath`(会强校验 `runner.ts/login.ts`)
- 默认按本地 sidecar 模式处理:必须传 `-LocalSourcePath`(指向你们自研 weixin sidecar 源码目录)。
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\weixin_install.ps1 -LocalSourcePath "D:\path\to\your-weixin-module"
```
- 若你要临时切回官方链路,可显式指定:
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\weixin_install.ps1 -UseOpenclawCli
```
- 仅本地 sidecar 模式会强校验 `runner.ts` / `login.ts` 是否存在;官方插件模式不做该校验。
注意:当前仅保留官方插件单链路,直接执行 `weixin_install.ps1` 即可。
安装目录:

View file

@ -1,7 +1,5 @@
param(
[string]$ChannelId = "oclaw-weixin",
[string]$LocalSourcePath = "",
[switch]$UseOpenclawCli = $false
[string]$ChannelId = "oclaw-weixin"
)
$ErrorActionPreference = "Stop"
@ -16,6 +14,16 @@ $oclawRoot = Resolve-RepoRoot
$sidecarRoot = Join-Path $oclawRoot "data\\channel_sidecar\\$ChannelId"
$stateDir = Join-Path $sidecarRoot "state"
$pluginRoot = Join-Path $env:USERPROFILE ".openclaw\\extensions\\openclaw-weixin"
function Sync-WeixinBridgeRunners {
$bridgeSrc = Join-Path $oclawRoot "runtime\\operations\\weixin_bridge"
foreach ($name in @("official_runner.ts", "login.ts")) {
$srcPath = Join-Path $bridgeSrc $name
if (-not (Test-Path $srcPath)) {
throw "missing bridge source file: $srcPath"
}
Copy-Item -Path $srcPath -Destination (Join-Path $sidecarRoot $name) -Force
}
}
New-Item -ItemType Directory -Force -Path $sidecarRoot | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $sidecarRoot "logs") | Out-Null
@ -36,52 +44,6 @@ function Ensure-OfficialPluginRuntimeDeps {
}
}
if ($UseOpenclawCli) {
# Do not require a globally-installed openclaw CLI.
# We install openclaw into the sidecar runtime and put node_modules/.bin on PATH
# so the official installer can run `openclaw ...` commands.
Push-Location $sidecarRoot
try {
if (-not (Test-Path (Join-Path $sidecarRoot "package.json"))) {
npm.cmd init -y | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "npm init failed with exit code $LASTEXITCODE"
}
}
npm.cmd install openclaw@latest --save
if ($LASTEXITCODE -ne 0) {
throw "npm install openclaw failed with exit code $LASTEXITCODE"
}
$env:PATH = (Join-Path $sidecarRoot "node_modules\\.bin") + ";" + $env:PATH
npx.cmd -y @tencent-weixin/openclaw-weixin-cli@latest install
if ($LASTEXITCODE -ne 0) {
throw "openclaw-weixin-cli install failed with exit code $LASTEXITCODE"
}
} finally {
Pop-Location
}
Ensure-OfficialPluginRuntimeDeps
Push-Location $sidecarRoot
try {
npm.cmd install openclaw@latest --save tsx@4.21.0 typescript@6.0.3
if ($LASTEXITCODE -ne 0) {
throw "npm install bridge runtime deps failed with exit code $LASTEXITCODE"
}
$bridgeSrc = Join-Path $oclawRoot "runtime\\operations\\weixin_bridge"
Copy-Item -Path (Join-Path $bridgeSrc "runner.ts") -Destination (Join-Path $sidecarRoot "runner.ts") -Force
Copy-Item -Path (Join-Path $bridgeSrc "official_runner.ts") -Destination (Join-Path $sidecarRoot "official_runner.ts") -Force
Copy-Item -Path (Join-Path $bridgeSrc "login.ts") -Destination (Join-Path $sidecarRoot "login.ts") -Force
} finally {
Pop-Location
}
Write-Host "[ok] installed official openclaw-weixin plugin + native/fallback sidecar runtime"
exit 0
}
if (-not $LocalSourcePath) {
throw "LocalSourcePath is required in sidecar mode. Example: .\\scripts\\weixin_install.ps1 -LocalSourcePath D:\\path\\to\\your-weixin-module"
}
Push-Location $sidecarRoot
try {
if (-not (Test-Path (Join-Path $sidecarRoot "package.json"))) {
@ -90,21 +52,18 @@ try {
throw "npm init failed with exit code $LASTEXITCODE"
}
}
$src = (Resolve-Path $LocalSourcePath).Path
npm.cmd install --save-exact $src tsx@4.21.0 typescript@6.0.3
npx.cmd -y @tencent-weixin/openclaw-weixin-cli@latest install
if ($LASTEXITCODE -ne 0) {
throw "npm install local source failed with exit code $LASTEXITCODE"
throw "openclaw-weixin-cli install failed with exit code $LASTEXITCODE"
}
if (-not (Test-Path (Join-Path $sidecarRoot "runner.ts"))) {
throw "install completed but runner.ts is missing (invalid sidecar package/source)"
npm.cmd install openclaw@latest --save tsx@4.21.0 typescript@6.0.3
if ($LASTEXITCODE -ne 0) {
throw "npm install bridge runtime deps failed with exit code $LASTEXITCODE"
}
if (-not (Test-Path (Join-Path $sidecarRoot "login.ts"))) {
throw "install completed but login.ts is missing (invalid sidecar package/source)"
}
Write-Host "[ok] installed local weixin sidecar into $sidecarRoot"
} finally {
Pop-Location
}
Ensure-OfficialPluginRuntimeDeps
Sync-WeixinBridgeRunners
Write-Host "[ok] installed official openclaw-weixin plugin sidecar runtime into $sidecarRoot"

View file

@ -27,7 +27,7 @@ try {
npm.cmd exec -- tsx login.ts
exit 0
}
throw "login.ts missing. Re-run weixin_install.ps1 -UseOpenclawCli to install sidecar runtime."
throw "login.ts missing. Re-run weixin_install.ps1 to install sidecar runtime."
} finally {
Pop-Location
}

View file

@ -18,15 +18,11 @@ $logDir = Join-Path $sidecarRoot "logs"
$pidFile = Join-Path $sidecarRoot "pid.txt"
$bridgeSrc = Join-Path $oclawRoot "runtime\\operations\\weixin_bridge"
$pluginRoot = Join-Path $env:USERPROFILE ".openclaw\\extensions\\openclaw-weixin"
$runnerMode = [string]($env:AIA_WEIXIN_RUNNER_MODE)
if (-not $runnerMode) { $runnerMode = "official" }
$runnerMode = $runnerMode.Trim().ToLowerInvariant()
function Get-SidecarProcesses {
$escapedSidecarRoot = $sidecarRoot.Replace("\", "\\")
$patterns = @(
"*$ChannelId*",
"*runner.ts*",
"*official_runner.ts*",
"*$escapedSidecarRoot*"
)
@ -82,7 +78,7 @@ $cleaned = Stop-SidecarProcesses
Remove-Item -Force $pidFile -ErrorAction SilentlyContinue
if (Test-Path $bridgeSrc) {
foreach ($name in @("runner.ts", "official_runner.ts", "login.ts")) {
foreach ($name in @("official_runner.ts", "login.ts")) {
$srcPath = Join-Path $bridgeSrc $name
if (Test-Path $srcPath) {
Copy-Item -Path $srcPath -Destination (Join-Path $sidecarRoot $name) -Force
@ -92,27 +88,18 @@ if (Test-Path $bridgeSrc) {
$logPath = Join-Path $logDir "weixin_sidecar.log"
$errPath = Join-Path $logDir "weixin_sidecar.err.log"
if ((Test-Path (Join-Path $sidecarRoot "runner.ts")) -or (Test-Path (Join-Path $sidecarRoot "official_runner.ts"))) {
$runnerFile = "official_runner.ts"
if ($runnerMode -eq "legacy") {
$runnerFile = "runner.ts"
}
if ($runnerMode -eq "official") {
Ensure-OfficialPluginRuntimeDeps
}
if (-not (Test-Path (Join-Path $sidecarRoot $runnerFile))) {
throw "selected runner file missing: $runnerFile"
}
if (Test-Path (Join-Path $sidecarRoot "official_runner.ts")) {
Ensure-OfficialPluginRuntimeDeps
$cmd = "cmd.exe"
$args = @(
"/c",
"cd /d $sidecarRoot && set OCLAW_STATE_DIR=$stateDir&& set AIA_GATEWAY_BASE_URL=$GatewayBaseUrl&& set NODE_PATH=$sidecarRoot\node_modules&& npm.cmd exec -- tsx $runnerFile"
"cd /d $sidecarRoot && set OCLAW_STATE_DIR=$stateDir&& set AIA_GATEWAY_BASE_URL=$GatewayBaseUrl&& set NODE_PATH=$sidecarRoot\node_modules&& npm.cmd exec -- tsx official_runner.ts"
)
$p = Start-Process -FilePath $cmd -ArgumentList $args -WorkingDirectory $sidecarRoot -PassThru -WindowStyle Hidden -RedirectStandardOutput $logPath -RedirectStandardError $errPath
Set-Content -Path $pidFile -Value $p.Id
Write-Host "[ok] started weixin sidecar pid=$($p.Id) mode=$runnerMode cleaned=$cleaned out=$logPath err=$errPath"
Write-Host "[ok] started weixin sidecar pid=$($p.Id) mode=official cleaned=$cleaned out=$logPath err=$errPath"
exit 0
}
throw "No runner.ts/official_runner.ts found in sidecar root. Re-run weixin_install.ps1 -UseOpenclawCli."
throw "official_runner.ts missing in sidecar root. Re-run weixin_install.ps1."

View file

@ -10,12 +10,11 @@ def _read(rel: str) -> str:
return (REPO_ROOT / rel).read_text(encoding="utf-8")
def test_weixin_start_defaults_to_official_runner() -> None:
def test_weixin_start_official_only_runner() -> None:
text = _read("runtime/operations/scripts/weixin_start.ps1")
assert '$runnerMode = "official"' in text
assert '$runnerFile = "official_runner.ts"' in text
assert 'AIA_WEIXIN_RUNNER_MODE' in text
assert "mode=official" in text
assert 'official_runner.ts' in text
assert "AIA_WEIXIN_RUNNER_MODE" not in text
def test_weixin_status_and_stop_track_official_runner() -> None:
@ -27,8 +26,10 @@ def test_weixin_status_and_stop_track_official_runner() -> None:
def test_weixin_install_copies_official_runner() -> None:
text = _read("runtime/operations/scripts/weixin_install.ps1")
assert 'Copy-Item -Path (Join-Path $bridgeSrc "official_runner.ts")' in text
assert "Sync-WeixinBridgeRunners" in text
assert '"official_runner.ts"' in text
assert "Ensure-OfficialPluginRuntimeDeps" in text
assert "LocalSourcePath" not in text
def test_weixin_start_ensures_plugin_runtime_deps() -> None: