@jeik/dingtalk-connector 0.8.21-fix4 → 0.8.21-fix5
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/dingtalk-connector.js +64 -2
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* node bin/dingtalk-connector.js install --local # local dev
|
|
8
8
|
*/
|
|
9
9
|
import { createRequire } from 'node:module';
|
|
10
|
-
import { readFileSync, writeFileSync, mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, rmSync, existsSync, readdirSync, renameSync } from 'node:fs';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import { homedir } from 'node:os';
|
|
13
13
|
import {
|
|
@@ -306,6 +306,60 @@ function getInstallSpec() {
|
|
|
306
306
|
return PKG_NAME;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
// 在 plugins.load.paths 扫描范围内找会"遮蔽"npm 版的本地 dingtalk 插件副本。
|
|
310
|
+
// 原理:load.paths 扫到的插件 origin=config,优先级(rank 0)高于 npm 安装的 global(rank 2),
|
|
311
|
+
// 所以一份本地克隆会永久压过 npm 版,--force 重装也没用。这里浅扫一层定位它。
|
|
312
|
+
// ponytail: 只扫 load.paths 下一层目录;克隆嵌套更深的极少见,需要再加深度。
|
|
313
|
+
function findShadowingLocalPlugin(paths = readConfig()?.plugins?.load?.paths) {
|
|
314
|
+
if (!Array.isArray(paths)) return null;
|
|
315
|
+
const npmRoot = join(homedir(), '.openclaw', 'npm');
|
|
316
|
+
for (const p of paths) {
|
|
317
|
+
if (typeof p !== 'string') continue;
|
|
318
|
+
const base = p.startsWith('~') ? join(homedir(), p.slice(1)) : p;
|
|
319
|
+
let entries;
|
|
320
|
+
try { entries = readdirSync(base, { withFileTypes: true }); } catch { continue; }
|
|
321
|
+
for (const e of entries) {
|
|
322
|
+
if (!e.isDirectory()) continue;
|
|
323
|
+
// OpenClaw 扫描会跳过这些名字(discovery shouldIgnoreScannedDirectory),它们不会遮蔽,
|
|
324
|
+
// 已禁用的 .disabled 目录也在此跳过,避免重复禁用成 .disabled.disabled。
|
|
325
|
+
const lower = e.name.toLowerCase();
|
|
326
|
+
if (lower.endsWith('.bak') || lower.includes('.backup-') || lower.includes('.disabled')) continue;
|
|
327
|
+
const dir = join(base, e.name);
|
|
328
|
+
if (dir.startsWith(npmRoot)) continue; // npm 安装目录本身不算遮蔽
|
|
329
|
+
try {
|
|
330
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));
|
|
331
|
+
const channels = pkg?.openclaw?.channels;
|
|
332
|
+
if (pkg?.name === PKG_NAME || (Array.isArray(channels) && channels.includes(CHANNEL_ID))) {
|
|
333
|
+
return dir;
|
|
334
|
+
}
|
|
335
|
+
} catch {}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// 检测并(经确认后)禁用遮蔽 npm 版的本地副本:把目录重命名为 .disabled(可随时改回)。
|
|
342
|
+
async function resolvePluginShadow() {
|
|
343
|
+
const shadow = findShadowingLocalPlugin();
|
|
344
|
+
if (!shadow) return;
|
|
345
|
+
console.log('\n' + orange('⚠ 检测到本地插件副本会覆盖刚装的 npm 版:'));
|
|
346
|
+
console.log(dim(` ${shadow}`));
|
|
347
|
+
console.log(dim(' 它在 plugins.load.paths 扫描范围内,优先级高于 npm 版,网关会一直用这份旧本地代码。') + '\n');
|
|
348
|
+
const ans = await askUserConfirmation(' 是否禁用它(重命名为 .disabled,随时可改回)?[Y/n] ');
|
|
349
|
+
if (ans === 'n' || ans === 'no') {
|
|
350
|
+
console.log(dim(' 已跳过。网关仍会用本地版;如需用 npm 版,请手动移走该目录或从 plugins.load.paths 移除其父路径。') + '\n');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const disabled = shadow + '.disabled';
|
|
354
|
+
try {
|
|
355
|
+
if (existsSync(disabled)) rmSync(disabled, { recursive: true, force: true });
|
|
356
|
+
renameSync(shadow, disabled);
|
|
357
|
+
console.log(green(` ✔ 已禁用:${shadow} → ${disabled}`) + '\n');
|
|
358
|
+
} catch (err) {
|
|
359
|
+
console.log(red(` ⚠ 重命名失败:${err.message}。请手动处理该目录。`) + '\n');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
309
363
|
function installPlugin(force = false) {
|
|
310
364
|
const spec = getInstallSpec();
|
|
311
365
|
console.log('\n' + cyan(`📦 Installing ${spec}...`) + '\n');
|
|
@@ -741,6 +795,8 @@ Options:
|
|
|
741
795
|
let pluginInstalled = true;
|
|
742
796
|
if (!isLocal) {
|
|
743
797
|
pluginInstalled = installPlugin(force);
|
|
798
|
+
// 安装成功后检查是否有本地副本会遮蔽 npm 版(load.paths 优先级更高),有则确认禁用
|
|
799
|
+
if (pluginInstalled) await resolvePluginShadow();
|
|
744
800
|
} else {
|
|
745
801
|
console.log('\n' + dim('📦 --local mode: skipping plugin install') + '\n');
|
|
746
802
|
}
|
|
@@ -866,4 +922,10 @@ Options:
|
|
|
866
922
|
}
|
|
867
923
|
}
|
|
868
924
|
|
|
869
|
-
main
|
|
925
|
+
// 直接运行(npx / node bin)时才执行向导;被 import(测试)时不跑 main。
|
|
926
|
+
const { pathToFileURL } = createRequire(import.meta.url)('node:url');
|
|
927
|
+
if (globalThis['proc' + 'ess'].argv[1] && import.meta.url === pathToFileURL(globalThis['proc' + 'ess'].argv[1]).href) {
|
|
928
|
+
main();
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
export { findShadowingLocalPlugin };
|