@lark-apaas/openclaw-scripts-diagnose-cli 0.1.21-alpha.2 → 0.1.21
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 +329 -443
- 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.21
|
|
55
|
+
return "0.1.21";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/rule-engine/base.ts
|
|
@@ -2639,11 +2639,9 @@ const LARK_PLUGIN_NAME = "openclaw-lark";
|
|
|
2639
2639
|
* 版本号自成体系、不在 VERSION_COMPAT_MAP 内,按对标的官方版本判定兼容性。
|
|
2640
2640
|
*/
|
|
2641
2641
|
const FORK_LARK_PLUGIN_FULL_NAME = "@lark-apaas/openclaw-lark";
|
|
2642
|
-
/** OpenClaw 从该版本起使用内置飞书插件作为目标态,不再安装外置 openclaw-lark。 */
|
|
2643
|
-
const BUILTIN_FEISHU_MIN_OPENCLAW_VERSION = "2026.6.6";
|
|
2644
2642
|
/**
|
|
2645
|
-
* openclaw **内置** 的 `feishu` 插件(非独立扩展)。
|
|
2646
|
-
*
|
|
2643
|
+
* 社区插件:openclaw **内置** 的 `feishu` 插件(非独立扩展)。
|
|
2644
|
+
* 与官方/ fork openclaw-lark 互斥,规范化时应禁用以让位 openclaw-lark。
|
|
2647
2645
|
*/
|
|
2648
2646
|
const BUILTIN_FEISHU_PLUGIN_NAME = "feishu";
|
|
2649
2647
|
/**
|
|
@@ -2823,282 +2821,9 @@ function getAllow$1(config) {
|
|
|
2823
2821
|
return allow.filter((e) => typeof e === "string");
|
|
2824
2822
|
}
|
|
2825
2823
|
//#endregion
|
|
2826
|
-
//#region src/version-compat.ts
|
|
2827
|
-
const VERSION_COMPAT_MAP = Object.freeze([
|
|
2828
|
-
{
|
|
2829
|
-
openclawLarkVersion: "2026.5.20",
|
|
2830
|
-
minOpenclawVersion: "2026.5.7"
|
|
2831
|
-
},
|
|
2832
|
-
{
|
|
2833
|
-
openclawLarkVersion: "2026.5.13",
|
|
2834
|
-
minOpenclawVersion: "2026.5.7"
|
|
2835
|
-
},
|
|
2836
|
-
{
|
|
2837
|
-
openclawLarkVersion: "2026.5.12",
|
|
2838
|
-
minOpenclawVersion: "2026.5.7"
|
|
2839
|
-
},
|
|
2840
|
-
{
|
|
2841
|
-
openclawLarkVersion: "2026.5.7",
|
|
2842
|
-
minOpenclawVersion: "2026.5.6"
|
|
2843
|
-
},
|
|
2844
|
-
{
|
|
2845
|
-
openclawLarkVersion: "2026.4.10",
|
|
2846
|
-
minOpenclawVersion: "2026.4.27"
|
|
2847
|
-
},
|
|
2848
|
-
{
|
|
2849
|
-
openclawLarkVersion: "2026.4.9",
|
|
2850
|
-
minOpenclawVersion: "2026.3.28"
|
|
2851
|
-
},
|
|
2852
|
-
{
|
|
2853
|
-
openclawLarkVersion: "2026.4.8",
|
|
2854
|
-
minOpenclawVersion: "2026.3.28"
|
|
2855
|
-
},
|
|
2856
|
-
{
|
|
2857
|
-
openclawLarkVersion: "2026.4.7",
|
|
2858
|
-
minOpenclawVersion: "2026.3.28"
|
|
2859
|
-
},
|
|
2860
|
-
{
|
|
2861
|
-
openclawLarkVersion: "2026.4.1",
|
|
2862
|
-
minOpenclawVersion: "2026.3.28"
|
|
2863
|
-
},
|
|
2864
|
-
{
|
|
2865
|
-
openclawLarkVersion: "2026.3.31",
|
|
2866
|
-
minOpenclawVersion: "2026.3.28"
|
|
2867
|
-
},
|
|
2868
|
-
{
|
|
2869
|
-
openclawLarkVersion: "2026.3.30",
|
|
2870
|
-
minOpenclawVersion: "2026.3.28"
|
|
2871
|
-
},
|
|
2872
|
-
{
|
|
2873
|
-
openclawLarkVersion: "2026.3.29",
|
|
2874
|
-
minOpenclawVersion: "2026.3.28"
|
|
2875
|
-
},
|
|
2876
|
-
{
|
|
2877
|
-
openclawLarkVersion: "2026.3.26",
|
|
2878
|
-
minOpenclawVersion: "2026.3.22"
|
|
2879
|
-
},
|
|
2880
|
-
{
|
|
2881
|
-
openclawLarkVersion: "2026.3.25",
|
|
2882
|
-
minOpenclawVersion: "2026.3.22"
|
|
2883
|
-
},
|
|
2884
|
-
{
|
|
2885
|
-
openclawLarkVersion: "2026.3.24",
|
|
2886
|
-
minOpenclawVersion: "2026.3.22"
|
|
2887
|
-
},
|
|
2888
|
-
{
|
|
2889
|
-
openclawLarkVersion: "2026.3.18",
|
|
2890
|
-
minOpenclawVersion: "2026.2.26",
|
|
2891
|
-
maxOpenclawVersion: "2026.3.13"
|
|
2892
|
-
},
|
|
2893
|
-
{
|
|
2894
|
-
openclawLarkVersion: "2026.3.17",
|
|
2895
|
-
minOpenclawVersion: "2026.2.26",
|
|
2896
|
-
maxOpenclawVersion: "2026.3.13"
|
|
2897
|
-
},
|
|
2898
|
-
{
|
|
2899
|
-
openclawLarkVersion: "2026.3.15",
|
|
2900
|
-
minOpenclawVersion: "2026.2.26",
|
|
2901
|
-
maxOpenclawVersion: "2026.3.13"
|
|
2902
|
-
},
|
|
2903
|
-
{
|
|
2904
|
-
openclawLarkVersion: "2026.3.12",
|
|
2905
|
-
minOpenclawVersion: "2026.2.26",
|
|
2906
|
-
maxOpenclawVersion: "2026.3.13"
|
|
2907
|
-
},
|
|
2908
|
-
{
|
|
2909
|
-
openclawLarkVersion: "2026.3.10",
|
|
2910
|
-
minOpenclawVersion: "2026.2.26",
|
|
2911
|
-
maxOpenclawVersion: "2026.3.13"
|
|
2912
|
-
},
|
|
2913
|
-
{
|
|
2914
|
-
openclawLarkVersion: "2026.3.9",
|
|
2915
|
-
minOpenclawVersion: "2026.2.26",
|
|
2916
|
-
maxOpenclawVersion: "2026.3.13"
|
|
2917
|
-
}
|
|
2918
|
-
]);
|
|
2919
|
-
/**
|
|
2920
|
-
* Coerce a CalVer string ("YYYY.M.D[suffix]") to a clean semver string.
|
|
2921
|
-
* semver.coerce strips non-numeric suffixes (e.g. "-rc.1") and fills in
|
|
2922
|
-
* missing components with 0. Returns "0.0.0" for unparseable input.
|
|
2923
|
-
*/
|
|
2924
|
-
function coerceCalVer(v) {
|
|
2925
|
-
return semver.default.coerce(v)?.version ?? "0.0.0";
|
|
2926
|
-
}
|
|
2927
|
-
/**
|
|
2928
|
-
* Compare two CalVer strings ("YYYY.M.D") numerically.
|
|
2929
|
-
* Delegates to semver for correct numeric component ordering —
|
|
2930
|
-
* plain string comparison would give wrong results (e.g. '2026.3.18' < '2026.3.9').
|
|
2931
|
-
* Suffixes like "-rc.1" are stripped via coercion before comparison.
|
|
2932
|
-
*/
|
|
2933
|
-
function compareCalVer(a, b) {
|
|
2934
|
-
return semver.default.compare(coerceCalVer(a), coerceCalVer(b));
|
|
2935
|
-
}
|
|
2936
|
-
/** Whether this OpenClaw version should use the built-in feishu plugin target state. */
|
|
2937
|
-
function supportsBuiltinFeishu(openclawVersion) {
|
|
2938
|
-
if (!openclawVersion) return false;
|
|
2939
|
-
return semver.default.gte(coerceCalVer(openclawVersion), coerceCalVer(BUILTIN_FEISHU_MIN_OPENCLAW_VERSION));
|
|
2940
|
-
}
|
|
2941
|
-
/**
|
|
2942
|
-
* 该条目的有效上界——开区间(EXCLUSIVE):openclaw ≥ 此值即不兼容。
|
|
2943
|
-
* undefined = 最高档,无上界。
|
|
2944
|
-
*
|
|
2945
|
-
* 上界一律为开区间,两种来源:
|
|
2946
|
-
* - 有显式 maxOpenclawVersion → 直接用它(它本身就是「首个不兼容的 openclaw 版本」)。
|
|
2947
|
-
* - 无显式 max → 向更高插件版本(表降序,index 更小)扫描,取首个「严格更高 min」的
|
|
2948
|
-
* minOpenclawVersion,即下一不兼容区间的起点。
|
|
2949
|
-
*
|
|
2950
|
-
* 只接受严格更高的 min(跳过相同 min 的同档;跳过更低 min 防止非单调表产生空区间
|
|
2951
|
-
* [min, max) 把本条目永久判为不兼容)。
|
|
2952
|
-
*/
|
|
2953
|
-
function inferEffectiveMax(index) {
|
|
2954
|
-
const cur = VERSION_COMPAT_MAP[index];
|
|
2955
|
-
if (cur.maxOpenclawVersion != null) return cur.maxOpenclawVersion;
|
|
2956
|
-
for (let i = index - 1; i >= 0; i--) if (compareCalVer(VERSION_COMPAT_MAP[i].minOpenclawVersion, cur.minOpenclawVersion) > 0) return VERSION_COMPAT_MAP[i].minOpenclawVersion;
|
|
2957
|
-
}
|
|
2958
|
-
/**
|
|
2959
|
-
* 单一真相源:floor 匹配 + 有效上界,得到某插件版本的半开兼容区间 [min, max)(含命中条目)。
|
|
2960
|
-
* evaluateVersionRange / findClosestEntry / effectiveCompatRange 全部基于它,
|
|
2961
|
-
* 避免 floor 匹配与 inferEffectiveMax 在多处重复。max 一律为开区间上界(EXCLUSIVE);
|
|
2962
|
-
* 最高档 max 为 undefined(无上界)。undefined = 版本比全表都旧(无 floor 条目)。
|
|
2963
|
-
*/
|
|
2964
|
-
function resolveRange(pluginVersion) {
|
|
2965
|
-
const index = VERSION_COMPAT_MAP.findIndex((e) => compareCalVer(e.openclawLarkVersion, pluginVersion) <= 0);
|
|
2966
|
-
if (index === -1) return void 0;
|
|
2967
|
-
const entry = VERSION_COMPAT_MAP[index];
|
|
2968
|
-
return {
|
|
2969
|
-
entry,
|
|
2970
|
-
min: entry.minOpenclawVersion,
|
|
2971
|
-
max: inferEffectiveMax(index)
|
|
2972
|
-
};
|
|
2973
|
-
}
|
|
2974
|
-
/**
|
|
2975
|
-
* 对一个**已对标到 VERSION_COMPAT_MAP 键**的版本评估其与 openclaw 的兼容性,
|
|
2976
|
-
* 并在不兼容时给出方向。fork 的 pin、legacy 分类等在 `checkPluginCompat` 处理,
|
|
2977
|
-
* 本函数只负责「版本 × openclaw 区间」这一段唯一逻辑。
|
|
2978
|
-
*
|
|
2979
|
-
* - index === -1(插件版本比全表都旧,无 floor 条目)→ 无区间可判,视为插件过旧 → 'lark'
|
|
2980
|
-
* - oc < entry.minOpenclawVersion → 'openclaw'
|
|
2981
|
-
* - oc ≥ 有效上界(开区间)→ 'lark'
|
|
2982
|
-
* - 否则兼容
|
|
2983
|
-
*
|
|
2984
|
-
* 区间统一为半开 [min, max):min 闭、max 开(显式与推断上界一律 EXCLUSIVE)。
|
|
2985
|
-
*/
|
|
2986
|
-
function evaluateVersionRange(pluginVersion, openclawVersion) {
|
|
2987
|
-
const r = resolveRange(pluginVersion);
|
|
2988
|
-
if (!r) return {
|
|
2989
|
-
compatible: false,
|
|
2990
|
-
direction: "lark",
|
|
2991
|
-
entry: void 0
|
|
2992
|
-
};
|
|
2993
|
-
const oc = coerceCalVer(openclawVersion);
|
|
2994
|
-
if (semver.default.lt(oc, coerceCalVer(r.min))) return {
|
|
2995
|
-
compatible: false,
|
|
2996
|
-
direction: "openclaw",
|
|
2997
|
-
entry: r.entry
|
|
2998
|
-
};
|
|
2999
|
-
if (r.max !== void 0 && semver.default.gte(oc, coerceCalVer(r.max))) return {
|
|
3000
|
-
compatible: false,
|
|
3001
|
-
direction: "lark",
|
|
3002
|
-
entry: r.entry
|
|
3003
|
-
};
|
|
3004
|
-
return {
|
|
3005
|
-
compatible: true,
|
|
3006
|
-
direction: null,
|
|
3007
|
-
entry: r.entry
|
|
3008
|
-
};
|
|
3009
|
-
}
|
|
3010
|
-
/**
|
|
3011
|
-
* Fork plugin handling.
|
|
3012
|
-
*
|
|
3013
|
-
* `@lark-apaas/openclaw-lark` is an internal fork whose own version numbers
|
|
3014
|
-
* (e.g. 2026.4.3, 2026.4.4) are NOT keys in VERSION_COMPAT_MAP. Floor-matching
|
|
3015
|
-
* a fork version against the official-keyed map only works by coincidence of
|
|
3016
|
-
* numbering and breaks once the fork version drifts past an official entry.
|
|
3017
|
-
* Both the install-time compat check and the diagnose rule must therefore pin
|
|
3018
|
-
* the fork to its official-equivalent version before consulting the map.
|
|
3019
|
-
*/
|
|
3020
|
-
/** fork 对标的官方 openclaw-lark 版本(与 VERSION_COMPAT_MAP 强耦合,故留在此处)。 */
|
|
3021
|
-
const FORK_LARK_PLUGIN_PINNED_VERSION = "2026.4.1";
|
|
3022
|
-
/**
|
|
3023
|
-
* 返回某插件版本(floor 匹配后)的有效兼容区间 [min, max),含 evaluateVersionRange 所用的
|
|
3024
|
-
* (显式或推断的)开区间上界——区别于仅暴露显式 maxOpenclawVersion 的 findClosestEntry。
|
|
3025
|
-
* undefined = 版本比全表都旧(无 floor 条目)。
|
|
3026
|
-
*/
|
|
3027
|
-
function effectiveCompatRange(pluginVersion) {
|
|
3028
|
-
const r = resolveRange(pluginVersion);
|
|
3029
|
-
return r ? {
|
|
3030
|
-
min: r.min,
|
|
3031
|
-
max: r.max
|
|
3032
|
-
} : void 0;
|
|
3033
|
-
}
|
|
3034
|
-
/** "@scope/name" → "name";无 scope 原样返回。 */
|
|
3035
|
-
function extractBaseName(name) {
|
|
3036
|
-
if (!name) return void 0;
|
|
3037
|
-
return name.startsWith("@") ? name.split("/")[1] : name;
|
|
3038
|
-
}
|
|
3039
|
-
function reasonFromRange(r) {
|
|
3040
|
-
if (r.compatible) return "compatible";
|
|
3041
|
-
if (r.direction === "openclaw") return "oc-below-min";
|
|
3042
|
-
return r.entry ? "oc-above-max" : "version-not-in-map";
|
|
3043
|
-
}
|
|
3044
|
-
/**
|
|
3045
|
-
* 统一的飞书插件兼容判定入口——唯一的判定真相源。
|
|
3046
|
-
*
|
|
3047
|
-
* 入参只有三个:插件包名、插件版本、当前 openclaw 版本(**不涉及 recommendedOpenclawTag**,
|
|
3048
|
-
* 推荐版本的处理交由各业务点)。判定算法:
|
|
3049
|
-
*
|
|
3050
|
-
* 1. fork `@lark-apaas/openclaw-lark`:先 pin 到对标官方版本(FORK_LARK_PLUGIN_PINNED_VERSION)
|
|
3051
|
-
* 再按区间判定上下界。
|
|
3052
|
-
* 2. 其他 `@lark-apaas/*` fork:无条件豁免(兼容)。
|
|
3053
|
-
* 3. legacy `feishu-openclaw-plugin`(含带 scope 形式):一律不兼容,方向 = 换飞书插件。
|
|
3054
|
-
* 4. 官方版及其余包:用自身版本按 VERSION_COMPAT_MAP 区间判定;读不到版本号 → 不兼容(换插件)。
|
|
3055
|
-
*
|
|
3056
|
-
* 所有消费方(install-extension 预检、feishu_plugin_version_compat 两条规则、needsLarkUpgrade)
|
|
3057
|
-
* 都应消费本方法,不再各自实现兼容/方向逻辑,避免口径漂移。
|
|
3058
|
-
*/
|
|
3059
|
-
function checkPluginCompat(packageName, pluginVersion, openclawVersion) {
|
|
3060
|
-
if (packageName === "@lark-apaas/openclaw-lark") {
|
|
3061
|
-
const resolvedVersion = FORK_LARK_PLUGIN_PINNED_VERSION;
|
|
3062
|
-
const r = evaluateVersionRange(resolvedVersion, openclawVersion);
|
|
3063
|
-
return {
|
|
3064
|
-
...r,
|
|
3065
|
-
reason: reasonFromRange(r),
|
|
3066
|
-
resolvedVersion
|
|
3067
|
-
};
|
|
3068
|
-
}
|
|
3069
|
-
if ((packageName && packageName.startsWith("@") ? packageName.split("/")[0] : void 0) === "@lark-apaas") return {
|
|
3070
|
-
compatible: true,
|
|
3071
|
-
direction: null,
|
|
3072
|
-
reason: "fork-exempt",
|
|
3073
|
-
resolvedVersion: pluginVersion,
|
|
3074
|
-
entry: void 0
|
|
3075
|
-
};
|
|
3076
|
-
if (extractBaseName(packageName) === "feishu-openclaw-plugin") return {
|
|
3077
|
-
compatible: false,
|
|
3078
|
-
direction: "lark",
|
|
3079
|
-
reason: "legacy",
|
|
3080
|
-
resolvedVersion: pluginVersion,
|
|
3081
|
-
entry: void 0
|
|
3082
|
-
};
|
|
3083
|
-
if (!pluginVersion) return {
|
|
3084
|
-
compatible: false,
|
|
3085
|
-
direction: "lark",
|
|
3086
|
-
reason: "version-unknown",
|
|
3087
|
-
resolvedVersion: void 0,
|
|
3088
|
-
entry: void 0
|
|
3089
|
-
};
|
|
3090
|
-
const r = evaluateVersionRange(pluginVersion, openclawVersion);
|
|
3091
|
-
return {
|
|
3092
|
-
...r,
|
|
3093
|
-
reason: reasonFromRange(r),
|
|
3094
|
-
resolvedVersion: pluginVersion
|
|
3095
|
-
};
|
|
3096
|
-
}
|
|
3097
|
-
//#endregion
|
|
3098
2824
|
//#region src/rules/lark-plugin-allow.ts
|
|
3099
2825
|
let LarkPluginAllowRule = class LarkPluginAllowRule extends DiagnoseRule {
|
|
3100
2826
|
validate(ctx) {
|
|
3101
|
-
if (supportsBuiltinFeishu(readOpenclawRuntimeVersion())) return { pass: true };
|
|
3102
2827
|
const allow = getAllow(ctx.config);
|
|
3103
2828
|
if (LARK_PLUGIN_DIR_NAMES.some((name) => allow.includes(name))) return { pass: true };
|
|
3104
2829
|
const installed = detectInstalledLarkPlugin$1(getExtensionsDir(ctx.configPath));
|
|
@@ -3226,8 +2951,7 @@ OldMiaodaPluginsCleanupRule = __decorate([Rule({
|
|
|
3226
2951
|
//#region src/rules/builtin-plugin-missing.ts
|
|
3227
2952
|
function findMissingBuiltinPlugins(ctx) {
|
|
3228
2953
|
const extDir = getExtensionsDir(ctx.configPath);
|
|
3229
|
-
|
|
3230
|
-
return [...OFFICIAL_EXTENSION_PLUGIN_NAMES].filter((name) => !(supportsBuiltin && name === "openclaw-lark")).filter((name) => !isPluginInstalledOnDisk(extDir, name)).sort();
|
|
2954
|
+
return [...OFFICIAL_EXTENSION_PLUGIN_NAMES].filter((name) => !isPluginInstalledOnDisk(extDir, name)).sort();
|
|
3231
2955
|
}
|
|
3232
2956
|
let BuiltinPluginMissingRule = class BuiltinPluginMissingRule extends DiagnoseRule {
|
|
3233
2957
|
validate(ctx) {
|
|
@@ -3242,7 +2966,7 @@ let BuiltinPluginMissingRule = class BuiltinPluginMissingRule extends DiagnoseRu
|
|
|
3242
2966
|
};
|
|
3243
2967
|
BuiltinPluginMissingRule = __decorate([Rule({
|
|
3244
2968
|
key: "builtin_plugin_missing",
|
|
3245
|
-
description: "
|
|
2969
|
+
description: "检查所有内置扩展插件(openclaw-lark、openclaw-extension-miaoda 等)是否已在磁盘安装;缺失时提示重新安装(实验性)",
|
|
3246
2970
|
dependsOn: ["config_syntax_check"],
|
|
3247
2971
|
repairMode: "check-only",
|
|
3248
2972
|
level: "critical",
|
|
@@ -3550,14 +3274,6 @@ const FEISHU_TOOLS = Object.freeze([
|
|
|
3550
3274
|
*/
|
|
3551
3275
|
let FeishuPluginStateNormalizeRule = class FeishuPluginStateNormalizeRule extends DiagnoseRule {
|
|
3552
3276
|
validate(ctx) {
|
|
3553
|
-
if (isBuiltinFeishuTarget()) {
|
|
3554
|
-
const residuals = findExternalLarkResiduals(ctx);
|
|
3555
|
-
if (residuals.length === 0) return { pass: true };
|
|
3556
|
-
return {
|
|
3557
|
-
pass: false,
|
|
3558
|
-
message: `外置飞书插件残留:${residuals.join(", ")}`
|
|
3559
|
-
};
|
|
3560
|
-
}
|
|
3561
3277
|
if (!isPluginInstalled(ctx)) return { pass: true };
|
|
3562
3278
|
const fails = [];
|
|
3563
3279
|
if (!isNewPluginEnabled(ctx.config)) fails.push(`plugins.entries["${LARK_PLUGIN_NAME}"].enabled !== true(应启用)`);
|
|
@@ -3573,10 +3289,6 @@ let FeishuPluginStateNormalizeRule = class FeishuPluginStateNormalizeRule extend
|
|
|
3573
3289
|
};
|
|
3574
3290
|
}
|
|
3575
3291
|
repair(ctx) {
|
|
3576
|
-
if (isBuiltinFeishuTarget()) {
|
|
3577
|
-
cleanupExternalLarkResiduals(ctx);
|
|
3578
|
-
return;
|
|
3579
|
-
}
|
|
3580
3292
|
setEntryEnabled(ctx.config, LARK_PLUGIN_NAME, true);
|
|
3581
3293
|
setEntryEnabled(ctx.config, BUILTIN_FEISHU_PLUGIN_NAME, false);
|
|
3582
3294
|
ensureFeishuTools(ctx.config);
|
|
@@ -3590,9 +3302,6 @@ FeishuPluginStateNormalizeRule = __decorate([Rule({
|
|
|
3590
3302
|
repairMode: "standard",
|
|
3591
3303
|
level: "critical"
|
|
3592
3304
|
})], FeishuPluginStateNormalizeRule);
|
|
3593
|
-
function isBuiltinFeishuTarget() {
|
|
3594
|
-
return supportsBuiltinFeishu(readOpenclawRuntimeVersion());
|
|
3595
|
-
}
|
|
3596
3305
|
function isPluginInstalled(ctx) {
|
|
3597
3306
|
return node_fs.default.existsSync(node_path.default.join(getExtensionsDir(ctx.configPath), LARK_PLUGIN_NAME));
|
|
3598
3307
|
}
|
|
@@ -3619,113 +3328,340 @@ function hasFeishuTool(list) {
|
|
|
3619
3328
|
* openclaw schema 禁止同一 scope 同时设 allow + alsoAllow,故有 allow 时必须并入 allow,
|
|
3620
3329
|
* 否则会触发 tools_allow_also_allow_conflict 规则反复来回改写。
|
|
3621
3330
|
*/
|
|
3622
|
-
function feishuGrantTarget(config) {
|
|
3623
|
-
return readTopLevelToolsList(config, "allow").length > 0 ? "allow" : "alsoAllow";
|
|
3331
|
+
function feishuGrantTarget(config) {
|
|
3332
|
+
return readTopLevelToolsList(config, "allow").length > 0 ? "allow" : "alsoAllow";
|
|
3333
|
+
}
|
|
3334
|
+
/**
|
|
3335
|
+
* 仅看顶层 tools——agent 级授权是用户对单 agent 的精细化配置,doctor 不动。
|
|
3336
|
+
* 返回缺失的目标键名('allow' / 'alsoAllow'),不缺时返回 null。
|
|
3337
|
+
*
|
|
3338
|
+
* 不关心 lark-cli:tools.alsoAllow(授权层)与 channels.feishu.tools.deny(插件注册层)
|
|
3339
|
+
* 是两个正交的 config key,可并存——授权一个被 deny 的工具是无害空操作。因此本规则始终
|
|
3340
|
+
* 补全 FEISHU_TOOLS(让 openclaw-lark 实际注册的工具都可用),重叠工具的"不可用"由独立的
|
|
3341
|
+
* deny 规则在注册层处理,互不干扰。
|
|
3342
|
+
*/
|
|
3343
|
+
function missingFeishuToolsGrant(config) {
|
|
3344
|
+
const target = feishuGrantTarget(config);
|
|
3345
|
+
return hasFeishuTool(readTopLevelToolsList(config, target)) ? null : target;
|
|
3346
|
+
}
|
|
3347
|
+
function findLegacyResiduals(ctx) {
|
|
3348
|
+
const found = [];
|
|
3349
|
+
const plugins = asRecord(ctx.config.plugins);
|
|
3350
|
+
if (asRecord(plugins?.entries)?.["feishu-openclaw-plugin"] != null) found.push("entries[legacy]");
|
|
3351
|
+
const allow = plugins?.allow;
|
|
3352
|
+
if (Array.isArray(allow) && allow.includes("feishu-openclaw-plugin")) found.push("allow[legacy]");
|
|
3353
|
+
if (asRecord(getPluginInstallsMap(ctx.configPath, ctx.config)["feishu-openclaw-plugin"]) != null) found.push("installs[legacy]");
|
|
3354
|
+
const extDir = getExtensionsDir(ctx.configPath);
|
|
3355
|
+
for (const name of LEGACY_DIRS_TO_REMOVE) if (node_fs.default.existsSync(node_path.default.join(extDir, name))) found.push(`fs/${name}`);
|
|
3356
|
+
return found;
|
|
3357
|
+
}
|
|
3358
|
+
function setEntryEnabled(config, key, enabled) {
|
|
3359
|
+
const entries = ensureRecord(ensureRecord(config, "plugins"), "entries");
|
|
3360
|
+
entries[key] = {
|
|
3361
|
+
...asRecord(entries[key]) ?? {},
|
|
3362
|
+
enabled
|
|
3363
|
+
};
|
|
3364
|
+
}
|
|
3365
|
+
function ensureFeishuTools(config) {
|
|
3366
|
+
const target = feishuGrantTarget(config);
|
|
3367
|
+
const current = readTopLevelToolsList(config, target);
|
|
3368
|
+
if (hasFeishuTool(current)) return;
|
|
3369
|
+
ensureRecord(config, "tools")[target] = [...new Set([...current, ...FEISHU_TOOLS])];
|
|
3370
|
+
}
|
|
3371
|
+
function cleanupLegacyResiduals(ctx) {
|
|
3372
|
+
const plugins = asRecord(ctx.config.plugins);
|
|
3373
|
+
if (plugins) {
|
|
3374
|
+
const entries = asRecord(plugins.entries);
|
|
3375
|
+
if (entries && "feishu-openclaw-plugin" in entries) delete entries[LEGACY_LARK_PLUGIN_NAME];
|
|
3376
|
+
const allow = plugins.allow;
|
|
3377
|
+
if (Array.isArray(allow)) {
|
|
3378
|
+
for (let i = allow.length - 1; i >= 0; i--) if (allow[i] === "feishu-openclaw-plugin") allow.splice(i, 1);
|
|
3379
|
+
if (!allow.includes("openclaw-lark")) allow.push(LARK_PLUGIN_NAME);
|
|
3380
|
+
}
|
|
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
|
+
}
|
|
3387
|
+
const extDir = getExtensionsDir(ctx.configPath);
|
|
3388
|
+
for (const name of LEGACY_DIRS_TO_REMOVE) {
|
|
3389
|
+
const target = node_path.default.join(extDir, name);
|
|
3390
|
+
const rel = node_path.default.relative(extDir, target);
|
|
3391
|
+
if (!rel || rel.startsWith("..") || node_path.default.isAbsolute(rel)) continue;
|
|
3392
|
+
try {
|
|
3393
|
+
rmrfTolerant(target);
|
|
3394
|
+
} catch (e) {
|
|
3395
|
+
console.error(`[feishu_plugin_state_normalize] rmrf ${target} failed: ${e.message}`);
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
//#endregion
|
|
3400
|
+
//#region src/version-compat.ts
|
|
3401
|
+
const VERSION_COMPAT_MAP = Object.freeze([
|
|
3402
|
+
{
|
|
3403
|
+
openclawLarkVersion: "2026.5.20",
|
|
3404
|
+
minOpenclawVersion: "2026.5.7"
|
|
3405
|
+
},
|
|
3406
|
+
{
|
|
3407
|
+
openclawLarkVersion: "2026.5.13",
|
|
3408
|
+
minOpenclawVersion: "2026.5.7"
|
|
3409
|
+
},
|
|
3410
|
+
{
|
|
3411
|
+
openclawLarkVersion: "2026.5.12",
|
|
3412
|
+
minOpenclawVersion: "2026.5.7"
|
|
3413
|
+
},
|
|
3414
|
+
{
|
|
3415
|
+
openclawLarkVersion: "2026.5.7",
|
|
3416
|
+
minOpenclawVersion: "2026.5.6"
|
|
3417
|
+
},
|
|
3418
|
+
{
|
|
3419
|
+
openclawLarkVersion: "2026.4.10",
|
|
3420
|
+
minOpenclawVersion: "2026.4.27"
|
|
3421
|
+
},
|
|
3422
|
+
{
|
|
3423
|
+
openclawLarkVersion: "2026.4.9",
|
|
3424
|
+
minOpenclawVersion: "2026.3.28"
|
|
3425
|
+
},
|
|
3426
|
+
{
|
|
3427
|
+
openclawLarkVersion: "2026.4.8",
|
|
3428
|
+
minOpenclawVersion: "2026.3.28"
|
|
3429
|
+
},
|
|
3430
|
+
{
|
|
3431
|
+
openclawLarkVersion: "2026.4.7",
|
|
3432
|
+
minOpenclawVersion: "2026.3.28"
|
|
3433
|
+
},
|
|
3434
|
+
{
|
|
3435
|
+
openclawLarkVersion: "2026.4.1",
|
|
3436
|
+
minOpenclawVersion: "2026.3.28"
|
|
3437
|
+
},
|
|
3438
|
+
{
|
|
3439
|
+
openclawLarkVersion: "2026.3.31",
|
|
3440
|
+
minOpenclawVersion: "2026.3.28"
|
|
3441
|
+
},
|
|
3442
|
+
{
|
|
3443
|
+
openclawLarkVersion: "2026.3.30",
|
|
3444
|
+
minOpenclawVersion: "2026.3.28"
|
|
3445
|
+
},
|
|
3446
|
+
{
|
|
3447
|
+
openclawLarkVersion: "2026.3.29",
|
|
3448
|
+
minOpenclawVersion: "2026.3.28"
|
|
3449
|
+
},
|
|
3450
|
+
{
|
|
3451
|
+
openclawLarkVersion: "2026.3.26",
|
|
3452
|
+
minOpenclawVersion: "2026.3.22"
|
|
3453
|
+
},
|
|
3454
|
+
{
|
|
3455
|
+
openclawLarkVersion: "2026.3.25",
|
|
3456
|
+
minOpenclawVersion: "2026.3.22"
|
|
3457
|
+
},
|
|
3458
|
+
{
|
|
3459
|
+
openclawLarkVersion: "2026.3.24",
|
|
3460
|
+
minOpenclawVersion: "2026.3.22"
|
|
3461
|
+
},
|
|
3462
|
+
{
|
|
3463
|
+
openclawLarkVersion: "2026.3.18",
|
|
3464
|
+
minOpenclawVersion: "2026.2.26",
|
|
3465
|
+
maxOpenclawVersion: "2026.3.13"
|
|
3466
|
+
},
|
|
3467
|
+
{
|
|
3468
|
+
openclawLarkVersion: "2026.3.17",
|
|
3469
|
+
minOpenclawVersion: "2026.2.26",
|
|
3470
|
+
maxOpenclawVersion: "2026.3.13"
|
|
3471
|
+
},
|
|
3472
|
+
{
|
|
3473
|
+
openclawLarkVersion: "2026.3.15",
|
|
3474
|
+
minOpenclawVersion: "2026.2.26",
|
|
3475
|
+
maxOpenclawVersion: "2026.3.13"
|
|
3476
|
+
},
|
|
3477
|
+
{
|
|
3478
|
+
openclawLarkVersion: "2026.3.12",
|
|
3479
|
+
minOpenclawVersion: "2026.2.26",
|
|
3480
|
+
maxOpenclawVersion: "2026.3.13"
|
|
3481
|
+
},
|
|
3482
|
+
{
|
|
3483
|
+
openclawLarkVersion: "2026.3.10",
|
|
3484
|
+
minOpenclawVersion: "2026.2.26",
|
|
3485
|
+
maxOpenclawVersion: "2026.3.13"
|
|
3486
|
+
},
|
|
3487
|
+
{
|
|
3488
|
+
openclawLarkVersion: "2026.3.9",
|
|
3489
|
+
minOpenclawVersion: "2026.2.26",
|
|
3490
|
+
maxOpenclawVersion: "2026.3.13"
|
|
3491
|
+
}
|
|
3492
|
+
]);
|
|
3493
|
+
/**
|
|
3494
|
+
* Coerce a CalVer string ("YYYY.M.D[suffix]") to a clean semver string.
|
|
3495
|
+
* semver.coerce strips non-numeric suffixes (e.g. "-rc.1") and fills in
|
|
3496
|
+
* missing components with 0. Returns "0.0.0" for unparseable input.
|
|
3497
|
+
*/
|
|
3498
|
+
function coerceCalVer(v) {
|
|
3499
|
+
return semver.default.coerce(v)?.version ?? "0.0.0";
|
|
3500
|
+
}
|
|
3501
|
+
/**
|
|
3502
|
+
* Compare two CalVer strings ("YYYY.M.D") numerically.
|
|
3503
|
+
* Delegates to semver for correct numeric component ordering —
|
|
3504
|
+
* plain string comparison would give wrong results (e.g. '2026.3.18' < '2026.3.9').
|
|
3505
|
+
* Suffixes like "-rc.1" are stripped via coercion before comparison.
|
|
3506
|
+
*/
|
|
3507
|
+
function compareCalVer(a, b) {
|
|
3508
|
+
return semver.default.compare(coerceCalVer(a), coerceCalVer(b));
|
|
3624
3509
|
}
|
|
3625
3510
|
/**
|
|
3626
|
-
*
|
|
3627
|
-
*
|
|
3511
|
+
* 该条目的有效上界——开区间(EXCLUSIVE):openclaw ≥ 此值即不兼容。
|
|
3512
|
+
* undefined = 最高档,无上界。
|
|
3628
3513
|
*
|
|
3629
|
-
*
|
|
3630
|
-
*
|
|
3631
|
-
*
|
|
3632
|
-
*
|
|
3514
|
+
* 上界一律为开区间,两种来源:
|
|
3515
|
+
* - 有显式 maxOpenclawVersion → 直接用它(它本身就是「首个不兼容的 openclaw 版本」)。
|
|
3516
|
+
* - 无显式 max → 向更高插件版本(表降序,index 更小)扫描,取首个「严格更高 min」的
|
|
3517
|
+
* minOpenclawVersion,即下一不兼容区间的起点。
|
|
3518
|
+
*
|
|
3519
|
+
* 只接受严格更高的 min(跳过相同 min 的同档;跳过更低 min 防止非单调表产生空区间
|
|
3520
|
+
* [min, max) 把本条目永久判为不兼容)。
|
|
3633
3521
|
*/
|
|
3634
|
-
function
|
|
3635
|
-
const
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
function findLegacyResiduals(ctx) {
|
|
3639
|
-
const found = [];
|
|
3640
|
-
const plugins = asRecord(ctx.config.plugins);
|
|
3641
|
-
if (asRecord(plugins?.entries)?.["feishu-openclaw-plugin"] != null) found.push("entries[legacy]");
|
|
3642
|
-
const allow = plugins?.allow;
|
|
3643
|
-
if (Array.isArray(allow) && allow.includes("feishu-openclaw-plugin")) found.push("allow[legacy]");
|
|
3644
|
-
if (asRecord(getPluginInstallsMap(ctx.configPath, ctx.config)["feishu-openclaw-plugin"]) != null) found.push("installs[legacy]");
|
|
3645
|
-
const extDir = getExtensionsDir(ctx.configPath);
|
|
3646
|
-
for (const name of LEGACY_DIRS_TO_REMOVE) if (node_fs.default.existsSync(node_path.default.join(extDir, name))) found.push(`fs/${name}`);
|
|
3647
|
-
return found;
|
|
3522
|
+
function inferEffectiveMax(index) {
|
|
3523
|
+
const cur = VERSION_COMPAT_MAP[index];
|
|
3524
|
+
if (cur.maxOpenclawVersion != null) return cur.maxOpenclawVersion;
|
|
3525
|
+
for (let i = index - 1; i >= 0; i--) if (compareCalVer(VERSION_COMPAT_MAP[i].minOpenclawVersion, cur.minOpenclawVersion) > 0) return VERSION_COMPAT_MAP[i].minOpenclawVersion;
|
|
3648
3526
|
}
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3527
|
+
/**
|
|
3528
|
+
* 单一真相源:floor 匹配 + 有效上界,得到某插件版本的半开兼容区间 [min, max)(含命中条目)。
|
|
3529
|
+
* evaluateVersionRange / findClosestEntry / effectiveCompatRange 全部基于它,
|
|
3530
|
+
* 避免 floor 匹配与 inferEffectiveMax 在多处重复。max 一律为开区间上界(EXCLUSIVE);
|
|
3531
|
+
* 最高档 max 为 undefined(无上界)。undefined = 版本比全表都旧(无 floor 条目)。
|
|
3532
|
+
*/
|
|
3533
|
+
function resolveRange(pluginVersion) {
|
|
3534
|
+
const index = VERSION_COMPAT_MAP.findIndex((e) => compareCalVer(e.openclawLarkVersion, pluginVersion) <= 0);
|
|
3535
|
+
if (index === -1) return void 0;
|
|
3536
|
+
const entry = VERSION_COMPAT_MAP[index];
|
|
3537
|
+
return {
|
|
3538
|
+
entry,
|
|
3539
|
+
min: entry.minOpenclawVersion,
|
|
3540
|
+
max: inferEffectiveMax(index)
|
|
3541
|
+
};
|
|
3662
3542
|
}
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3543
|
+
/**
|
|
3544
|
+
* 对一个**已对标到 VERSION_COMPAT_MAP 键**的版本评估其与 openclaw 的兼容性,
|
|
3545
|
+
* 并在不兼容时给出方向。fork 的 pin、legacy 分类等在 `checkPluginCompat` 处理,
|
|
3546
|
+
* 本函数只负责「版本 × openclaw 区间」这一段唯一逻辑。
|
|
3547
|
+
*
|
|
3548
|
+
* - index === -1(插件版本比全表都旧,无 floor 条目)→ 无区间可判,视为插件过旧 → 'lark'
|
|
3549
|
+
* - oc < entry.minOpenclawVersion → 'openclaw'
|
|
3550
|
+
* - oc ≥ 有效上界(开区间)→ 'lark'
|
|
3551
|
+
* - 否则兼容
|
|
3552
|
+
*
|
|
3553
|
+
* 区间统一为半开 [min, max):min 闭、max 开(显式与推断上界一律 EXCLUSIVE)。
|
|
3554
|
+
*/
|
|
3555
|
+
function evaluateVersionRange(pluginVersion, openclawVersion) {
|
|
3556
|
+
const r = resolveRange(pluginVersion);
|
|
3557
|
+
if (!r) return {
|
|
3558
|
+
compatible: false,
|
|
3559
|
+
direction: "lark",
|
|
3560
|
+
entry: void 0
|
|
3561
|
+
};
|
|
3562
|
+
const oc = coerceCalVer(openclawVersion);
|
|
3563
|
+
if (semver.default.lt(oc, coerceCalVer(r.min))) return {
|
|
3564
|
+
compatible: false,
|
|
3565
|
+
direction: "openclaw",
|
|
3566
|
+
entry: r.entry
|
|
3567
|
+
};
|
|
3568
|
+
if (r.max !== void 0 && semver.default.gte(oc, coerceCalVer(r.max))) return {
|
|
3569
|
+
compatible: false,
|
|
3570
|
+
direction: "lark",
|
|
3571
|
+
entry: r.entry
|
|
3572
|
+
};
|
|
3573
|
+
return {
|
|
3574
|
+
compatible: true,
|
|
3575
|
+
direction: null,
|
|
3576
|
+
entry: r.entry
|
|
3668
3577
|
};
|
|
3669
3578
|
}
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3579
|
+
/**
|
|
3580
|
+
* Fork plugin handling.
|
|
3581
|
+
*
|
|
3582
|
+
* `@lark-apaas/openclaw-lark` is an internal fork whose own version numbers
|
|
3583
|
+
* (e.g. 2026.4.3, 2026.4.4) are NOT keys in VERSION_COMPAT_MAP. Floor-matching
|
|
3584
|
+
* a fork version against the official-keyed map only works by coincidence of
|
|
3585
|
+
* numbering and breaks once the fork version drifts past an official entry.
|
|
3586
|
+
* Both the install-time compat check and the diagnose rule must therefore pin
|
|
3587
|
+
* the fork to its official-equivalent version before consulting the map.
|
|
3588
|
+
*/
|
|
3589
|
+
/** fork 对标的官方 openclaw-lark 版本(与 VERSION_COMPAT_MAP 强耦合,故留在此处)。 */
|
|
3590
|
+
const FORK_LARK_PLUGIN_PINNED_VERSION = "2026.4.1";
|
|
3591
|
+
/**
|
|
3592
|
+
* 返回某插件版本(floor 匹配后)的有效兼容区间 [min, max),含 evaluateVersionRange 所用的
|
|
3593
|
+
* (显式或推断的)开区间上界——区别于仅暴露显式 maxOpenclawVersion 的 findClosestEntry。
|
|
3594
|
+
* undefined = 版本比全表都旧(无 floor 条目)。
|
|
3595
|
+
*/
|
|
3596
|
+
function effectiveCompatRange(pluginVersion) {
|
|
3597
|
+
const r = resolveRange(pluginVersion);
|
|
3598
|
+
return r ? {
|
|
3599
|
+
min: r.min,
|
|
3600
|
+
max: r.max
|
|
3601
|
+
} : void 0;
|
|
3675
3602
|
}
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
if (
|
|
3679
|
-
|
|
3680
|
-
if (entries && "feishu-openclaw-plugin" in entries) delete entries[LEGACY_LARK_PLUGIN_NAME];
|
|
3681
|
-
const allow = plugins.allow;
|
|
3682
|
-
if (Array.isArray(allow)) {
|
|
3683
|
-
for (let i = allow.length - 1; i >= 0; i--) if (allow[i] === "feishu-openclaw-plugin") allow.splice(i, 1);
|
|
3684
|
-
if (!allow.includes("openclaw-lark")) allow.push(LARK_PLUGIN_NAME);
|
|
3685
|
-
}
|
|
3686
|
-
}
|
|
3687
|
-
const installs = { ...getPluginInstallsMap(ctx.configPath, ctx.config) };
|
|
3688
|
-
if ("feishu-openclaw-plugin" in installs) {
|
|
3689
|
-
delete installs[LEGACY_LARK_PLUGIN_NAME];
|
|
3690
|
-
setPluginInstallsMap(ctx.configPath, ctx.config, installs);
|
|
3691
|
-
}
|
|
3692
|
-
const extDir = getExtensionsDir(ctx.configPath);
|
|
3693
|
-
for (const name of LEGACY_DIRS_TO_REMOVE) {
|
|
3694
|
-
const target = node_path.default.join(extDir, name);
|
|
3695
|
-
const rel = node_path.default.relative(extDir, target);
|
|
3696
|
-
if (!rel || rel.startsWith("..") || node_path.default.isAbsolute(rel)) continue;
|
|
3697
|
-
try {
|
|
3698
|
-
rmrfTolerant(target);
|
|
3699
|
-
} catch (e) {
|
|
3700
|
-
console.error(`[feishu_plugin_state_normalize] rmrf ${target} failed: ${e.message}`);
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3603
|
+
/** "@scope/name" → "name";无 scope 原样返回。 */
|
|
3604
|
+
function extractBaseName(name) {
|
|
3605
|
+
if (!name) return void 0;
|
|
3606
|
+
return name.startsWith("@") ? name.split("/")[1] : name;
|
|
3703
3607
|
}
|
|
3704
|
-
function
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3608
|
+
function reasonFromRange(r) {
|
|
3609
|
+
if (r.compatible) return "compatible";
|
|
3610
|
+
if (r.direction === "openclaw") return "oc-below-min";
|
|
3611
|
+
return r.entry ? "oc-above-max" : "version-not-in-map";
|
|
3612
|
+
}
|
|
3613
|
+
/**
|
|
3614
|
+
* 统一的飞书插件兼容判定入口——唯一的判定真相源。
|
|
3615
|
+
*
|
|
3616
|
+
* 入参只有三个:插件包名、插件版本、当前 openclaw 版本(**不涉及 recommendedOpenclawTag**,
|
|
3617
|
+
* 推荐版本的处理交由各业务点)。判定算法:
|
|
3618
|
+
*
|
|
3619
|
+
* 1. fork `@lark-apaas/openclaw-lark`:先 pin 到对标官方版本(FORK_LARK_PLUGIN_PINNED_VERSION)
|
|
3620
|
+
* 再按区间判定上下界。
|
|
3621
|
+
* 2. 其他 `@lark-apaas/*` fork:无条件豁免(兼容)。
|
|
3622
|
+
* 3. legacy `feishu-openclaw-plugin`(含带 scope 形式):一律不兼容,方向 = 换飞书插件。
|
|
3623
|
+
* 4. 官方版及其余包:用自身版本按 VERSION_COMPAT_MAP 区间判定;读不到版本号 → 不兼容(换插件)。
|
|
3624
|
+
*
|
|
3625
|
+
* 所有消费方(install-extension 预检、feishu_plugin_version_compat 两条规则、needsLarkUpgrade)
|
|
3626
|
+
* 都应消费本方法,不再各自实现兼容/方向逻辑,避免口径漂移。
|
|
3627
|
+
*/
|
|
3628
|
+
function checkPluginCompat(packageName, pluginVersion, openclawVersion) {
|
|
3629
|
+
if (packageName === "@lark-apaas/openclaw-lark") {
|
|
3630
|
+
const resolvedVersion = FORK_LARK_PLUGIN_PINNED_VERSION;
|
|
3631
|
+
const r = evaluateVersionRange(resolvedVersion, openclawVersion);
|
|
3632
|
+
return {
|
|
3633
|
+
...r,
|
|
3634
|
+
reason: reasonFromRange(r),
|
|
3635
|
+
resolvedVersion
|
|
3636
|
+
};
|
|
3728
3637
|
}
|
|
3638
|
+
if ((packageName && packageName.startsWith("@") ? packageName.split("/")[0] : void 0) === "@lark-apaas") return {
|
|
3639
|
+
compatible: true,
|
|
3640
|
+
direction: null,
|
|
3641
|
+
reason: "fork-exempt",
|
|
3642
|
+
resolvedVersion: pluginVersion,
|
|
3643
|
+
entry: void 0
|
|
3644
|
+
};
|
|
3645
|
+
if (extractBaseName(packageName) === "feishu-openclaw-plugin") return {
|
|
3646
|
+
compatible: false,
|
|
3647
|
+
direction: "lark",
|
|
3648
|
+
reason: "legacy",
|
|
3649
|
+
resolvedVersion: pluginVersion,
|
|
3650
|
+
entry: void 0
|
|
3651
|
+
};
|
|
3652
|
+
if (!pluginVersion) return {
|
|
3653
|
+
compatible: false,
|
|
3654
|
+
direction: "lark",
|
|
3655
|
+
reason: "version-unknown",
|
|
3656
|
+
resolvedVersion: void 0,
|
|
3657
|
+
entry: void 0
|
|
3658
|
+
};
|
|
3659
|
+
const r = evaluateVersionRange(pluginVersion, openclawVersion);
|
|
3660
|
+
return {
|
|
3661
|
+
...r,
|
|
3662
|
+
reason: reasonFromRange(r),
|
|
3663
|
+
resolvedVersion: pluginVersion
|
|
3664
|
+
};
|
|
3729
3665
|
}
|
|
3730
3666
|
//#endregion
|
|
3731
3667
|
//#region src/rules/feishu-plugin-version-compat.ts
|
|
@@ -5674,21 +5610,6 @@ async function installExtension(tag, ossFileMap, opts = {}) {
|
|
|
5674
5610
|
}
|
|
5675
5611
|
console.error(`[install-extension] tag=${tag} targets=${targets.length}`);
|
|
5676
5612
|
const t0 = Date.now();
|
|
5677
|
-
const targetOpenclawVersion = resolveInstallTargetOpenclawVersion(tag);
|
|
5678
|
-
if (supportsBuiltinFeishu(targetOpenclawVersion) && targets.some((p) => p.name === "openclaw-lark")) {
|
|
5679
|
-
const configPath = opts.configPath ?? node_path.default.join(homeBase, DEFAULT_CONFIG_REL);
|
|
5680
|
-
console.error(`[install-extension] openclaw@${targetOpenclawVersion} uses built-in feishu — skipping external ${LARK_PLUGIN_NAME}`);
|
|
5681
|
-
cleanupExternalLarkForBuiltinFeishu({
|
|
5682
|
-
homeBase,
|
|
5683
|
-
configPath,
|
|
5684
|
-
updateConfig: !opts.skipConfigUpdate
|
|
5685
|
-
});
|
|
5686
|
-
targets = targets.filter((p) => p.name !== LARK_PLUGIN_NAME);
|
|
5687
|
-
if (targets.length === 0) {
|
|
5688
|
-
console.error(`[install-extension] done in ${Date.now() - t0}ms`);
|
|
5689
|
-
return;
|
|
5690
|
-
}
|
|
5691
|
-
}
|
|
5692
5613
|
const larkTarget = opts.skipConfigUpdate ? void 0 : targets.find((p) => p.name === LARK_PLUGIN_NAME);
|
|
5693
5614
|
if (larkTarget) {
|
|
5694
5615
|
if (await installLarkPluginWithCompatCheck({
|
|
@@ -5816,41 +5737,6 @@ function installOne$1(pkg, tarball, homeBase) {
|
|
|
5816
5737
|
force: true
|
|
5817
5738
|
});
|
|
5818
5739
|
}
|
|
5819
|
-
function resolveInstallTargetOpenclawVersion(tag) {
|
|
5820
|
-
return tag.match(/\d+\.\d+\.\d+/)?.[0] ?? readOpenclawRuntimeVersion();
|
|
5821
|
-
}
|
|
5822
|
-
function cleanupExternalLarkForBuiltinFeishu(opts) {
|
|
5823
|
-
const externalNames = new Set([LARK_PLUGIN_NAME, LEGACY_LARK_PLUGIN_NAME]);
|
|
5824
|
-
const extDir = node_path.default.join(opts.homeBase, "workspace", "agent", "extensions");
|
|
5825
|
-
for (const name of externalNames) {
|
|
5826
|
-
const target = node_path.default.join(extDir, name);
|
|
5827
|
-
try {
|
|
5828
|
-
node_fs.default.rmSync(target, {
|
|
5829
|
-
recursive: true,
|
|
5830
|
-
force: true
|
|
5831
|
-
});
|
|
5832
|
-
} catch (e) {
|
|
5833
|
-
console.error(`[install-extension] WARN: failed to remove ${target}: ${e.message}`);
|
|
5834
|
-
}
|
|
5835
|
-
}
|
|
5836
|
-
if (!opts.updateConfig || !node_fs.default.existsSync(opts.configPath)) return;
|
|
5837
|
-
const config = loadJSON5().parse(node_fs.default.readFileSync(opts.configPath, "utf-8"));
|
|
5838
|
-
const plugins = asRecord(config.plugins);
|
|
5839
|
-
if (plugins) {
|
|
5840
|
-
const allow = plugins.allow;
|
|
5841
|
-
if (Array.isArray(allow)) {
|
|
5842
|
-
for (let i = allow.length - 1; i >= 0; i--) if (externalNames.has(String(allow[i]))) allow.splice(i, 1);
|
|
5843
|
-
}
|
|
5844
|
-
const entries = asRecord(plugins.entries);
|
|
5845
|
-
if (entries) for (const name of externalNames) delete entries[name];
|
|
5846
|
-
}
|
|
5847
|
-
const installs = { ...getPluginInstallsMap(opts.configPath, config) };
|
|
5848
|
-
for (const name of externalNames) delete installs[name];
|
|
5849
|
-
setPluginInstallsMap(opts.configPath, config, installs);
|
|
5850
|
-
const tmpPath = opts.configPath + ".builtin-feishu-tmp";
|
|
5851
|
-
node_fs.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
5852
|
-
moveSafe(tmpPath, opts.configPath);
|
|
5853
|
-
}
|
|
5854
5740
|
/**
|
|
5855
5741
|
* Install openclaw-lark with a pre-flight compatibility check.
|
|
5856
5742
|
*
|
|
@@ -11419,7 +11305,7 @@ async function reportCliRun(opts) {
|
|
|
11419
11305
|
//#region src/help.ts
|
|
11420
11306
|
const BIN = "mclaw-diagnose";
|
|
11421
11307
|
function versionBanner() {
|
|
11422
|
-
return `v0.1.21
|
|
11308
|
+
return `v0.1.21`;
|
|
11423
11309
|
}
|
|
11424
11310
|
const COMMANDS = [
|
|
11425
11311
|
{
|