@lark-apaas/openclaw-scripts-diagnose-cli 0.1.5-alpha.6 → 0.1.5-alpha.8

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 +84 -27
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -53,7 +53,7 @@ let json_diff = require("json-diff");
53
53
  * it terse and parseable.
54
54
  */
55
55
  function getVersion() {
56
- return "0.1.5-alpha.6";
56
+ return "0.1.5-alpha.8";
57
57
  }
58
58
  //#endregion
59
59
  //#region src/rule-engine/base.ts
@@ -781,12 +781,10 @@ FeishuChannelRule = __decorate([Rule({
781
781
  //#endregion
782
782
  //#region src/rules/feishu-default-account.ts
783
783
  /**
784
- * Owns the multi-agent feishu-channel migration: turns legacy v1/v2
784
+ * Owner of the multi-agent feishu channel shape: migrates legacy v1/v2
785
785
  * (top-level appId + defaultAccount/default) into v3 (`bot-<appId>` account),
786
- * preserving the user's top-level `appId` / `appSecret` verbatim. Once on
787
- * v3 this rule does not touch account values the user owns them.
788
- * Single-agent configs (no `accounts`) are out of scope — handled by
789
- * `feishu_channel`.
786
+ * detects + fixes drift on the main bot's appId/appSecret. Single-agent
787
+ * configs (no `accounts`) are out of scopehandled by `feishu_channel`.
790
788
  */
791
789
  /** Top-level `channels.feishu.*` account-policy fields migrated into the main bot. */
792
790
  const TOP_FIELDS_TO_MIGRATE = [
@@ -799,11 +797,25 @@ let FeishuDefaultAccountRule = class FeishuDefaultAccountRule extends DiagnoseRu
799
797
  validate(ctx) {
800
798
  const feishu = getNestedMap(ctx.config, "channels", "feishu");
801
799
  if (!feishu) return { pass: true };
802
- if (!asRecord(feishu.accounts)) return { pass: true };
803
- if (hasLegacyTopLevel(feishu)) return {
800
+ const accounts = asRecord(feishu.accounts);
801
+ if (!accounts) return { pass: true };
802
+ const topAppId = feishu.appId;
803
+ if (typeof topAppId === "string" && topAppId !== "") return {
804
804
  pass: false,
805
805
  message: "channels.feishu has legacy shape; needs migration to accounts.bot-<appId>"
806
806
  };
807
+ const mainBot = findMainBotAccount(ctx.config, accounts);
808
+ if (mainBot) {
809
+ const expectedAppId = ctx.vars?.feishuAppID;
810
+ if (typeof expectedAppId === "string" && expectedAppId !== "" && mainBot.acc.appId !== expectedAppId) return {
811
+ pass: false,
812
+ message: `accounts.${mainBot.accountId}.appId mismatch: got ${mainBot.acc.appId}, expected ${expectedAppId}`
813
+ };
814
+ if (!secretMatchesCanonical(mainBot.acc.appSecret)) return {
815
+ pass: false,
816
+ message: `accounts.${mainBot.accountId}.appSecret drift`
817
+ };
818
+ }
807
819
  return { pass: true };
808
820
  }
809
821
  repair(ctx) {
@@ -811,10 +823,16 @@ let FeishuDefaultAccountRule = class FeishuDefaultAccountRule extends DiagnoseRu
811
823
  if (!feishu) return;
812
824
  const accounts = asRecord(feishu.accounts);
813
825
  if (!accounts) return;
814
- if (hasLegacyTopLevel(feishu)) this.migrate(ctx, feishu, accounts, feishu.appId, feishu.appSecret);
826
+ const topAppId = feishu.appId;
827
+ if (typeof topAppId === "string" && topAppId !== "") {
828
+ this.migrate(ctx, feishu, accounts, topAppId);
829
+ return;
830
+ }
831
+ this.enforceMainBotValues(ctx, accounts);
815
832
  }
816
- migrate(ctx, feishu, accounts, topAppId, topAppSecret) {
817
- const expectedKey = `bot-${topAppId}`;
833
+ migrate(ctx, feishu, accounts, topAppId) {
834
+ const effectiveAppId = nonEmpty(ctx.vars?.feishuAppID) ?? topAppId;
835
+ const expectedKey = `bot-${effectiveAppId}`;
818
836
  const existingBot = asRecord(accounts[expectedKey]) ?? {};
819
837
  const defaultAccount = asRecord(accounts.defaultAccount) ?? {};
820
838
  const defaultAcc = asRecord(accounts.default) ?? {};
@@ -831,8 +849,8 @@ let FeishuDefaultAccountRule = class FeishuDefaultAccountRule extends DiagnoseRu
831
849
  ...topGroups
832
850
  };
833
851
  if (Object.keys(fusedGroups).length > 0) merged.groups = fusedGroups;
834
- merged.appId = topAppId;
835
- merged.appSecret = topAppSecret;
852
+ merged.appId = effectiveAppId;
853
+ merged.appSecret = DEFAULT_FEISHU_APP_SECRET;
836
854
  const chatID = ctx.vars?.teamChatID;
837
855
  if (typeof chatID === "string" && chatID !== "") {
838
856
  const existingGroups = asRecord(merged.groups) ?? {};
@@ -849,6 +867,14 @@ let FeishuDefaultAccountRule = class FeishuDefaultAccountRule extends DiagnoseRu
849
867
  for (const k of TOP_FIELDS_TO_MIGRATE) delete feishu[k];
850
868
  this.rewireBindings(ctx.config, expectedKey);
851
869
  }
870
+ enforceMainBotValues(ctx, accounts) {
871
+ const mainBot = findMainBotAccount(ctx.config, accounts);
872
+ if (!mainBot) return;
873
+ const acc = accounts[mainBot.accountId];
874
+ const expectedAppId = nonEmpty(ctx.vars?.feishuAppID);
875
+ if (expectedAppId !== void 0 && acc.appId !== expectedAppId) acc.appId = expectedAppId;
876
+ if (!secretMatchesCanonical(acc.appSecret)) acc.appSecret = DEFAULT_FEISHU_APP_SECRET;
877
+ }
852
878
  rewireBindings(config, expectedKey) {
853
879
  if (!Array.isArray(config.bindings)) return;
854
880
  const bindings = config.bindings;
@@ -894,18 +920,32 @@ FeishuDefaultAccountRule = __decorate([Rule({
894
920
  repairMode: "standard",
895
921
  usesVars: ["feishuAppID", "teamChatID"]
896
922
  })], FeishuDefaultAccountRule);
897
- /**
898
- * Legacy top-level shape only counts as "needs migration" when BOTH appId and
899
- * appSecret are present. Either one alone is treated as a partial config the
900
- * user owns; doctor leaves it untouched and won't synthesize the missing half
901
- * from defaults. `appId` must be a non-empty string (used as bot key);
902
- * `appSecret` may be a string OR a provider-ref object, so we only require
903
- * `!== undefined`.
904
- */
905
- function hasLegacyTopLevel(feishu) {
906
- const appId = feishu.appId;
907
- if (typeof appId !== "string" || appId === "") return false;
908
- return feishu.appSecret !== void 0;
923
+ function nonEmpty(v) {
924
+ return typeof v === "string" && v !== "" ? v : void 0;
925
+ }
926
+ function findMainBotAccount(config, accounts) {
927
+ const mainId = findMainAgent(config)?.id;
928
+ if (typeof mainId !== "string" || mainId === "") return void 0;
929
+ const bindings = Array.isArray(config.bindings) ? config.bindings : [];
930
+ for (const b of bindings) {
931
+ const rec = asRecord(b);
932
+ const match = asRecord(rec?.match);
933
+ if (rec && match && rec.agentId === mainId && match.channel === "feishu") {
934
+ const accountId = match.accountId;
935
+ if (typeof accountId === "string") {
936
+ const acc = asRecord(accounts[accountId]);
937
+ if (acc) return {
938
+ accountId,
939
+ acc
940
+ };
941
+ }
942
+ }
943
+ }
944
+ }
945
+ /** Bot accounts must carry the canonical provider-ref `appSecret`. */
946
+ function secretMatchesCanonical(secret) {
947
+ if (typeof secret !== "object" || secret === null || Array.isArray(secret)) return false;
948
+ return matchMap(secret, DEFAULT_FEISHU_APP_SECRET);
909
949
  }
910
950
  //#endregion
911
951
  //#region src/rules/gateway.ts
@@ -1907,6 +1947,10 @@ function findEntry(pluginVersion) {
1907
1947
  const PLUGIN_NAME = "openclaw-lark";
1908
1948
  const LEGACY_SHORT_NAMES = ["feishu-openclaw-plugin"];
1909
1949
  const FORK_SCOPES = ["@lark-apaas"];
1950
+ /** 特化 fork 版全名:虽免于 VERSION_COMPAT_MAP 检查,仍需 openclaw ≥ 此版本 */
1951
+ const FORK_LARK_PLUGIN_FULL_NAME = "@lark-apaas/openclaw-lark";
1952
+ /** 来自 VERSION_COMPAT_MAP openclawLarkVersion=2026.4.1 对应的 minOpenclawVersion */
1953
+ const FORK_LARK_PLUGIN_MIN_OC_VERSION = "2026.3.28";
1910
1954
  /**
1911
1955
  * 飞书插件 ↔ openclaw 版本兼容检测。
1912
1956
  *
@@ -1931,7 +1975,7 @@ let FeishuPluginVersionCompatRule = class FeishuPluginVersionCompatRule extends
1931
1975
  if (!ocCur) return { pass: true };
1932
1976
  const installed = detectInstalledPlugin(ctx);
1933
1977
  if (installed == null) return { pass: true };
1934
- if (isForkPlugin(installed)) return { pass: true };
1978
+ if (isForkPlugin(installed)) return validateForkPlugin(installed, ocCur, recommendedOc);
1935
1979
  const isLegacy = isLegacyPlugin(installed);
1936
1980
  if (!isLegacy && isVersionCompatible(installed, ocCur)) return { pass: true };
1937
1981
  return decideUpgrade({
@@ -1975,6 +2019,19 @@ function decideUpgrade(args) {
1975
2019
  message: `${prefix};当前 openclaw@${ocCur} 已达推荐版本,可直接升级飞书插件`
1976
2020
  };
1977
2021
  }
2022
+ /**
2023
+ * @lark-apaas/openclaw-lark 豁免 VERSION_COMPAT_MAP,但仍要求 openclaw ≥ FORK_LARK_PLUGIN_MIN_OC_VERSION。
2024
+ * 其他 @lark-apaas scope 的 fork 插件继续无条件 pass。
2025
+ */
2026
+ function validateForkPlugin(installed, ocCur, recommendedOc) {
2027
+ if (installed.fullName !== FORK_LARK_PLUGIN_FULL_NAME) return { pass: true };
2028
+ if (compareCalVer(ocCur, FORK_LARK_PLUGIN_MIN_OC_VERSION) >= 0) return { pass: true };
2029
+ return {
2030
+ pass: false,
2031
+ action: "upgrade_openclaw",
2032
+ message: `安装了 ${describePlugin(installed)}(fork 版),当前 openclaw@${ocCur} 低于最低要求 ${FORK_LARK_PLUGIN_MIN_OC_VERSION};将 openclaw 升级到 ${recommendedOc} 即可满足`
2033
+ };
2034
+ }
1978
2035
  function describePlugin(p) {
1979
2036
  return (p.fullName ?? p.allowName) + (p.version ? `@${p.version}` : "");
1980
2037
  }
@@ -4257,7 +4314,7 @@ async function reportCliRun(opts) {
4257
4314
  //#region src/help.ts
4258
4315
  const BIN = "mclaw-diagnose";
4259
4316
  function versionBanner() {
4260
- return `v0.1.5-alpha.6`;
4317
+ return `v0.1.5-alpha.8`;
4261
4318
  }
4262
4319
  const COMMANDS = [
4263
4320
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/openclaw-scripts-diagnose-cli",
3
- "version": "0.1.5-alpha.6",
3
+ "version": "0.1.5-alpha.8",
4
4
  "description": "CLI for OpenClaw config diagnose and repair with JSON5 support",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {