openclawsetup 2.1.2 → 2.1.4

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/README.md CHANGED
@@ -72,6 +72,7 @@ npx openclawsetup@latest --auto
72
72
  | `--with-channel` | 检测到渠道配置时暂停自动选择 |
73
73
  | `--update` | 检查并更新已安装的 OpenClaw |
74
74
  | `--reinstall` | 卸载后重新安装(清除配置) |
75
+ | `--uninstall` | 卸载 OpenClaw |
75
76
  | `--help, -h` | 显示帮助信息 |
76
77
 
77
78
  ## 使用示例
@@ -100,6 +101,9 @@ npx openclawsetup@latest --update
100
101
 
101
102
  # 卸载后重新安装(会清除配置)
102
103
  npx openclawsetup@latest --reinstall
104
+
105
+ # 直接卸载
106
+ npx openclawsetup@latest --uninstall
103
107
  ```
104
108
 
105
109
  ## 安装后
@@ -114,6 +118,12 @@ npx openclawapi@latest preset-claude
114
118
  npx openclawapi@latest
115
119
  ```
116
120
 
121
+ ## Dashboard 访问
122
+
123
+ 安装完成后会自动显示:
124
+ - 本机访问地址(含 token)
125
+ - 云服务器场景下的 SSH 隧道命令与说明
126
+
117
127
  ## 配置聊天渠道
118
128
 
119
129
  ```bash
package/bin/cli.mjs CHANGED
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import { execSync, spawnSync } from 'child_process';
14
- import { existsSync, accessSync, constants as fsConstants, rmSync } from 'fs';
14
+ import { existsSync, accessSync, constants as fsConstants, rmSync, readFileSync } from 'fs';
15
15
  import { homedir, platform } from 'os';
16
16
  import { join } from 'path';
17
17
  import { createInterface } from 'readline';
@@ -51,6 +51,7 @@ function parseArgs() {
51
51
  return {
52
52
  update: args.includes('--update'),
53
53
  reinstall: args.includes('--reinstall'),
54
+ uninstall: args.includes('--uninstall'),
54
55
  manual: args.includes('--manual'),
55
56
  auto: args.includes('--auto'),
56
57
  withModel: args.includes('--with-model'),
@@ -67,6 +68,7 @@ ${colors.cyan('用法:')}
67
68
  npx openclawsetup 带中文指引的安装
68
69
  npx openclawsetup --update 更新已安装的 OpenClaw
69
70
  npx openclawsetup --reinstall 卸载后重新安装
71
+ npx openclawsetup --uninstall 卸载 OpenClaw
70
72
  npx openclawsetup --manual 完全手动模式
71
73
  npx openclawsetup --auto 强制自动模式
72
74
 
@@ -139,6 +141,65 @@ function detectExistingInstall() {
139
141
  return { installed: false };
140
142
  }
141
143
 
144
+ function getConfigInfo() {
145
+ const home = homedir();
146
+ const configs = [
147
+ { dir: join(home, '.openclaw'), file: 'openclaw.json' },
148
+ { dir: join(home, '.clawdbot'), file: 'clawdbot.json' },
149
+ ];
150
+
151
+ for (const cfg of configs) {
152
+ const configPath = join(cfg.dir, cfg.file);
153
+ if (!existsSync(configPath)) continue;
154
+ try {
155
+ const raw = readFileSync(configPath, 'utf8');
156
+ const json = JSON.parse(raw);
157
+ const token = json.token || json.gatewayToken || '';
158
+ const port = Number(json.port || json.gatewayPort || 18789);
159
+ const bind = json.bind || json.gatewayBind || '';
160
+ return { configDir: cfg.dir, configPath, token, port, bind, raw };
161
+ } catch {
162
+ try {
163
+ const raw = readFileSync(configPath, 'utf8');
164
+ const tokenMatch = raw.match(/"token"\\s*:\\s*"([^"]+)"/i);
165
+ const portMatch = raw.match(/"port"\\s*:\\s*(\\d+)/i);
166
+ const bindMatch = raw.match(/"bind"\\s*:\\s*"([^"]+)"/i);
167
+ return {
168
+ configDir: cfg.dir,
169
+ configPath,
170
+ token: tokenMatch ? tokenMatch[1] : '',
171
+ port: portMatch ? Number(portMatch[1]) : 18789,
172
+ bind: bindMatch ? bindMatch[1] : '',
173
+ raw,
174
+ };
175
+ } catch {
176
+ return { configDir: cfg.dir, configPath, token: '', port: 18789, bind: '', raw: '' };
177
+ }
178
+ }
179
+ }
180
+ return { configDir: '', configPath: '', token: '', port: 18789, bind: '', raw: '' };
181
+ }
182
+
183
+ function detectVps() {
184
+ return existsSync('/etc/cloud') || existsSync('/var/lib/cloud') || existsSync('/sys/hypervisor');
185
+ }
186
+
187
+ function getServerIp() {
188
+ const candidates = [
189
+ 'curl -s --connect-timeout 2 ifconfig.me',
190
+ 'curl -s --connect-timeout 2 icanhazip.com',
191
+ 'curl -s --connect-timeout 2 ipinfo.io/ip',
192
+ "hostname -I 2>/dev/null | awk '{print $1}'",
193
+ ];
194
+ for (const cmd of candidates) {
195
+ const result = safeExec(cmd);
196
+ if (result.ok && result.output) {
197
+ return result.output.trim();
198
+ }
199
+ }
200
+ return '';
201
+ }
202
+
142
203
  // ============ 安装指引 ============
143
204
 
144
205
  function showInstallGuide() {
@@ -676,6 +737,8 @@ function showCompletionInfo(cliName) {
676
737
  console.log(colors.cyan('\n下一步 - 配置 AI 模型(必须):'));
677
738
  console.log(` ${colors.yellow('npx openclawapi@latest preset-claude')}`);
678
739
 
740
+ showDashboardAccessInfo();
741
+
679
742
  console.log(colors.cyan('\n常用命令:'));
680
743
  console.log(` 查看状态: ${colors.yellow(`${cliName} status`)}`);
681
744
  console.log(` 查看日志: ${colors.yellow(`${cliName} gateway logs`)}`);
@@ -689,6 +752,78 @@ function showCompletionInfo(cliName) {
689
752
  console.log('');
690
753
  }
691
754
 
755
+ function showDashboardAccessInfo() {
756
+ const config = getConfigInfo();
757
+ const port = config.port || 18789;
758
+ const token = config.token || '<你的token>';
759
+ const dashboardUrl = `http://127.0.0.1:${port}/?token=${token}`;
760
+
761
+ if (detectVps()) {
762
+ const serverIp = getServerIp() || '<服务器IP>';
763
+ const user = process.env.USER || 'root';
764
+
765
+ console.log(colors.cyan('\n📡 Dashboard 访问(云服务器):'));
766
+ console.log(colors.gray(' Gateway 默认绑定 127.0.0.1,外部无法直接访问(安全设计)'));
767
+ console.log('');
768
+ console.log(colors.yellow(' 方式一:SSH 隧道(推荐,安全)'));
769
+ console.log(colors.gray(' 在本地电脑执行以下命令,保持终端窗口打开:'));
770
+ console.log(` ${colors.green(`ssh -N -L ${port}:127.0.0.1:${port} ${user}@${serverIp}`)}`);
771
+ console.log(colors.gray(' 然后在本地浏览器访问:'));
772
+ console.log(` ${colors.green(dashboardUrl)}`);
773
+ console.log('');
774
+ console.log(colors.yellow(' 方式二:直接暴露端口(不推荐,有安全风险)'));
775
+ console.log(colors.gray(' 1. 修改配置文件 ~/.openclaw/openclaw.json'));
776
+ console.log(colors.gray(' 将 "bind": "loopback" 改为 "bind": "all"'));
777
+ console.log(colors.gray(` 2. 在云服务器控制台开放端口 ${port}`));
778
+ console.log(colors.gray(' 3. 重启 Gateway:openclaw gateway restart'));
779
+ console.log(colors.gray(` 4. 访问:http://${serverIp}:${port}/?token=...`));
780
+ } else {
781
+ console.log(colors.cyan('\nDashboard 访问:'));
782
+ console.log(` ${colors.yellow(dashboardUrl)}`);
783
+ }
784
+ }
785
+
786
+ async function uninstallOpenClaw(existing) {
787
+ const cliName = existing?.name || 'openclaw';
788
+ const useSudo = needsSudo();
789
+
790
+ console.log(colors.cyan('\n开始卸载...'));
791
+
792
+ safeExec(`${cliName} gateway stop`);
793
+
794
+ if (useSudo) {
795
+ console.log(colors.yellow('\n请运行以下命令卸载:'));
796
+ console.log(colors.green(` sudo npm uninstall -g ${cliName}`));
797
+ console.log(colors.green(' rm -rf ~/.openclaw ~/.clawdbot\n'));
798
+ await waitForEnter('卸载完成后按回车继续...');
799
+ } else {
800
+ spawnSync('npm', ['uninstall', '-g', cliName], { stdio: 'inherit', shell: true });
801
+ }
802
+
803
+ const config = getConfigInfo();
804
+ if (config.configDir && existsSync(config.configDir)) {
805
+ rmSync(config.configDir, { recursive: true, force: true });
806
+ }
807
+ const otherDir = config.configDir?.endsWith('.openclaw') ? join(homedir(), '.clawdbot') : join(homedir(), '.openclaw');
808
+ if (existsSync(otherDir)) {
809
+ rmSync(otherDir, { recursive: true, force: true });
810
+ }
811
+
812
+ if (platform() === 'darwin') {
813
+ const plist = join(homedir(), 'Library/LaunchAgents/com.openclaw.gateway.plist');
814
+ safeExec(`launchctl unload "${plist}"`);
815
+ if (existsSync(plist)) rmSync(plist, { force: true });
816
+ } else if (platform() === 'linux') {
817
+ safeExec('systemctl --user stop openclaw');
818
+ safeExec('systemctl --user disable openclaw');
819
+ const service = join(homedir(), '.config/systemd/user/openclaw.service');
820
+ if (existsSync(service)) rmSync(service, { force: true });
821
+ safeExec('systemctl --user daemon-reload');
822
+ }
823
+
824
+ log.success('卸载完成');
825
+ }
826
+
692
827
  // ============ 主函数 ============
693
828
 
694
829
  async function main() {
@@ -716,27 +851,20 @@ async function main() {
716
851
  process.exit(0);
717
852
  }
718
853
 
854
+ if (options.uninstall) {
855
+ await uninstallOpenClaw(existing);
856
+ process.exit(0);
857
+ }
858
+
719
859
  if (options.reinstall) {
720
- log.info('\n卸载现有安装...');
721
- safeExec(`${existing.name} gateway stop`);
722
-
723
- if (needsSudo()) {
724
- console.log(colors.yellow('\n请运行以下命令卸载:'));
725
- console.log(colors.green(` sudo npm uninstall -g ${existing.name}`));
726
- console.log(colors.green(` rm -rf ~/.openclaw ~/.clawdbot\n`));
727
- await waitForEnter('卸载完成后按回车继续...');
728
- } else {
729
- spawnSync('npm', ['uninstall', '-g', existing.name], { stdio: 'inherit', shell: true });
730
- if (existing.configDir && existsSync(existing.configDir)) {
731
- rmSync(existing.configDir, { recursive: true, force: true });
732
- }
733
- log.success('卸载完成');
734
- }
860
+ await uninstallOpenClaw(existing);
735
861
  } else {
736
862
  console.log(colors.cyan('\n已安装,可选操作:'));
737
863
  console.log(` 更新: ${colors.yellow('npx openclawsetup --update')}`);
738
864
  console.log(` 重装: ${colors.yellow('npx openclawsetup --reinstall')}`);
865
+ console.log(` 卸载: ${colors.yellow('npx openclawsetup --uninstall')}`);
739
866
  console.log(` 配置模型: ${colors.yellow('npx openclawapi@latest preset-claude')}`);
867
+ showDashboardAccessInfo();
740
868
  console.log('');
741
869
  process.exit(0);
742
870
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclawsetup",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "OpenClaw 安装向导 - 带中文指引的官方安装流程",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74,6 +74,9 @@ npx openclawsetup@latest --update
74
74
 
75
75
  # 卸载后重新安装(会清除配置)
76
76
  npx openclawsetup@latest --reinstall
77
+
78
+ # 直接卸载
79
+ npx openclawsetup@latest --uninstall
77
80
  ```
78
81
 
79
82
  ## 安装完成后
@@ -84,10 +87,9 @@ npx openclawsetup@latest --reinstall
84
87
  ```
85
88
 
86
89
  2. **访问 Dashboard**
87
- ```
88
- http://127.0.0.1:18789/?token=<你的token>
89
- ```
90
- Token 在安装完成时会显示。
90
+ 安装完成后会自动显示:
91
+ - 本机访问地址(含 token
92
+ - 云服务器场景下的 SSH 隧道命令与说明
91
93
 
92
94
  3. **配置聊天渠道(可选)**
93
95
  ```bash