@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.23 → 0.1.1-alpha.25

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.
Files changed (2) hide show
  1. package/dist/index.cjs +167 -6
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -877,6 +877,121 @@ SecretsRule = __decorate([Rule({
877
877
  skipWhen: ({ hasMiaoda, deps }) => !hasMiaoda || !deps.usesMiaodaSecretProvider
878
878
  })], SecretsRule);
879
879
  //#endregion
880
+ //#region src/rules/template-vars-unreplaced.ts
881
+ /**
882
+ * Placeholder format used by miaoda-openclaw-template and Go-side templateVars,
883
+ * e.g. `$$__FEISHU_APP_ID__`. Double underscores on both sides act as a natural
884
+ * boundary so split-join replacement can't accidentally overlap between keys.
885
+ */
886
+ const PLACEHOLDER_RE = /\$\$__[A-Z0-9_]+__/g;
887
+ let TemplateVarsUnreplacedRule = class TemplateVarsUnreplacedRule extends DiagnoseRule {
888
+ validate(ctx) {
889
+ const found = /* @__PURE__ */ new Set();
890
+ collectPlaceholders(ctx.config, found);
891
+ if (found.size === 0) return { pass: true };
892
+ return {
893
+ pass: false,
894
+ message: "存在未替换的模板占位符: " + [...found].sort().join(", ")
895
+ };
896
+ }
897
+ repair(ctx) {
898
+ const map = ctx.templateVars;
899
+ if (!map || Object.keys(map).length === 0) return;
900
+ replaceInPlace(ctx.config, Object.entries(map));
901
+ }
902
+ };
903
+ TemplateVarsUnreplacedRule = __decorate([Rule({
904
+ key: "template_vars_unreplaced",
905
+ dependsOn: ["config_syntax_check"],
906
+ repairMode: "standard"
907
+ })], TemplateVarsUnreplacedRule);
908
+ function collectPlaceholders(value, found) {
909
+ if (typeof value === "string") {
910
+ const matches = value.match(PLACEHOLDER_RE);
911
+ if (matches) for (const m of matches) found.add(m);
912
+ return;
913
+ }
914
+ if (Array.isArray(value)) {
915
+ for (const v of value) collectPlaceholders(v, found);
916
+ return;
917
+ }
918
+ if (value && typeof value === "object") for (const v of Object.values(value)) collectPlaceholders(v, found);
919
+ }
920
+ function replaceInPlace(value, entries) {
921
+ if (Array.isArray(value)) {
922
+ for (let i = 0; i < value.length; i++) {
923
+ const el = value[i];
924
+ if (typeof el === "string") value[i] = applyVars(el, entries);
925
+ else replaceInPlace(el, entries);
926
+ }
927
+ return;
928
+ }
929
+ if (value && typeof value === "object") {
930
+ const obj = value;
931
+ for (const key of Object.keys(obj)) {
932
+ const v = obj[key];
933
+ if (typeof v === "string") obj[key] = applyVars(v, entries);
934
+ else replaceInPlace(v, entries);
935
+ }
936
+ }
937
+ }
938
+ /** Split-join replacement — matches the algorithm in reset.ts:120 and avoids regex-escaping `$$`. */
939
+ function applyVars(str, entries) {
940
+ let out = str;
941
+ for (const [placeholder, value] of entries) {
942
+ if (!value) continue;
943
+ if (out.includes(placeholder)) out = out.split(placeholder).join(value);
944
+ }
945
+ return out;
946
+ }
947
+ //#endregion
948
+ //#region src/rules/cleanup-install-backup-dirs.ts
949
+ const DIR_PREFIX = ".openclaw-install-";
950
+ function resolveExtensionsDir(configPath) {
951
+ return node_path.default.join(node_path.default.dirname(configPath), "extensions");
952
+ }
953
+ function findLeftoverDirs(extensionsDir) {
954
+ if (!fileExists(extensionsDir)) return [];
955
+ let entries;
956
+ try {
957
+ entries = node_fs.default.readdirSync(extensionsDir, { withFileTypes: true });
958
+ } catch {
959
+ return [];
960
+ }
961
+ return entries.filter((e) => e.isDirectory() && e.name.startsWith(DIR_PREFIX)).map((e) => node_path.default.join(extensionsDir, e.name));
962
+ }
963
+ let CleanupInstallBackupDirsRule = class CleanupInstallBackupDirsRule extends DiagnoseRule {
964
+ validate(ctx) {
965
+ const configPath = ctx.config.__configPath;
966
+ if (!configPath) return { pass: true };
967
+ const dirs = findLeftoverDirs(resolveExtensionsDir(configPath));
968
+ if (dirs.length === 0) return { pass: true };
969
+ return {
970
+ pass: false,
971
+ message: `extensions 目录下发现 ${dirs.length} 个 ${DIR_PREFIX}* 脏目录需要清理`
972
+ };
973
+ }
974
+ repair(ctx) {
975
+ const configPath = ctx.config.__configPath;
976
+ if (!configPath) return;
977
+ const dirs = findLeftoverDirs(resolveExtensionsDir(configPath));
978
+ const failures = [];
979
+ for (const dir of dirs) try {
980
+ node_fs.default.rmSync(dir, {
981
+ recursive: true,
982
+ force: true
983
+ });
984
+ } catch (e) {
985
+ failures.push(`${node_path.default.basename(dir)}: ${e.message}`);
986
+ }
987
+ if (dirs.length > 0 && failures.length === dirs.length) throw new Error(`cleanup_install_backup_dirs: 全部清理失败: ${failures.join("; ")}`);
988
+ }
989
+ };
990
+ CleanupInstallBackupDirsRule = __decorate([Rule({
991
+ key: "cleanup_install_backup_dirs",
992
+ repairMode: "standard"
993
+ })], CleanupInstallBackupDirsRule);
994
+ //#endregion
880
995
  //#region src/rules/miaoda-official-plugins-install-spec-unlock.ts
881
996
  /**
882
997
  * Official miaoda-side plugins that must track manifest — version-locked specs
@@ -942,19 +1057,21 @@ const OLD_PLUGIN_NAMES = Object.freeze([
942
1057
  "miaoda-keepalive"
943
1058
  ]);
944
1059
  function getPluginMaps(config) {
1060
+ const rawAllow = asRecord(config.plugins)?.allow;
945
1061
  return {
946
1062
  entries: getNestedMap(config, "plugins", "entries"),
947
- installs: getNestedMap(config, "plugins", "installs")
1063
+ installs: getNestedMap(config, "plugins", "installs"),
1064
+ allow: Array.isArray(rawAllow) ? rawAllow : void 0
948
1065
  };
949
1066
  }
950
1067
  function getExtensionsDir(configPath) {
951
1068
  return node_path.default.join(node_path.default.dirname(configPath), "extensions");
952
1069
  }
953
- function hasNewMiaoda({ entries, installs }) {
954
- return asRecord(entries?.[NEW_MIAODA]) != null || asRecord(installs?.[NEW_MIAODA]) != null;
1070
+ function hasNewMiaoda({ entries, installs, allow }) {
1071
+ return asRecord(entries?.[NEW_MIAODA]) != null || asRecord(installs?.[NEW_MIAODA]) != null || (allow?.includes(NEW_MIAODA) ?? false);
955
1072
  }
956
- function findResiduals({ entries, installs }, extensionsDir) {
957
- return OLD_PLUGIN_NAMES.filter((name) => entries?.[name] != null || installs?.[name] != null || node_fs.default.existsSync(node_path.default.join(extensionsDir, name)));
1073
+ function findResiduals({ entries, installs, allow }, extensionsDir) {
1074
+ return OLD_PLUGIN_NAMES.filter((name) => entries?.[name] != null || installs?.[name] != null || (allow?.includes(name) ?? false) || node_fs.default.existsSync(node_path.default.join(extensionsDir, name)));
958
1075
  }
959
1076
  let OldMiaodaPluginsCleanupRule = class OldMiaodaPluginsCleanupRule extends DiagnoseRule {
960
1077
  validate(ctx) {
@@ -971,7 +1088,12 @@ let OldMiaodaPluginsCleanupRule = class OldMiaodaPluginsCleanupRule extends Diag
971
1088
  const maps = getPluginMaps(ctx.config);
972
1089
  if (!hasNewMiaoda(maps)) return;
973
1090
  const extensionsDir = getExtensionsDir(ctx.configPath);
974
- const { entries, installs } = maps;
1091
+ const { entries, installs, allow } = maps;
1092
+ const oldSet = new Set(OLD_PLUGIN_NAMES);
1093
+ if (allow) for (let i = allow.length - 1; i >= 0; i--) {
1094
+ const v = allow[i];
1095
+ if (typeof v === "string" && oldSet.has(v)) allow.splice(i, 1);
1096
+ }
975
1097
  for (const name of OLD_PLUGIN_NAMES) {
976
1098
  if (entries && name in entries) delete entries[name];
977
1099
  if (installs && name in installs) delete installs[name];
@@ -995,6 +1117,45 @@ OldMiaodaPluginsCleanupRule = __decorate([Rule({
995
1117
  repairMode: "standard"
996
1118
  })], OldMiaodaPluginsCleanupRule);
997
1119
  //#endregion
1120
+ //#region src/rules/lark-plugin-allow.ts
1121
+ const LARK_PLUGIN = "openclaw-lark";
1122
+ const LARK_PLUGIN_NAMES = [LARK_PLUGIN, "feishu-openclaw-plugin"];
1123
+ let LarkPluginAllowRule = class LarkPluginAllowRule extends DiagnoseRule {
1124
+ validate(ctx) {
1125
+ const allow = getAllow(ctx.config);
1126
+ if (LARK_PLUGIN_NAMES.some((name) => allow.includes(name))) return { pass: true };
1127
+ return {
1128
+ pass: false,
1129
+ message: `plugins.allow 缺少飞书插件 (expected one of: ${LARK_PLUGIN_NAMES.join(", ")})`
1130
+ };
1131
+ }
1132
+ repair(ctx) {
1133
+ if (ctx.config.plugins == null || typeof ctx.config.plugins !== "object" || Array.isArray(ctx.config.plugins)) {
1134
+ ctx.config.plugins = { allow: [LARK_PLUGIN] };
1135
+ return;
1136
+ }
1137
+ const pluginsMap = ctx.config.plugins;
1138
+ const rawAllow = pluginsMap.allow;
1139
+ const original = Array.isArray(rawAllow) ? rawAllow : [];
1140
+ const stringAllow = original.filter((e) => typeof e === "string");
1141
+ if (LARK_PLUGIN_NAMES.some((name) => stringAllow.includes(name))) return;
1142
+ original.push(LARK_PLUGIN);
1143
+ pluginsMap.allow = original;
1144
+ }
1145
+ };
1146
+ LarkPluginAllowRule = __decorate([Rule({
1147
+ key: "lark_plugin_allow",
1148
+ dependsOn: ["config_syntax_check"],
1149
+ repairMode: "standard"
1150
+ })], LarkPluginAllowRule);
1151
+ function getAllow(config) {
1152
+ const plugins = config.plugins;
1153
+ if (plugins == null || typeof plugins !== "object" || Array.isArray(plugins)) return [];
1154
+ const allow = plugins.allow;
1155
+ if (!Array.isArray(allow)) return [];
1156
+ return allow.filter((e) => typeof e === "string");
1157
+ }
1158
+ //#endregion
998
1159
  //#region src/check.ts
999
1160
  function runCheck(input) {
1000
1161
  const result = { failedRules: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/openclaw-scripts-diagnose-cli",
3
- "version": "0.1.1-alpha.23",
3
+ "version": "0.1.1-alpha.25",
4
4
  "description": "CLI for OpenClaw config diagnose and repair with JSON5 support",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {