codewave-openclaw-installer 2.1.2 → 2.1.3

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/check.mjs CHANGED
@@ -16,6 +16,11 @@ import { spawn } from 'node:child_process';
16
16
  import { existsSync, readFileSync } from 'node:fs';
17
17
  import { join } from 'node:path';
18
18
  import { homedir, platform } from 'node:os';
19
+ import {
20
+ CHANNEL_DEFINITIONS,
21
+ detectDesktopAppInstallMatches,
22
+ getDesktopAppCandidates,
23
+ } from './install-lib.mjs';
19
24
 
20
25
  // ─── 颜色 ───
21
26
  const NO_COLOR = process.env.NO_COLOR || process.argv.includes('--json');
@@ -32,6 +37,12 @@ const isMac = process.platform === 'darwin';
32
37
  const isLinux = process.platform === 'linux';
33
38
  const JSON_MODE = process.argv.includes('--json');
34
39
  const FIX_MODE = process.argv.includes('--fix');
40
+ const WINDOWS_UNINSTALL_KEYS = [
41
+ 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
42
+ 'HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
43
+ 'HKLM\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
44
+ ];
45
+ let windowsUninstallDisplayNamesPromise = null;
35
46
 
36
47
  // ─── 工具函数 ───
37
48
 
@@ -86,6 +97,54 @@ function run(cmd, args) {
86
97
  });
87
98
  }
88
99
 
100
+ function runCapture(cmd, args) {
101
+ return new Promise((resolve) => {
102
+ const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], shell: isWin });
103
+ let stdout = '';
104
+ let stderr = '';
105
+ child.stdout?.on('data', (chunk) => { stdout += chunk.toString(); });
106
+ child.stderr?.on('data', (chunk) => { stderr += chunk.toString(); });
107
+ child.on('close', (code) => resolve({ code: code ?? 1, stdout, stderr }));
108
+ child.on('error', (err) => resolve({ code: 1, stdout, stderr: err.message }));
109
+ });
110
+ }
111
+
112
+ async function getWindowsUninstallDisplayNames() {
113
+ if (!isWin) {
114
+ return [];
115
+ }
116
+ if (!windowsUninstallDisplayNamesPromise) {
117
+ windowsUninstallDisplayNamesPromise = (async () => {
118
+ const displayNames = [];
119
+ for (const registryKey of WINDOWS_UNINSTALL_KEYS) {
120
+ const result = await runCapture('reg', ['query', registryKey, '/s', '/v', 'DisplayName']);
121
+ const lines = `${result.stdout}\n${result.stderr}`.split(/\r?\n/);
122
+ for (const line of lines) {
123
+ const match = line.match(/^\s*DisplayName\s+REG_\w+\s+(.+?)\s*$/i);
124
+ if (match?.[1]) {
125
+ displayNames.push(match[1].trim());
126
+ }
127
+ }
128
+ }
129
+ return [...new Set(displayNames)];
130
+ })();
131
+ }
132
+ return windowsUninstallDisplayNamesPromise;
133
+ }
134
+
135
+ async function findDesktopApps(definition) {
136
+ const installedRegistryDisplayNames = await getWindowsUninstallDisplayNames();
137
+ return detectDesktopAppInstallMatches({
138
+ platform: process.platform,
139
+ homeDir: homedir(),
140
+ env: process.env,
141
+ fileCandidates: getDesktopAppCandidates(definition, process.platform),
142
+ registryDisplayNames: definition.desktopAppWindowsRegistryNames ?? [],
143
+ installedRegistryDisplayNames,
144
+ exists: existsSync,
145
+ });
146
+ }
147
+
89
148
  // ─── 检测项定义 ───
90
149
 
91
150
  /** @typedef {{ name: string, status: 'ok'|'warn'|'fail', version?: string, message: string, fix?: string }} CheckResult */
@@ -267,9 +326,11 @@ async function checkChannel(name, configPaths, envVars, commands, options = {})
267
326
 
268
327
  const configMatches = configPaths.filter(fileExists);
269
328
  const envMatches = envVars.filter((key) => Boolean(process.env[key]));
329
+ const desktopMatches = options.definition ? await findDesktopApps(options.definition) : [];
270
330
 
271
331
  const hints = [
272
332
  ...commandMatches.map((cmd) => `命令:${cmd}`),
333
+ ...desktopMatches.map((path) => `桌面客户端:${path}`),
273
334
  ...configMatches.map((path) => `配置:${path}`),
274
335
  ...envMatches.map((key) => `环境变量:${key}`),
275
336
  ];
@@ -282,7 +343,7 @@ async function checkChannel(name, configPaths, envVars, commands, options = {})
282
343
  };
283
344
  }
284
345
 
285
- if (configMatches.length > 0 || envMatches.length > 0) {
346
+ if (desktopMatches.length > 0 || configMatches.length > 0 || envMatches.length > 0) {
286
347
  return {
287
348
  name,
288
349
  status: 'warn',
@@ -416,11 +477,12 @@ async function main() {
416
477
  ],
417
478
  ['LARK_APP_ID', 'LARK_APP_SECRET', 'FEISHU_APP_ID', 'FEISHU_APP_SECRET'],
418
479
  [],
419
- { hintMessage: `检测到环境线索,可通过 openclaw 渠道引导继续 (${[
480
+ { definition: CHANNEL_DEFINITIONS.lark, hintMessage: `检测到环境线索,可通过 openclaw 渠道引导继续 (${[
420
481
  join(homedir(), '.openclaw', 'lark.json'),
421
482
  join(homedir(), '.openclaw', 'extensions', '@openclaw', 'feishu'),
422
483
  join(homedir(), '.openclaw', 'extensions', 'openclaw-lark'),
423
484
  ].filter(fileExists).map((path) => `配置:${path}`).concat(
485
+ await findDesktopApps(CHANNEL_DEFINITIONS.lark).then((matches) => matches.map((path) => `桌面客户端:${path}`)),
424
486
  ['LARK_APP_ID', 'LARK_APP_SECRET', 'FEISHU_APP_ID', 'FEISHU_APP_SECRET']
425
487
  .filter((key) => Boolean(process.env[key]))
426
488
  .map((key) => `环境变量:${key}`),
@@ -435,6 +497,7 @@ async function main() {
435
497
  ],
436
498
  ['DWS_CLIENT_ID', 'DWS_CLIENT_SECRET'],
437
499
  ['dws', 'dingtalk', 'dingtalk-workspace-cli'],
500
+ { definition: CHANNEL_DEFINITIONS.dingtalk },
438
501
  );
439
502
 
440
503
  // 打印基础环境结果
@@ -22,9 +22,17 @@ export const CHANNEL_DEFINITIONS = {
22
22
  desktopAppCandidates: ['Feishu.app', 'Lark.app', '飞书.app'],
23
23
  desktopAppWindowsCandidates: [
24
24
  'Feishu.exe',
25
+ 'FeishuLauncher.exe',
26
+ 'Feishu/Feishu.exe',
27
+ 'Feishu/FeishuLauncher.exe',
25
28
  'Lark.exe',
29
+ 'LarkLauncher.exe',
30
+ 'Lark/Lark.exe',
31
+ 'Lark/LarkLauncher.exe',
26
32
  'Programs/Feishu/Feishu.exe',
33
+ 'Programs/Feishu/FeishuLauncher.exe',
27
34
  'Programs/Lark/Lark.exe',
35
+ 'Programs/Lark/LarkLauncher.exe',
28
36
  ],
29
37
  desktopAppWindowsRegistryNames: ['Feishu', 'Lark', '飞书'],
30
38
  configPaths: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codewave-openclaw-installer",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "网易智企 CodeWave OpenClaw 扩展:Skills + CLI 依赖一键安装",
5
5
  "type": "module",
6
6
  "main": "index.js",