openclawsetup 2.8.12 → 2.8.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +85 -16
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
renameSync,
|
|
22
22
|
mkdirSync,
|
|
23
23
|
writeFileSync,
|
|
24
|
+
statSync,
|
|
24
25
|
} from 'fs';
|
|
25
26
|
import { createServer } from 'net';
|
|
26
27
|
import { homedir, platform, arch, release, hostname } from 'os';
|
|
@@ -521,7 +522,7 @@ async function collectEvidencePackage(options = {}) {
|
|
|
521
522
|
|
|
522
523
|
const snapshot = gatherEnvironmentSnapshot();
|
|
523
524
|
const tokenOptimizationPreview = createTokenOptimizationPlan();
|
|
524
|
-
const cliName = snapshot.openclaw.detectedInstall?.name || findWorkingCliName() || 'openclaw';
|
|
525
|
+
const cliName = snapshot.openclaw.detectedInstall?.name || findWorkingCliName(snapshot.openclaw.configDir?.includes('.clawdbot') ? 'clawdbot' : undefined) || 'openclaw';
|
|
525
526
|
|
|
526
527
|
const captures = {
|
|
527
528
|
doctor: runCmdCapture(`${cliName} doctor`, quick ? 20000 : 90000),
|
|
@@ -697,9 +698,9 @@ ${colors.cyan('安装后配置模型:')}
|
|
|
697
698
|
npx openclawapi@latest # 交互式配置
|
|
698
699
|
|
|
699
700
|
${colors.cyan('常见问题快速修复:')}
|
|
700
|
-
Gateway 未启动: openclaw gateway start
|
|
701
|
+
Gateway 未启动: openclaw gateway start (或 clawdbot gateway start)
|
|
701
702
|
端口被占用: openclaw config set gateway.port 18790
|
|
702
|
-
配置文件损坏:
|
|
703
|
+
配置文件损坏: 重新运行 npx openclawsetup@latest
|
|
703
704
|
`);
|
|
704
705
|
}
|
|
705
706
|
|
|
@@ -796,8 +797,17 @@ function isRealGatewayCli(name) {
|
|
|
796
797
|
return true;
|
|
797
798
|
}
|
|
798
799
|
|
|
799
|
-
function findWorkingCliName() {
|
|
800
|
-
|
|
800
|
+
function findWorkingCliName(preferredName) {
|
|
801
|
+
const candidates = ['openclaw', 'clawdbot', 'moltbot'];
|
|
802
|
+
// If a preferred name is given (e.g. matching the config dir), check it first
|
|
803
|
+
if (preferredName) {
|
|
804
|
+
const reordered = [preferredName, ...candidates.filter(n => n !== preferredName)];
|
|
805
|
+
for (const name of reordered) {
|
|
806
|
+
if (isRealGatewayCli(name)) return name;
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
for (const name of candidates) {
|
|
801
811
|
if (isRealGatewayCli(name)) return name;
|
|
802
812
|
}
|
|
803
813
|
return null;
|
|
@@ -809,13 +819,49 @@ function detectExistingInstall() {
|
|
|
809
819
|
const clawdbotDir = join(home, '.clawdbot');
|
|
810
820
|
|
|
811
821
|
if (existsSync(openclawDir) || existsSync(clawdbotDir)) {
|
|
812
|
-
|
|
813
|
-
const
|
|
822
|
+
// Determine which config dir has an actual config file (not just an empty directory)
|
|
823
|
+
const hasOpenclawConfig = existsSync(join(openclawDir, 'openclaw.json'));
|
|
824
|
+
const hasClawdbotConfig = existsSync(join(clawdbotDir, 'clawdbot.json'));
|
|
825
|
+
|
|
826
|
+
let configDir;
|
|
827
|
+
let preferredCli;
|
|
828
|
+
|
|
829
|
+
if (hasClawdbotConfig && !hasOpenclawConfig) {
|
|
830
|
+
// Only clawdbot has a real config — prefer clawdbot
|
|
831
|
+
configDir = clawdbotDir;
|
|
832
|
+
preferredCli = 'clawdbot';
|
|
833
|
+
} else if (hasOpenclawConfig && !hasClawdbotConfig) {
|
|
834
|
+
// Only openclaw has a real config — prefer openclaw
|
|
835
|
+
configDir = openclawDir;
|
|
836
|
+
preferredCli = 'openclaw';
|
|
837
|
+
} else if (hasClawdbotConfig && hasOpenclawConfig) {
|
|
838
|
+
// Both have configs — prefer the one modified more recently
|
|
839
|
+
try {
|
|
840
|
+
const ocStat = statSync(join(openclawDir, 'openclaw.json'));
|
|
841
|
+
const cbStat = statSync(join(clawdbotDir, 'clawdbot.json'));
|
|
842
|
+
if (cbStat.mtimeMs >= ocStat.mtimeMs) {
|
|
843
|
+
configDir = clawdbotDir;
|
|
844
|
+
preferredCli = 'clawdbot';
|
|
845
|
+
} else {
|
|
846
|
+
configDir = openclawDir;
|
|
847
|
+
preferredCli = 'openclaw';
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
850
|
+
configDir = clawdbotDir;
|
|
851
|
+
preferredCli = 'clawdbot';
|
|
852
|
+
}
|
|
853
|
+
} else {
|
|
854
|
+
// Neither has a config file — just pick whichever dir exists
|
|
855
|
+
configDir = existsSync(openclawDir) ? openclawDir : clawdbotDir;
|
|
856
|
+
preferredCli = existsSync(openclawDir) ? 'openclaw' : 'clawdbot';
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
const cliName = findWorkingCliName(preferredCli);
|
|
814
860
|
if (cliName) {
|
|
815
861
|
return { installed: true, configDir, name: cliName };
|
|
816
862
|
}
|
|
817
863
|
// Config dir exists but no working CLI found
|
|
818
|
-
return { installed: true, configDir, name:
|
|
864
|
+
return { installed: true, configDir, name: preferredCli, cliMissing: true };
|
|
819
865
|
}
|
|
820
866
|
|
|
821
867
|
const cliName = findWorkingCliName();
|
|
@@ -1097,13 +1143,34 @@ function hasListeningState(output = '') {
|
|
|
1097
1143
|
|
|
1098
1144
|
function gatewayHealthRequest(port, path = '/health') {
|
|
1099
1145
|
const endpoint = `http://127.0.0.1:${port}${path}`;
|
|
1146
|
+
// Try Node.js native fetch first (available in Node 18+), then fall back to curl
|
|
1147
|
+
try {
|
|
1148
|
+
const result = execSync(
|
|
1149
|
+
`node -e "fetch('${endpoint}',{signal:AbortSignal.timeout(4000)}).then(r=>r.text()).then(t=>process.stdout.write(t)).catch(()=>process.exit(1))"`,
|
|
1150
|
+
{ timeout: 7000, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] },
|
|
1151
|
+
);
|
|
1152
|
+
if (result) return { ok: true, output: result };
|
|
1153
|
+
} catch { /* fall through to curl */ }
|
|
1100
1154
|
const curlCmd = `curl -sS --max-time 5 --connect-timeout 2 ${endpoint}`;
|
|
1101
1155
|
return safeExec(curlCmd, { timeout: 7000 });
|
|
1102
1156
|
}
|
|
1103
1157
|
|
|
1104
1158
|
function gatewayHttpStatusProbe(port, path = '/v1/responses') {
|
|
1105
1159
|
const endpoint = `http://127.0.0.1:${port}${path}`;
|
|
1106
|
-
|
|
1160
|
+
// Try Node.js native fetch first (avoids Windows cmd.exe % escaping issues with curl)
|
|
1161
|
+
try {
|
|
1162
|
+
const result = execSync(
|
|
1163
|
+
`node -e "fetch('${endpoint}',{signal:AbortSignal.timeout(4000)}).then(r=>{process.stdout.write(String(r.status));process.exit(0)}).catch(()=>process.exit(1))"`,
|
|
1164
|
+
{ timeout: 7000, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] },
|
|
1165
|
+
);
|
|
1166
|
+
const status = Number(result);
|
|
1167
|
+
if (Number.isInteger(status) && status > 0) {
|
|
1168
|
+
return { ok: true, status };
|
|
1169
|
+
}
|
|
1170
|
+
} catch { /* fall through to curl */ }
|
|
1171
|
+
// Fallback: curl (on Windows, escape % for cmd.exe)
|
|
1172
|
+
const fmt = platform() === 'win32' ? '%%{http_code}' : '%{http_code}';
|
|
1173
|
+
const cmd = `curl -sS -o ${platform() === 'win32' ? 'NUL' : '/dev/null'} -w "${fmt}" --max-time 5 --connect-timeout 2 ${endpoint}`;
|
|
1107
1174
|
const result = safeExec(cmd, { timeout: 7000 });
|
|
1108
1175
|
if (!result.ok || !result.output) {
|
|
1109
1176
|
return { ok: false, status: 0 };
|
|
@@ -1696,7 +1763,7 @@ function showInstallGuide() {
|
|
|
1696
1763
|
console.log(colors.bold(colors.cyan(' 📖 OpenClaw 安装指引')));
|
|
1697
1764
|
console.log(colors.bold(colors.cyan('='.repeat(60))));
|
|
1698
1765
|
|
|
1699
|
-
console.log(colors.yellow('\n接下来会运行官方
|
|
1766
|
+
console.log(colors.yellow('\n接下来会运行官方 onboard 命令'));
|
|
1700
1767
|
console.log(colors.yellow('自动模式会按以下推荐选择(可随时接管):\n'));
|
|
1701
1768
|
|
|
1702
1769
|
console.log(colors.cyan('┌─────────────────────────────────────────────────────────┐'));
|
|
@@ -1910,7 +1977,7 @@ async function runOnboard(cliName) {
|
|
|
1910
1977
|
console.log(colors.bold(colors.cyan('\n[2/2] 运行配置向导\n')));
|
|
1911
1978
|
|
|
1912
1979
|
console.log(colors.gray('-'.repeat(60)));
|
|
1913
|
-
console.log(colors.gray('以下是官方
|
|
1980
|
+
console.log(colors.gray('以下是官方 onboard 界面:'));
|
|
1914
1981
|
console.log(colors.gray('-'.repeat(60) + '\n'));
|
|
1915
1982
|
|
|
1916
1983
|
const manualResult = runOnboardManual(cliName);
|
|
@@ -2269,7 +2336,7 @@ function showCompletionInfo(cliName) {
|
|
|
2269
2336
|
console.log(colors.cyan('\n下一步 - 配置 AI 模型(必须):'));
|
|
2270
2337
|
console.log(` ${colors.yellow('npx openclawapi@latest preset-claude')}`);
|
|
2271
2338
|
|
|
2272
|
-
showDashboardAccessInfo();
|
|
2339
|
+
showDashboardAccessInfo(cliName);
|
|
2273
2340
|
|
|
2274
2341
|
console.log(colors.cyan('\n常用命令:'));
|
|
2275
2342
|
console.log(` 查看状态: ${colors.yellow(`${cliName} status`)}`);
|
|
@@ -2284,12 +2351,14 @@ function showCompletionInfo(cliName) {
|
|
|
2284
2351
|
console.log('');
|
|
2285
2352
|
}
|
|
2286
2353
|
|
|
2287
|
-
function showDashboardAccessInfo() {
|
|
2354
|
+
function showDashboardAccessInfo(cliName) {
|
|
2288
2355
|
const config = getConfigInfo();
|
|
2289
2356
|
const port = config.port || 18789;
|
|
2290
2357
|
const tokenRaw = getDashboardToken(config) || '<你的token>';
|
|
2291
2358
|
const tokenMasked = maskToken(tokenRaw);
|
|
2292
2359
|
const dashboardUrl = `http://127.0.0.1:${port}/?token=${tokenMasked}`;
|
|
2360
|
+
const activeCli = cliName || (config.configPath?.includes('.clawdbot') ? 'clawdbot' : 'openclaw');
|
|
2361
|
+
const configFileName = config.configPath || `~/.${activeCli}/${activeCli}.json`;
|
|
2293
2362
|
|
|
2294
2363
|
if (detectVps()) {
|
|
2295
2364
|
const serverIp = getServerIp() || '<服务器IP>';
|
|
@@ -2305,10 +2374,10 @@ function showDashboardAccessInfo() {
|
|
|
2305
2374
|
console.log(` ${colors.green(dashboardUrl)}`);
|
|
2306
2375
|
console.log('');
|
|
2307
2376
|
console.log(colors.yellow(' 方式二:直接暴露端口(不推荐,有安全风险)'));
|
|
2308
|
-
console.log(colors.gray(
|
|
2377
|
+
console.log(colors.gray(` 1. 修改配置文件 ${configFileName}`));
|
|
2309
2378
|
console.log(colors.gray(' 将 "bind": "loopback" 改为 "bind": "all"'));
|
|
2310
2379
|
console.log(colors.gray(` 2. 在云服务器控制台开放端口 ${port}`));
|
|
2311
|
-
console.log(colors.gray(
|
|
2380
|
+
console.log(colors.gray(` 3. 重启 Gateway:${activeCli} gateway restart`));
|
|
2312
2381
|
console.log(colors.gray(` 4. 访问:http://${serverIp}:${port}/?token=...`));
|
|
2313
2382
|
} else {
|
|
2314
2383
|
console.log(colors.cyan('\nDashboard 访问:'));
|
|
@@ -2960,7 +3029,7 @@ async function showInteractiveMenu(existing) {
|
|
|
2960
3029
|
console.log(colors.bold(colors.cyan(' 🦞 OpenClaw 管理菜单')));
|
|
2961
3030
|
console.log(colors.bold(colors.cyan('='.repeat(50))));
|
|
2962
3031
|
|
|
2963
|
-
showDashboardAccessInfo();
|
|
3032
|
+
showDashboardAccessInfo(cliName);
|
|
2964
3033
|
|
|
2965
3034
|
console.log(colors.cyan('\n请选择操作:'));
|
|
2966
3035
|
console.log(` ${colors.yellow('1')}. 状态信息`);
|