diff --git a/install/install.ps1 b/install/install.ps1 index f16aac1..d6ee8ba 100644 --- a/install/install.ps1 +++ b/install/install.ps1 @@ -595,6 +595,7 @@ set "OPENCLAW_MJS=%DIR%core\node_modules\openclaw\openclaw.mjs" set "OPENCLAW_HOME=%DIR%data" set "OPENCLAW_STATE_DIR=%DIR%data\.openclaw" set "OPENCLAW_CONFIG_PATH=%DIR%data\.openclaw\openclaw.json" +set "OPENCLAW_DISABLE_BONJOUR=1" REM Find available port set PORT=18789 diff --git a/portable/Windows-Install.bat b/portable/Windows-Install.bat index 37d2be7..581d0f4 100644 --- a/portable/Windows-Install.bat +++ b/portable/Windows-Install.bat @@ -192,6 +192,7 @@ echo set "OPENCLAW_MJS=%%DIR%%core\node_modules\openclaw\openclaw.mjs" echo set "OPENCLAW_HOME=%%DIR%%data" echo set "OPENCLAW_STATE_DIR=%%DIR%%data\.openclaw" echo set "OPENCLAW_CONFIG_PATH=%%DIR%%data\.openclaw\openclaw.json" +echo set "OPENCLAW_DISABLE_BONJOUR=1" echo. echo REM Find available port echo set PORT=18789 diff --git a/portable/Windows-Menu.bat b/portable/Windows-Menu.bat index cdb81ab..37d2901 100644 --- a/portable/Windows-Menu.bat +++ b/portable/Windows-Menu.bat @@ -19,6 +19,9 @@ set "NPM_BIN=%NODE_DIR%\npm.cmd" set "OPENCLAW_HOME=%DATA_DIR%" set "OPENCLAW_STATE_DIR=%STATE_DIR%" set "OPENCLAW_CONFIG_PATH=%STATE_DIR%\openclaw.json" +REM U-Claw opens the local dashboard directly; disable mDNS discovery on Windows +REM to avoid OpenClaw/@homebridge ciao crashes during bonjour re-advertise. +set "OPENCLAW_DISABLE_BONJOUR=1" set "PATH=%NODE_DIR%;%PATH%" set "OPENCLAW_MJS=%CORE_DIR%\node_modules\openclaw\openclaw.mjs" diff --git a/portable/Windows-Start.bat b/portable/Windows-Start.bat index 66aef1c..9967a7f 100644 --- a/portable/Windows-Start.bat +++ b/portable/Windows-Start.bat @@ -24,6 +24,9 @@ set "NPM_BIN=%NODE_DIR%\npm.cmd" set "OPENCLAW_HOME=%DATA_DIR%" set "OPENCLAW_STATE_DIR=%STATE_DIR%" set "OPENCLAW_CONFIG_PATH=%STATE_DIR%\openclaw.json" +REM U-Claw opens the local dashboard directly; disable mDNS discovery on Windows +REM to avoid OpenClaw/@homebridge ciao crashes during bonjour re-advertise. +set "OPENCLAW_DISABLE_BONJOUR=1" REM Check runtime if not exist "%NODE_BIN%" ( @@ -66,10 +69,10 @@ if not exist "%CORE_DIR%\node_modules" ( echo [WARN] node_modules not found echo ======================================== echo This release should ship with deps pre-installed. - echo Falling back to npm install (USB drives may take 20+ minutes). + echo Falling back to npm install ^(USB drives may take 20+ minutes^). echo. echo TIP: Re-download u-claw-portable-*.zip from GitHub releases, - echo which includes pre-installed deps (~200 MB). + echo which includes pre-installed deps ^(~200 MB^). echo. echo File system: NTFS recommended. exFAT/FAT32 will be very slow. echo. diff --git a/tests/windows-launchers.test.mjs b/tests/windows-launchers.test.mjs new file mode 100644 index 0000000..8a304fd --- /dev/null +++ b/tests/windows-launchers.test.mjs @@ -0,0 +1,71 @@ +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; +import test from 'node:test'; +import assert from 'node:assert/strict'; + +const repoRoot = fileURLToPath(new URL('..', import.meta.url)); + +function readRepoFile(...parts) { + return readFileSync(join(repoRoot, ...parts), 'utf8'); +} + +function lineOf(content, needle) { + const lines = content.split(/\r?\n/); + const index = lines.findIndex((line) => line.includes(needle)); + assert.notEqual(index, -1, `missing line containing: ${needle}`); + return lines[index]; +} + +test('Windows-Start dependency fallback text escapes parentheses inside IF block', () => { + const script = readRepoFile('portable', 'Windows-Start.bat'); + + assert.match( + lineOf(script, 'Falling back to npm install'), + /\^\(USB drives may take 20\+ minutes\^\)\./, + ); + assert.match( + lineOf(script, 'pre-installed deps'), + /\^\(~200 MB\^\)\./, + ); +}); + +test('portable Windows launchers disable OpenClaw bonjour discovery', () => { + for (const scriptName of [ + 'Windows-Start.bat', + 'Windows-Menu.bat', + 'Windows-Install.bat', + ]) { + const script = readRepoFile('portable', scriptName); + assert.match( + script, + /OPENCLAW_DISABLE_BONJOUR=1/, + `${scriptName} should disable bonjour discovery`, + ); + } +}); + +test('PowerShell installer generated start.bat disables OpenClaw bonjour discovery', () => { + const script = readRepoFile('install', 'install.ps1'); + + assert.match(script, /\$startBat = @'/); + assert.match( + script, + /set "OPENCLAW_DISABLE_BONJOUR=1"/, + 'generated start.bat should disable bonjour discovery', + ); +}); + +test('Electron desktop launcher disables OpenClaw bonjour discovery on Windows only', () => { + const source = readRepoFile('u-claw-app', 'src', 'main.js'); + + assert.match( + source, + /if\s*\(\s*process\.platform\s*===\s*['"]win32['"]\s*\)\s*{[\s\S]*?env\.OPENCLAW_DISABLE_BONJOUR\s*=\s*['"]1['"]/, + ); + assert.doesNotMatch( + source, + /OPENCLAW_DISABLE_BONJOUR:\s*['"]1['"]/, + 'bonjour disable flag should not be in the unconditional env object', + ); +}); diff --git a/u-claw-app/package-lock.json b/u-claw-app/package-lock.json index e84a1d5..6a518e4 100644 --- a/u-claw-app/package-lock.json +++ b/u-claw-app/package-lock.json @@ -1,12 +1,12 @@ { "name": "u-claw", - "version": "2.0.0", + "version": "2.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "u-claw", - "version": "2.0.0", + "version": "2.1.4", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/u-claw-app/package.json b/u-claw-app/package.json index b90911d..de2af4b 100644 --- a/u-claw-app/package.json +++ b/u-claw-app/package.json @@ -1,6 +1,6 @@ { "name": "u-claw", - "version": "2.1.2", + "version": "2.1.4", "description": "U-Claw - AI 助手桌面版,插上 U 盘就能用", "main": "src/main.js", "author": "U-Claw (https://u-claw.org)", diff --git a/u-claw-app/src/main.js b/u-claw-app/src/main.js index 53a6673..53a4881 100644 --- a/u-claw-app/src/main.js +++ b/u-claw-app/src/main.js @@ -236,6 +236,10 @@ function startGateway(port) { OPENCLAW_EMBEDDED_IN: APP_NAME, }; + if (process.platform === 'win32') { + env.OPENCLAW_DISABLE_BONJOUR = '1'; + } + gatewayProcess = spawn(nodeBin, [ openclawEntry, 'gateway', 'run',