feat(portable): 内网/局域网可用性工具包 + 启动绕代理 (v2.1.10)
便携版在内网/离线/受控浏览器环境下"配不上、用不了、查不清"的三个痛点工具化, Win + Mac 双端,纯 Node 零依赖脚本,中文提示由 node 打印(.bat 保持纯 ASCII, .command 保持 LF),三端真机验证(本机 Win / Mac mini / 客户机 pc-7512)。 新增工具: - lib/intranet-check.mjs (+ Windows-IntranetFix.bat / Mac-IntranetFix.command) 一键体检: 代理env + 直连可达 + 真发一条对话,分清"网络不通 vs 配置错"。 - lib/setup-local-model.mjs (+ Windows-LocalModel.bat / Mac-LocalModel.command) 纯命令行配 Ollama / newapi 并当场实测,绕开打不开的 Control UI;写前自动备份+merge。 - lib/resolve-no-proxy.mjs 接入 Windows-Start.bat / Mac-Start.command: 把配置里的模型 host 写进 NO_PROXY,避免系统代理劫持内网模型请求 (OpenClaw 自身只 bypass loopback CDP,不管模型 host)。 - OpenClaw-Doctor.bat / Mac-OpenClaw-Doctor.command: 官方 doctor 的隔离进阶入口 (只读、非交互;doctor 实跑慢且 TTY-only,故不进客户一键流程)。 测试: tests/windows-launchers.test.mjs 新增回归 - 客户面 .bat 必须纯 ASCII (UTF-8 中文会被 GBK cmd 读乱,报 usebackq 不是命令) - macOS .command 必须 LF-only (CRLF 触发 bad interpreter: /bin/bash^M) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,73 @@ test('Windows gateway fallback does not force-open Dashboard', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('portable launchers route configured model hosts around the system proxy', () => {
|
||||
const winStart = readRepoFile('portable', 'Windows-Start.bat');
|
||||
assert.match(
|
||||
winStart,
|
||||
/resolve-no-proxy\.mjs[\s\S]*UCLAW_NO_PROXY[\s\S]*set "NO_PROXY=/,
|
||||
'Windows-Start.bat should set NO_PROXY from resolve-no-proxy.mjs',
|
||||
);
|
||||
|
||||
const macStart = readRepoFile('portable', 'Mac-Start.command');
|
||||
assert.match(
|
||||
macStart,
|
||||
/resolve-no-proxy\.mjs[\s\S]*export NO_PROXY=/,
|
||||
'Mac-Start.command should export NO_PROXY from resolve-no-proxy.mjs',
|
||||
);
|
||||
});
|
||||
|
||||
test('customer-facing .bat launchers are pure ASCII (cmd.exe mis-parses UTF-8 Chinese on GBK Windows)', () => {
|
||||
// Non-ASCII bytes in a .bat get read as GBK by Chinese Windows cmd.exe, which
|
||||
// garbles parsing ("usebackq is not a command"). Chinese UX must live in the
|
||||
// node tools' stdout (rendered fine under chcp 65001), never in the .bat itself.
|
||||
for (const name of [
|
||||
'Windows-Start.bat',
|
||||
'Windows-IntranetFix.bat',
|
||||
'Windows-LocalModel.bat',
|
||||
'OpenClaw-Doctor.bat',
|
||||
]) {
|
||||
const bytes = readFileSync(join(repoRoot, 'portable', name));
|
||||
const offending = bytes.findIndex((b) => b > 0x7f);
|
||||
assert.equal(offending, -1, `${name} has a non-ASCII byte at offset ${offending}`);
|
||||
assert.ok(bytes.includes(0x0d), `${name} must use CRLF line endings`);
|
||||
}
|
||||
});
|
||||
|
||||
test('macOS .command launchers are LF-only (CRLF breaks #!/bin/bash on macOS)', () => {
|
||||
for (const name of [
|
||||
'Mac-Start.command',
|
||||
'Mac-IntranetFix.command',
|
||||
'Mac-LocalModel.command',
|
||||
'Mac-OpenClaw-Doctor.command',
|
||||
]) {
|
||||
const bytes = readFileSync(join(repoRoot, 'portable', name));
|
||||
const cr = bytes.indexOf(0x0d);
|
||||
assert.equal(cr, -1, `${name} has a CR byte at offset ${cr} (must be LF-only)`);
|
||||
assert.ok(bytes.toString('utf8').startsWith('#!/bin/bash'), `${name} must start with a clean shebang`);
|
||||
}
|
||||
});
|
||||
|
||||
test('macOS local-model / intranet launchers call the shared cross-platform scripts', () => {
|
||||
assert.match(readRepoFile('portable', 'Mac-IntranetFix.command'), /lib\/intranet-check\.mjs/);
|
||||
assert.match(readRepoFile('portable', 'Mac-LocalModel.command'), /lib\/setup-local-model\.mjs/);
|
||||
assert.match(readRepoFile('portable', 'Mac-OpenClaw-Doctor.command'), /doctor --non-interactive/);
|
||||
});
|
||||
|
||||
test('local-model setup launcher calls setup-local-model.mjs', () => {
|
||||
const bat = readRepoFile('portable', 'Windows-LocalModel.bat');
|
||||
assert.match(bat, /lib\\setup-local-model\.mjs/);
|
||||
});
|
||||
|
||||
test('OpenClaw doctor launcher is read-only (no destructive repair flags)', () => {
|
||||
const bat = readRepoFile('portable', 'OpenClaw-Doctor.bat');
|
||||
assert.match(bat, /OPENCLAW_MJS%" doctor --non-interactive/);
|
||||
// Must not auto-apply repairs that could overwrite user config/state.
|
||||
assert.doesNotMatch(bat, /doctor[^\n]*--fix/);
|
||||
assert.doesNotMatch(bat, /doctor[^\n]*--repair/);
|
||||
assert.doesNotMatch(bat, /doctor[^\n]*--force/);
|
||||
});
|
||||
|
||||
test('PowerShell installer generated start.bat disables OpenClaw bonjour discovery', () => {
|
||||
const script = readRepoFile('install', 'install.ps1');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user