@lark-apaas/openclaw-scripts-diagnose-cli 0.1.20 → 0.1.21-alpha.0
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/dist/index.cjs +91 -39
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,7 +52,7 @@ node_assert = __toESM(node_assert);
|
|
|
52
52
|
* it terse and parseable.
|
|
53
53
|
*/
|
|
54
54
|
function getVersion() {
|
|
55
|
-
return "0.1.
|
|
55
|
+
return "0.1.21-alpha.0";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/rule-engine/base.ts
|
|
@@ -2679,6 +2679,54 @@ const WORKSPACE_AGENT_REL = "workspace/agent";
|
|
|
2679
2679
|
/** openclaw.json 默认相对路径。 */
|
|
2680
2680
|
const DEFAULT_CONFIG_REL = `${WORKSPACE_AGENT_REL}/openclaw.json`;
|
|
2681
2681
|
//#endregion
|
|
2682
|
+
//#region src/plugin-installs-store.ts
|
|
2683
|
+
function getExternalInstallsPath(configPath) {
|
|
2684
|
+
return node_path.default.join(node_path.default.dirname(configPath), "plugins", "installs.json");
|
|
2685
|
+
}
|
|
2686
|
+
function readExternalInstallRecords(filePath) {
|
|
2687
|
+
const raw = node_fs.default.readFileSync(filePath, "utf-8");
|
|
2688
|
+
const records = asRecord(asRecord(JSON.parse(raw))?.installRecords);
|
|
2689
|
+
if (!records) throw new Error(`plugins installs file must contain object installRecords: ${filePath}`);
|
|
2690
|
+
return records;
|
|
2691
|
+
}
|
|
2692
|
+
function readExternalPayload(filePath) {
|
|
2693
|
+
const raw = node_fs.default.readFileSync(filePath, "utf-8");
|
|
2694
|
+
const payload = JSON.parse(raw);
|
|
2695
|
+
if (!asRecord(payload)) throw new Error(`plugins installs file must be an object: ${filePath}`);
|
|
2696
|
+
return payload;
|
|
2697
|
+
}
|
|
2698
|
+
function cloneRecords(records) {
|
|
2699
|
+
return JSON.parse(JSON.stringify(records));
|
|
2700
|
+
}
|
|
2701
|
+
function getPluginInstalls(configPath, config) {
|
|
2702
|
+
const externalPath = getExternalInstallsPath(configPath);
|
|
2703
|
+
if (node_fs.default.existsSync(externalPath)) return {
|
|
2704
|
+
records: readExternalInstallRecords(externalPath),
|
|
2705
|
+
externalPath,
|
|
2706
|
+
hasExternalFile: true
|
|
2707
|
+
};
|
|
2708
|
+
return {
|
|
2709
|
+
records: asRecord(asRecord(config.plugins)?.installs) ?? {},
|
|
2710
|
+
externalPath,
|
|
2711
|
+
hasExternalFile: false
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
function getPluginInstallsMap(configPath, config) {
|
|
2715
|
+
return getPluginInstalls(configPath, config).records;
|
|
2716
|
+
}
|
|
2717
|
+
function setPluginInstallsMap(configPath, config, records) {
|
|
2718
|
+
const externalPath = getExternalInstallsPath(configPath);
|
|
2719
|
+
const nextRecords = cloneRecords(records);
|
|
2720
|
+
const plugins = ensureRecord(config, "plugins");
|
|
2721
|
+
plugins.installs = cloneRecords(nextRecords);
|
|
2722
|
+
if (!node_fs.default.existsSync(externalPath)) return;
|
|
2723
|
+
const payload = readExternalPayload(externalPath);
|
|
2724
|
+
payload.installRecords = nextRecords;
|
|
2725
|
+
const tmpPath = `${externalPath}.tmp`;
|
|
2726
|
+
node_fs.default.writeFileSync(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
2727
|
+
node_fs.default.renameSync(tmpPath, externalPath);
|
|
2728
|
+
}
|
|
2729
|
+
//#endregion
|
|
2682
2730
|
//#region src/rules/miaoda-official-plugins-install-spec-unlock.ts
|
|
2683
2731
|
/**
|
|
2684
2732
|
* Official miaoda-side plugins that must track manifest — version-locked specs
|
|
@@ -2695,9 +2743,7 @@ function unlockSpec(spec) {
|
|
|
2695
2743
|
return spec.slice(0, cut);
|
|
2696
2744
|
}
|
|
2697
2745
|
/** Yield `[key, lockedSpec]` for every official-plugin install whose `spec` is locked. */
|
|
2698
|
-
function* iterLockedOfficialInstalls(
|
|
2699
|
-
const installs = getNestedMap(config, "plugins", "installs");
|
|
2700
|
-
if (!installs) return;
|
|
2746
|
+
function* iterLockedOfficialInstalls(installs) {
|
|
2701
2747
|
for (const [key, entry] of Object.entries(installs)) {
|
|
2702
2748
|
if (!OFFICIAL_EXTENSION_PLUGIN_NAMES.has(key)) continue;
|
|
2703
2749
|
const spec = asRecord(entry)?.spec;
|
|
@@ -2706,7 +2752,7 @@ function* iterLockedOfficialInstalls(config) {
|
|
|
2706
2752
|
}
|
|
2707
2753
|
let MiaodaOfficialPluginsInstallSpecUnlockRule = class MiaodaOfficialPluginsInstallSpecUnlockRule extends DiagnoseRule {
|
|
2708
2754
|
validate(ctx) {
|
|
2709
|
-
const locked = [...iterLockedOfficialInstalls(ctx.config)].map(([k]) => k);
|
|
2755
|
+
const locked = [...iterLockedOfficialInstalls(getPluginInstallsMap(ctx.configPath, ctx.config))].map(([k]) => k);
|
|
2710
2756
|
if (locked.length === 0) return { pass: true };
|
|
2711
2757
|
return {
|
|
2712
2758
|
pass: false,
|
|
@@ -2714,12 +2760,16 @@ let MiaodaOfficialPluginsInstallSpecUnlockRule = class MiaodaOfficialPluginsInst
|
|
|
2714
2760
|
};
|
|
2715
2761
|
}
|
|
2716
2762
|
repair(ctx) {
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2763
|
+
const installs = { ...getPluginInstallsMap(ctx.configPath, ctx.config) };
|
|
2764
|
+
for (const [key, spec] of iterLockedOfficialInstalls(installs)) {
|
|
2765
|
+
const entry = asRecord(installs[key]);
|
|
2766
|
+
if (!entry) continue;
|
|
2767
|
+
installs[key] = {
|
|
2768
|
+
...entry,
|
|
2769
|
+
spec: unlockSpec(spec)
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2772
|
+
setPluginInstallsMap(ctx.configPath, ctx.config, installs);
|
|
2723
2773
|
}
|
|
2724
2774
|
};
|
|
2725
2775
|
MiaodaOfficialPluginsInstallSpecUnlockRule = __decorate([Rule({
|
|
@@ -2837,11 +2887,11 @@ const OLD_PLUGIN_NAMES = Object.freeze([
|
|
|
2837
2887
|
"feishu-greeting",
|
|
2838
2888
|
"miaoda-keepalive"
|
|
2839
2889
|
]);
|
|
2840
|
-
function getPluginMaps(config) {
|
|
2890
|
+
function getPluginMaps(configPath, config) {
|
|
2841
2891
|
const rawAllow = asRecord(config.plugins)?.allow;
|
|
2842
2892
|
return {
|
|
2843
2893
|
entries: getNestedMap(config, "plugins", "entries"),
|
|
2844
|
-
installs:
|
|
2894
|
+
installs: getPluginInstallsMap(configPath, config),
|
|
2845
2895
|
allow: Array.isArray(rawAllow) ? rawAllow : void 0
|
|
2846
2896
|
};
|
|
2847
2897
|
}
|
|
@@ -2853,7 +2903,7 @@ function findResiduals({ entries, installs, allow }, extensionsDir) {
|
|
|
2853
2903
|
}
|
|
2854
2904
|
let OldMiaodaPluginsCleanupRule = class OldMiaodaPluginsCleanupRule extends DiagnoseRule {
|
|
2855
2905
|
validate(ctx) {
|
|
2856
|
-
const maps = getPluginMaps(ctx.config);
|
|
2906
|
+
const maps = getPluginMaps(ctx.configPath, ctx.config);
|
|
2857
2907
|
if (!hasNewMiaoda(maps)) return { pass: true };
|
|
2858
2908
|
const residuals = findResiduals(maps, getExtensionsDir(ctx.configPath));
|
|
2859
2909
|
if (residuals.length === 0) return { pass: true };
|
|
@@ -2863,7 +2913,7 @@ let OldMiaodaPluginsCleanupRule = class OldMiaodaPluginsCleanupRule extends Diag
|
|
|
2863
2913
|
};
|
|
2864
2914
|
}
|
|
2865
2915
|
repair(ctx) {
|
|
2866
|
-
const maps = getPluginMaps(ctx.config);
|
|
2916
|
+
const maps = getPluginMaps(ctx.configPath, ctx.config);
|
|
2867
2917
|
if (!hasNewMiaoda(maps)) return;
|
|
2868
2918
|
const extensionsDir = getExtensionsDir(ctx.configPath);
|
|
2869
2919
|
const { entries, installs, allow } = maps;
|
|
@@ -2887,6 +2937,7 @@ let OldMiaodaPluginsCleanupRule = class OldMiaodaPluginsCleanupRule extends Diag
|
|
|
2887
2937
|
console.error(`[old_miaoda_plugins_cleanup] rmSync ${target} failed: ${e.message}`);
|
|
2888
2938
|
}
|
|
2889
2939
|
}
|
|
2940
|
+
if (installs) setPluginInstallsMap(ctx.configPath, ctx.config, installs);
|
|
2890
2941
|
}
|
|
2891
2942
|
};
|
|
2892
2943
|
OldMiaodaPluginsCleanupRule = __decorate([Rule({
|
|
@@ -2929,8 +2980,7 @@ BuiltinPluginMissingRule = __decorate([Rule({
|
|
|
2929
2980
|
*/
|
|
2930
2981
|
function findOrphanedInstalls(ctx) {
|
|
2931
2982
|
const extDir = getExtensionsDir(ctx.configPath);
|
|
2932
|
-
const installs =
|
|
2933
|
-
if (!installs) return [];
|
|
2983
|
+
const installs = getPluginInstallsMap(ctx.configPath, ctx.config);
|
|
2934
2984
|
return Object.keys(installs).filter((name) => !isPluginInstalledOnDisk(extDir, name)).sort();
|
|
2935
2985
|
}
|
|
2936
2986
|
let BuiltinPluginInstallsCleanupRule = class BuiltinPluginInstallsCleanupRule extends DiagnoseRule {
|
|
@@ -2946,11 +2996,10 @@ let BuiltinPluginInstallsCleanupRule = class BuiltinPluginInstallsCleanupRule ex
|
|
|
2946
2996
|
const orphaned = findOrphanedInstalls(ctx);
|
|
2947
2997
|
if (orphaned.length === 0) return;
|
|
2948
2998
|
const orphanSet = new Set(orphaned);
|
|
2949
|
-
const
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
const rawAllow = plugins.allow;
|
|
2999
|
+
const installs = { ...getPluginInstallsMap(ctx.configPath, ctx.config) };
|
|
3000
|
+
for (const name of orphaned) delete installs[name];
|
|
3001
|
+
setPluginInstallsMap(ctx.configPath, ctx.config, installs);
|
|
3002
|
+
const rawAllow = asRecord(ctx.config.plugins)?.allow;
|
|
2954
3003
|
if (Array.isArray(rawAllow)) for (let i = rawAllow.length - 1; i >= 0; i--) {
|
|
2955
3004
|
const v = rawAllow[i];
|
|
2956
3005
|
if (typeof v === "string" && orphanSet.has(v)) rawAllow.splice(i, 1);
|
|
@@ -3301,7 +3350,7 @@ function findLegacyResiduals(ctx) {
|
|
|
3301
3350
|
if (asRecord(plugins?.entries)?.["feishu-openclaw-plugin"] != null) found.push("entries[legacy]");
|
|
3302
3351
|
const allow = plugins?.allow;
|
|
3303
3352
|
if (Array.isArray(allow) && allow.includes("feishu-openclaw-plugin")) found.push("allow[legacy]");
|
|
3304
|
-
if (asRecord(
|
|
3353
|
+
if (asRecord(getPluginInstallsMap(ctx.configPath, ctx.config)["feishu-openclaw-plugin"]) != null) found.push("installs[legacy]");
|
|
3305
3354
|
const extDir = getExtensionsDir(ctx.configPath);
|
|
3306
3355
|
for (const name of LEGACY_DIRS_TO_REMOVE) if (node_fs.default.existsSync(node_path.default.join(extDir, name))) found.push(`fs/${name}`);
|
|
3307
3356
|
return found;
|
|
@@ -3324,14 +3373,17 @@ function cleanupLegacyResiduals(ctx) {
|
|
|
3324
3373
|
if (plugins) {
|
|
3325
3374
|
const entries = asRecord(plugins.entries);
|
|
3326
3375
|
if (entries && "feishu-openclaw-plugin" in entries) delete entries[LEGACY_LARK_PLUGIN_NAME];
|
|
3327
|
-
const installs = asRecord(plugins.installs);
|
|
3328
|
-
if (installs && "feishu-openclaw-plugin" in installs) delete installs[LEGACY_LARK_PLUGIN_NAME];
|
|
3329
3376
|
const allow = plugins.allow;
|
|
3330
3377
|
if (Array.isArray(allow)) {
|
|
3331
3378
|
for (let i = allow.length - 1; i >= 0; i--) if (allow[i] === "feishu-openclaw-plugin") allow.splice(i, 1);
|
|
3332
3379
|
if (!allow.includes("openclaw-lark")) allow.push(LARK_PLUGIN_NAME);
|
|
3333
3380
|
}
|
|
3334
3381
|
}
|
|
3382
|
+
const installs = { ...getPluginInstallsMap(ctx.configPath, ctx.config) };
|
|
3383
|
+
if ("feishu-openclaw-plugin" in installs) {
|
|
3384
|
+
delete installs[LEGACY_LARK_PLUGIN_NAME];
|
|
3385
|
+
setPluginInstallsMap(ctx.configPath, ctx.config, installs);
|
|
3386
|
+
}
|
|
3335
3387
|
const extDir = getExtensionsDir(ctx.configPath);
|
|
3336
3388
|
for (const name of LEGACY_DIRS_TO_REMOVE) {
|
|
3337
3389
|
const target = node_path.default.join(extDir, name);
|
|
@@ -3752,13 +3804,13 @@ function detectInstalledLarkPlugin(ctx) {
|
|
|
3752
3804
|
const allowRaw = asRecord(ctx.config.plugins)?.allow;
|
|
3753
3805
|
const allow = Array.isArray(allowRaw) ? allowRaw.filter((e) => typeof e === "string") : [];
|
|
3754
3806
|
const extDir = getExtensionsDir(ctx.configPath);
|
|
3755
|
-
const installs =
|
|
3807
|
+
const installs = getPluginInstallsMap(ctx.configPath, ctx.config);
|
|
3756
3808
|
for (const name of [LARK_PLUGIN_NAME, ...LEGACY_SHORT_NAMES]) {
|
|
3757
3809
|
if (!allow.includes(name)) continue;
|
|
3758
3810
|
const pkgPath = node_path.default.join(extDir, name, "package.json");
|
|
3759
3811
|
if (!node_fs.default.existsSync(pkgPath)) continue;
|
|
3760
3812
|
const pkg = readPluginPackageJson(pkgPath) ?? {};
|
|
3761
|
-
const installEntry =
|
|
3813
|
+
const installEntry = asRecord(installs[name]);
|
|
3762
3814
|
return {
|
|
3763
3815
|
allowName: name,
|
|
3764
3816
|
fullName: pkg.name ?? extractScopedNameFromSpec$1(installEntry?.spec),
|
|
@@ -4324,8 +4376,7 @@ function readInstalledLarkPlugin(ctx) {
|
|
|
4324
4376
|
} catch {
|
|
4325
4377
|
pkg = {};
|
|
4326
4378
|
}
|
|
4327
|
-
const
|
|
4328
|
-
const installEntry = installs ? asRecord(installs[LARK_PLUGIN_NAME]) : void 0;
|
|
4379
|
+
const installEntry = asRecord(getPluginInstallsMap(ctx.configPath, ctx.config)[LARK_PLUGIN_NAME]);
|
|
4329
4380
|
return {
|
|
4330
4381
|
name: pkg.name ?? extractScopedNameFromSpec(installEntry?.spec),
|
|
4331
4382
|
version: pkg.version ?? (typeof installEntry?.version === "string" ? installEntry.version : void 0)
|
|
@@ -5599,12 +5650,13 @@ async function installExtension(tag, ossFileMap, opts = {}) {
|
|
|
5599
5650
|
}
|
|
5600
5651
|
const PLUGINS_TO_AUTO_ENABLE = [LARK_PLUGIN_NAME, MIAODA_PLUGIN_NAME];
|
|
5601
5652
|
/**
|
|
5602
|
-
* Merge each installed extension's installMetadata into
|
|
5603
|
-
*
|
|
5653
|
+
* Merge each installed extension's installMetadata into the plugin installs
|
|
5654
|
+
* store. Old sandboxes only have openclaw.json.plugins.installs; newer
|
|
5655
|
+
* templates also carry plugins/installs.json and keep openclaw.json as a mirror.
|
|
5604
5656
|
*
|
|
5605
5657
|
* - No openclaw.json → log + return (not an error; some install contexts don't have it yet)
|
|
5606
5658
|
* - Extension without installMetadata in manifest → skip that entry (log)
|
|
5607
|
-
* - Existing
|
|
5659
|
+
* - Existing install entries for other extensions left untouched
|
|
5608
5660
|
*
|
|
5609
5661
|
* Special-case for mem0: when openclaw-mem0-plugin is among the installed
|
|
5610
5662
|
* targets, also append it to plugins.allow (idempotent) and seed
|
|
@@ -5613,7 +5665,7 @@ const PLUGINS_TO_AUTO_ENABLE = [LARK_PLUGIN_NAME, MIAODA_PLUGIN_NAME];
|
|
|
5613
5665
|
*/
|
|
5614
5666
|
function updatePluginInstalls(configPath, installedPkgs) {
|
|
5615
5667
|
if (!node_fs.default.existsSync(configPath)) {
|
|
5616
|
-
console.error(`[install-extension] no config at ${configPath} — skip
|
|
5668
|
+
console.error(`[install-extension] no config at ${configPath} — skip plugin installs update`);
|
|
5617
5669
|
return;
|
|
5618
5670
|
}
|
|
5619
5671
|
const JSON5 = loadJSON5();
|
|
@@ -5621,8 +5673,7 @@ function updatePluginInstalls(configPath, installedPkgs) {
|
|
|
5621
5673
|
const config = JSON5.parse(raw);
|
|
5622
5674
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
5623
5675
|
const plugins = config.plugins;
|
|
5624
|
-
|
|
5625
|
-
const installs = plugins.installs;
|
|
5676
|
+
const installs = { ...getPluginInstallsMap(configPath, config) };
|
|
5626
5677
|
let updated = 0;
|
|
5627
5678
|
let skipped = 0;
|
|
5628
5679
|
for (const pkg of installedPkgs) if (pkg.installMetadata) {
|
|
@@ -5650,10 +5701,11 @@ function updatePluginInstalls(configPath, installedPkgs) {
|
|
|
5650
5701
|
enabled: true
|
|
5651
5702
|
};
|
|
5652
5703
|
}
|
|
5704
|
+
setPluginInstallsMap(configPath, config, installs);
|
|
5653
5705
|
const tmpPath = configPath + ".installs-tmp";
|
|
5654
5706
|
node_fs.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
5655
5707
|
moveSafe(tmpPath, configPath);
|
|
5656
|
-
console.error(`[install-extension]
|
|
5708
|
+
console.error(`[install-extension] plugin installs updated: ${updated} entry(ies) for ${configPath}` + (skipped > 0 ? ` (${skipped} package(s) without installMetadata skipped)` : ""));
|
|
5657
5709
|
}
|
|
5658
5710
|
function installOne$1(pkg, tarball, homeBase) {
|
|
5659
5711
|
const destDir = node_path.default.join(homeBase, pkg.installPath);
|
|
@@ -11253,7 +11305,7 @@ async function reportCliRun(opts) {
|
|
|
11253
11305
|
//#region src/help.ts
|
|
11254
11306
|
const BIN = "mclaw-diagnose";
|
|
11255
11307
|
function versionBanner() {
|
|
11256
|
-
return `v0.1.
|
|
11308
|
+
return `v0.1.21-alpha.0`;
|
|
11257
11309
|
}
|
|
11258
11310
|
const COMMANDS = [
|
|
11259
11311
|
{
|
|
@@ -11447,7 +11499,7 @@ OPTIONS
|
|
|
11447
11499
|
DESCRIPTION
|
|
11448
11500
|
Downloads + installs one or more openclaw extension tarballs
|
|
11449
11501
|
(feishu, miaoda, etc.) into <home_base>/workspace/agent/extensions/,
|
|
11450
|
-
then splices installMetadata into
|
|
11502
|
+
then splices installMetadata into the plugin installs store
|
|
11451
11503
|
unless --skip-config-update is passed.
|
|
11452
11504
|
|
|
11453
11505
|
ARGUMENTS
|
|
@@ -11459,7 +11511,7 @@ OPTIONS
|
|
|
11459
11511
|
--extension=<name> Install a specific extension (repeatable).
|
|
11460
11512
|
--home_base=<dir> Override the /home/gem base (tests).
|
|
11461
11513
|
--config_path=<p> Override the openclaw.json path (tests).
|
|
11462
|
-
--skip-config-update Leave
|
|
11514
|
+
--skip-config-update Leave plugin install records untouched.
|
|
11463
11515
|
--oss_file_map=... Pre-built OSS URL map (base64 JSON); skips innerapi.
|
|
11464
11516
|
`
|
|
11465
11517
|
},
|