baozang-activator 1.2.3 → 1.2.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/OPENCLAW.md CHANGED
@@ -153,6 +153,19 @@ where openclaw
153
153
  ### Q3: 安装后提示 PATH 缺失
154
154
  如果提示 npm 全局 bin 不在 PATH,重开终端后仍不生效时,请把对应路径加入 shell 配置(如 `~/.bashrc` / `~/.zshrc`),再 `source` 生效。
155
155
 
156
+ ### Q4: macOS 显示 `LaunchAgent (not loaded)`,但日志里有 `RPC probe: ok`
157
+ 这是 OpenClaw 在 macOS 上的常见状态之一。只要状态输出里同时出现:
158
+
159
+ ```text
160
+ RPC probe: ok
161
+ Listening: 127.0.0.1:18789
162
+ ```
163
+
164
+ 就说明网关实际已经可用。`baozang-activator` `1.2.4` 起会按探活结果判定成功,不再因为 `launchctl` 的未加载提示直接报错。
165
+
166
+ ### Q5: Windows 卸载报 `exit null`
167
+ 这是 Windows 下 `.cmd` shim 调用方式导致的子进程状态异常。`baozang-activator` `1.2.4` 起会通过显式 `cmd.exe` 调用 `openclaw`,避免这个问题。
168
+
156
169
  ## 8) 验证清单
157
170
 
158
171
  安装后建议至少执行一次:
package/README.md CHANGED
@@ -35,7 +35,7 @@ npm i -g baozang-activator@latest
35
35
  ```bash
36
36
  baozang-activator -v
37
37
  ```
38
- 应显示:`1.2.3`(或更高)
38
+ 应显示:`1.2.4`(或更高)
39
39
 
40
40
  ### 3) 重新执行激活(会刷新本地 auth.json)
41
41
  ```bash
package/lib/openclaw.js CHANGED
@@ -24,6 +24,30 @@ function commandExists(command) {
24
24
  return result.status === 0;
25
25
  }
26
26
 
27
+ function getCommandPath(command) {
28
+ const checker = IS_WINDOWS ? 'where' : 'which';
29
+ const result = spawnSync(checker, [command], {
30
+ encoding: 'utf8',
31
+ stdio: ['ignore', 'pipe', 'ignore'],
32
+ });
33
+ if (result.status !== 0) {
34
+ return '';
35
+ }
36
+
37
+ const lines = String(result.stdout || '')
38
+ .split(/\r?\n/)
39
+ .map((line) => sanitizeText(line))
40
+ .filter(Boolean);
41
+
42
+ for (const line of lines) {
43
+ if (!IS_WINDOWS || /\.cmd$|\.bat$|\.exe$/i.test(line) || fs.existsSync(line)) {
44
+ return line;
45
+ }
46
+ }
47
+
48
+ return lines[0] || '';
49
+ }
50
+
27
51
  function getNpmCommand() {
28
52
  return IS_WINDOWS ? 'npm.cmd' : 'npm';
29
53
  }
@@ -52,9 +76,10 @@ function getNpmGlobalBin() {
52
76
  }
53
77
 
54
78
  function resolveOpenClawCommand() {
55
- if (commandExists('openclaw')) {
79
+ const existingPath = getCommandPath('openclaw');
80
+ if (existingPath) {
56
81
  return {
57
- cmd: 'openclaw',
82
+ cmd: existingPath,
58
83
  env: null,
59
84
  };
60
85
  }
@@ -111,6 +136,17 @@ function runShell(commandString, options = {}) {
111
136
  return runCommand(bash, ['-lc', commandString], options);
112
137
  }
113
138
 
139
+ function quoteWindowsArg(value) {
140
+ const text = String(value || '');
141
+ if (!text) {
142
+ return '""';
143
+ }
144
+ if (!/[\s"&()^<>|]/.test(text)) {
145
+ return text;
146
+ }
147
+ return `"${text.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, '$1$1')}"`;
148
+ }
149
+
114
150
  function ensureDir(dirPath) {
115
151
  if (!fs.existsSync(dirPath)) {
116
152
  fs.mkdirSync(dirPath, { recursive: true });
@@ -198,6 +234,15 @@ function getDashboardUrl(options = {}) {
198
234
  function openclaw(args, options = {}) {
199
235
  const resolved = resolveOpenClawCommand();
200
236
  const env = resolved.env ? resolved.env : process.env;
237
+ if (IS_WINDOWS) {
238
+ const commandLine = [resolved.cmd, ...(args || [])]
239
+ .map((part) => quoteWindowsArg(part))
240
+ .join(' ');
241
+ return runCommand('cmd.exe', ['/d', '/s', '/c', commandLine], {
242
+ env,
243
+ ...options,
244
+ });
245
+ }
201
246
  return runCommand(resolved.cmd, args, {
202
247
  env,
203
248
  ...options,
@@ -490,23 +535,18 @@ function startGateway() {
490
535
  }
491
536
 
492
537
  let status = getGatewayStatusText();
493
- if (status.ok && parseGatewayRunning(status.text)) {
538
+ if (parseGatewayRunning(status.text)) {
494
539
  return { ok: true, message: '' };
495
540
  }
496
541
 
497
542
  const startText = sanitizeText(`${startResult.stdout}\n${startResult.stderr}`);
498
- if (
499
- startResult.status === 0 &&
500
- (startText.includes('Gateway service disabled') || sanitizeText(status.text).includes('disabled'))
501
- ) {
543
+ if (startResult.status === 0 && (gatewayServiceNeedsInstall(startText) || gatewayServiceNeedsInstall(status.text))) {
502
544
  const installResult = openclaw(['gateway', 'install'], { stdio: 'inherit' });
503
545
  if (installResult.status === 0) {
504
- const retry = openclaw(['gateway', 'start'], { stdio: 'inherit' });
505
- if (retry.status === 0) {
506
- status = getGatewayStatusText();
507
- if (status.ok && parseGatewayRunning(status.text)) {
508
- return { ok: true, message: '' };
509
- }
546
+ openclaw(['gateway', 'start'], { stdio: 'inherit' });
547
+ status = getGatewayStatusText();
548
+ if (parseGatewayRunning(status.text)) {
549
+ return { ok: true, message: '' };
510
550
  }
511
551
  }
512
552
  }
@@ -523,7 +563,7 @@ function startGateway() {
523
563
  child.unref();
524
564
  sleepMs(2000);
525
565
  status = getGatewayStatusText();
526
- if (status.ok && parseGatewayRunning(status.text)) {
566
+ if (parseGatewayRunning(status.text)) {
527
567
  return { ok: true, message: '' };
528
568
  }
529
569
  } catch (error) {
@@ -564,6 +604,9 @@ function parseGatewayRunning(statusText) {
564
604
  if (!text) {
565
605
  return false;
566
606
  }
607
+ if (text.includes('rpc probe: ok') || text.includes('listening: 127.0.0.1:') || text.includes('listening: localhost:')) {
608
+ return true;
609
+ }
567
610
  if (text.includes('not running') || text.includes('stopped') || text.includes('未运行') || text.includes('已停止')) {
568
611
  return false;
569
612
  }
@@ -578,14 +621,30 @@ function parseGatewayStopped(statusText) {
578
621
  if (!text) {
579
622
  return false;
580
623
  }
624
+ if (text.includes('rpc probe: ok') || text.includes('listening: 127.0.0.1:') || text.includes('listening: localhost:')) {
625
+ return false;
626
+ }
581
627
  return text.includes('not running') || text.includes('stopped') || text.includes('未运行') || text.includes('已停止');
582
628
  }
583
629
 
630
+ function gatewayServiceNeedsInstall(statusText) {
631
+ const text = sanitizeText(statusText).toLowerCase();
632
+ if (!text) {
633
+ return false;
634
+ }
635
+ return text.includes('service disabled')
636
+ || text.includes('gateway service disabled')
637
+ || text.includes('service not loaded')
638
+ || text.includes('gateway service not loaded')
639
+ || text.includes('launchagent (not loaded)')
640
+ || text.includes('could not find service');
641
+ }
642
+
584
643
  function verifyOpenClawReady() {
585
644
  const status = getGatewayStatusText();
586
645
  const running = parseGatewayRunning(status.text);
587
646
  const stopped = parseGatewayStopped(status.text);
588
- if (status.ok && (running || !stopped)) {
647
+ if (running || (status.ok && !stopped)) {
589
648
  return {
590
649
  ok: true,
591
650
  status: 'gateway-running',
@@ -750,7 +809,8 @@ function uninstallOpenClaw(params) {
750
809
 
751
810
  const result = openclaw(args, { stdio: 'inherit' });
752
811
  if (result.status !== 0) {
753
- return { ok: false, message: `OpenClaw 卸载失败(exit ${result.status})` };
812
+ const suffix = result.error && result.error.message ? `: ${result.error.message}` : '';
813
+ return { ok: false, message: `OpenClaw 卸载失败(exit ${String(result.status)})${suffix}` };
754
814
  }
755
815
 
756
816
  if (removeCli) {
@@ -784,5 +844,12 @@ module.exports = {
784
844
  openBrowser,
785
845
  getDefaultDashboardUrl,
786
846
  getDashboardUrl,
847
+ __internal: {
848
+ getCommandPath,
849
+ quoteWindowsArg,
850
+ parseGatewayRunning,
851
+ parseGatewayStopped,
852
+ gatewayServiceNeedsInstall,
853
+ },
787
854
  HOME,
788
855
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baozang-activator",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "API 激活工具 (生产环境 - baozangaizhongzhuan.net)",
5
5
  "main": "lib/index.js",
6
6
  "bin": {