@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.30 → 0.1.1-alpha.31
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 +188 -19
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -89,6 +89,17 @@ function topoSort(rules) {
|
|
|
89
89
|
//#endregion
|
|
90
90
|
//#region src/utils.ts
|
|
91
91
|
/**
|
|
92
|
+
* Canonical provider-ref for the feishu app secret. Both
|
|
93
|
+
* `feishu_default_account` (multi-agent path) and `feishu_channel`
|
|
94
|
+
* (single-agent path) use this as the source-of-truth `appSecret`
|
|
95
|
+
* value when repairing.
|
|
96
|
+
*/
|
|
97
|
+
const DEFAULT_FEISHU_APP_SECRET = {
|
|
98
|
+
source: "file",
|
|
99
|
+
provider: "miaoda-secret-provider",
|
|
100
|
+
id: "/channels_feishu_app_secret"
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
92
103
|
* Navigate nested object by keys, returning the value if it's a non-array object,
|
|
93
104
|
* or undefined otherwise.
|
|
94
105
|
*/
|
|
@@ -153,6 +164,25 @@ function setNestedValue(obj, keys, value) {
|
|
|
153
164
|
}
|
|
154
165
|
current[keys[keys.length - 1]] = value;
|
|
155
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Locate the "main" agent in `agents.list`. Preference order:
|
|
169
|
+
* 1. Explicit `default: true` entry.
|
|
170
|
+
* 2. Entry with `id === 'main'` (project naming convention).
|
|
171
|
+
* 3. First entry in the list (positional fallback).
|
|
172
|
+
* Returns `undefined` when `agents.list` is missing or empty.
|
|
173
|
+
*/
|
|
174
|
+
function findMainAgent(config) {
|
|
175
|
+
const agents = getNestedMap(config, "agents");
|
|
176
|
+
if (!agents) return void 0;
|
|
177
|
+
const list = agents.list;
|
|
178
|
+
if (!Array.isArray(list) || list.length === 0) return void 0;
|
|
179
|
+
const isObj = (a) => a != null && typeof a === "object" && !Array.isArray(a);
|
|
180
|
+
const explicit = list.find((a) => isObj(a) && a.default === true);
|
|
181
|
+
if (explicit) return explicit;
|
|
182
|
+
const namedMain = list.find((a) => isObj(a) && a.id === "main");
|
|
183
|
+
if (namedMain) return namedMain;
|
|
184
|
+
return isObj(list[0]) ? list[0] : void 0;
|
|
185
|
+
}
|
|
156
186
|
/** Analyze which miaoda providers the config references. */
|
|
157
187
|
function analyzeProviderDeps(config) {
|
|
158
188
|
const deps = {
|
|
@@ -618,16 +648,11 @@ SecretProviderRule = _SecretProviderRule = __decorate([Rule({
|
|
|
618
648
|
})], SecretProviderRule);
|
|
619
649
|
//#endregion
|
|
620
650
|
//#region src/rules/feishu-channel.ts
|
|
621
|
-
|
|
651
|
+
/**
|
|
652
|
+
* Owns `channels.feishu.enabled` + single-agent top-level appId/appSecret.
|
|
653
|
+
* Multi-agent shape (`accounts` present) belongs to `feishu_default_account`.
|
|
654
|
+
*/
|
|
622
655
|
let FeishuChannelRule = class FeishuChannelRule extends DiagnoseRule {
|
|
623
|
-
static {
|
|
624
|
-
_FeishuChannelRule = this;
|
|
625
|
-
}
|
|
626
|
-
static DEFAULT_APP_SECRET = {
|
|
627
|
-
source: "file",
|
|
628
|
-
provider: "miaoda-secret-provider",
|
|
629
|
-
id: "/channels_feishu_app_secret"
|
|
630
|
-
};
|
|
631
656
|
validate(ctx) {
|
|
632
657
|
const feishu = getNestedMap(ctx.config, "channels", "feishu");
|
|
633
658
|
if (!feishu) return {
|
|
@@ -638,16 +663,16 @@ let FeishuChannelRule = class FeishuChannelRule extends DiagnoseRule {
|
|
|
638
663
|
pass: false,
|
|
639
664
|
message: "channels.feishu.enabled mismatch: got " + feishu.enabled + ", expected true"
|
|
640
665
|
};
|
|
666
|
+
if (asRecord(feishu.accounts)) return { pass: true };
|
|
641
667
|
if (feishu.appId !== ctx.vars.feishuAppID) return {
|
|
642
668
|
pass: false,
|
|
643
|
-
message:
|
|
669
|
+
message: `channels.feishu.appId mismatch: got ${feishu.appId}, expected ${ctx.vars.feishuAppID}`
|
|
644
670
|
};
|
|
645
|
-
const expectedSecret = _FeishuChannelRule.DEFAULT_APP_SECRET;
|
|
646
671
|
const secret = feishu.appSecret;
|
|
647
672
|
if (typeof secret === "object" && secret !== null && !Array.isArray(secret)) {
|
|
648
|
-
if (!matchMap(secret,
|
|
673
|
+
if (!matchMap(secret, DEFAULT_FEISHU_APP_SECRET)) return {
|
|
649
674
|
pass: false,
|
|
650
|
-
message:
|
|
675
|
+
message: `channels.feishu.appSecret object mismatch: got ${JSON.stringify(secret)}`
|
|
651
676
|
};
|
|
652
677
|
} else if (typeof secret === "string") {
|
|
653
678
|
if (secret !== ctx.vars.feishuAppSecret) return {
|
|
@@ -666,6 +691,7 @@ let FeishuChannelRule = class FeishuChannelRule extends DiagnoseRule {
|
|
|
666
691
|
"feishu",
|
|
667
692
|
"enabled"
|
|
668
693
|
], true);
|
|
694
|
+
if (asRecord(getNestedMap(ctx.config, "channels", "feishu").accounts)) return;
|
|
669
695
|
setNestedValue(ctx.config, [
|
|
670
696
|
"channels",
|
|
671
697
|
"feishu",
|
|
@@ -675,27 +701,166 @@ let FeishuChannelRule = class FeishuChannelRule extends DiagnoseRule {
|
|
|
675
701
|
"channels",
|
|
676
702
|
"feishu",
|
|
677
703
|
"appSecret"
|
|
678
|
-
],
|
|
704
|
+
], DEFAULT_FEISHU_APP_SECRET);
|
|
679
705
|
}
|
|
680
706
|
};
|
|
681
|
-
FeishuChannelRule =
|
|
707
|
+
FeishuChannelRule = __decorate([Rule({
|
|
682
708
|
key: "feishu_channel",
|
|
683
|
-
dependsOn: ["config_syntax_check"],
|
|
709
|
+
dependsOn: ["config_syntax_check", "feishu_default_account"],
|
|
684
710
|
repairMode: "standard"
|
|
685
711
|
})], FeishuChannelRule);
|
|
686
712
|
//#endregion
|
|
687
713
|
//#region src/rules/feishu-default-account.ts
|
|
714
|
+
/**
|
|
715
|
+
* Owner of the multi-agent feishu channel shape: migrates legacy v1/v2
|
|
716
|
+
* (top-level appId + defaultAccount/default) into v3 (`bot-<appId>` account),
|
|
717
|
+
* detects + fixes drift on the main bot's appId/appSecret. Single-agent
|
|
718
|
+
* configs (no `accounts`) are out of scope — handled by `feishu_channel`.
|
|
719
|
+
*/
|
|
688
720
|
let FeishuDefaultAccountRule = class FeishuDefaultAccountRule extends DiagnoseRule {
|
|
689
|
-
validate(
|
|
721
|
+
validate(ctx) {
|
|
722
|
+
const feishu = getNestedMap(ctx.config, "channels", "feishu");
|
|
723
|
+
if (!feishu) return { pass: true };
|
|
724
|
+
const accounts = asRecord(feishu.accounts);
|
|
725
|
+
if (!accounts) return { pass: true };
|
|
726
|
+
const topAppId = feishu.appId;
|
|
727
|
+
if (typeof topAppId === "string" && topAppId !== "") return {
|
|
728
|
+
pass: false,
|
|
729
|
+
message: "channels.feishu has legacy shape; needs migration to accounts.bot-<appId>"
|
|
730
|
+
};
|
|
731
|
+
const mainBot = findMainBotAccount(ctx.config, accounts);
|
|
732
|
+
if (mainBot) {
|
|
733
|
+
const expectedAppId = ctx.vars?.feishuAppID;
|
|
734
|
+
if (typeof expectedAppId === "string" && expectedAppId !== "" && mainBot.acc.appId !== expectedAppId) return {
|
|
735
|
+
pass: false,
|
|
736
|
+
message: `accounts.${mainBot.accountId}.appId mismatch: got ${mainBot.acc.appId}, expected ${expectedAppId}`
|
|
737
|
+
};
|
|
738
|
+
if (!secretMatchesCanonical(mainBot.acc.appSecret)) return {
|
|
739
|
+
pass: false,
|
|
740
|
+
message: `accounts.${mainBot.accountId}.appSecret drift`
|
|
741
|
+
};
|
|
742
|
+
}
|
|
690
743
|
return { pass: true };
|
|
691
744
|
}
|
|
692
|
-
repair(
|
|
745
|
+
repair(ctx) {
|
|
746
|
+
const feishu = getNestedMap(ctx.config, "channels", "feishu");
|
|
747
|
+
if (!feishu) return;
|
|
748
|
+
const accounts = asRecord(feishu.accounts);
|
|
749
|
+
if (!accounts) return;
|
|
750
|
+
const topAppId = feishu.appId;
|
|
751
|
+
if (typeof topAppId === "string" && topAppId !== "") {
|
|
752
|
+
this.migrate(ctx, feishu, accounts, topAppId);
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
this.enforceMainBotValues(ctx, accounts);
|
|
756
|
+
}
|
|
757
|
+
migrate(ctx, feishu, accounts, topAppId) {
|
|
758
|
+
const effectiveAppId = nonEmpty(ctx.vars?.feishuAppID) ?? topAppId;
|
|
759
|
+
const expectedKey = `bot-${effectiveAppId}`;
|
|
760
|
+
const existingBot = asRecord(accounts[expectedKey]) ?? {};
|
|
761
|
+
const defaultAccount = asRecord(accounts.defaultAccount) ?? {};
|
|
762
|
+
const defaultAcc = asRecord(accounts.default) ?? {};
|
|
763
|
+
const merged = {
|
|
764
|
+
...existingBot,
|
|
765
|
+
...defaultAccount,
|
|
766
|
+
...defaultAcc,
|
|
767
|
+
appId: effectiveAppId,
|
|
768
|
+
appSecret: DEFAULT_FEISHU_APP_SECRET
|
|
769
|
+
};
|
|
770
|
+
const chatID = ctx.vars?.teamChatID;
|
|
771
|
+
if (typeof chatID === "string" && chatID !== "") {
|
|
772
|
+
const existingGroups = asRecord(merged.groups) ?? {};
|
|
773
|
+
if (!(chatID in existingGroups)) merged.groups = {
|
|
774
|
+
...existingGroups,
|
|
775
|
+
[chatID]: { requireMention: false }
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
accounts[expectedKey] = merged;
|
|
779
|
+
delete accounts.defaultAccount;
|
|
780
|
+
delete accounts.default;
|
|
781
|
+
delete feishu.appId;
|
|
782
|
+
delete feishu.appSecret;
|
|
783
|
+
this.rewireBindings(ctx.config, expectedKey);
|
|
784
|
+
}
|
|
785
|
+
enforceMainBotValues(ctx, accounts) {
|
|
786
|
+
const mainBot = findMainBotAccount(ctx.config, accounts);
|
|
787
|
+
if (!mainBot) return;
|
|
788
|
+
const acc = accounts[mainBot.accountId];
|
|
789
|
+
const expectedAppId = nonEmpty(ctx.vars?.feishuAppID);
|
|
790
|
+
if (expectedAppId !== void 0 && acc.appId !== expectedAppId) acc.appId = expectedAppId;
|
|
791
|
+
if (!secretMatchesCanonical(acc.appSecret)) acc.appSecret = DEFAULT_FEISHU_APP_SECRET;
|
|
792
|
+
}
|
|
793
|
+
rewireBindings(config, expectedKey) {
|
|
794
|
+
if (!Array.isArray(config.bindings)) return;
|
|
795
|
+
const bindings = config.bindings;
|
|
796
|
+
for (const b of bindings) {
|
|
797
|
+
const match = asRecord(asRecord(b)?.match);
|
|
798
|
+
if (match && match.channel === "feishu" && (match.accountId === "defaultAccount" || match.accountId === "default")) match.accountId = expectedKey;
|
|
799
|
+
}
|
|
800
|
+
const seen = /* @__PURE__ */ new Set();
|
|
801
|
+
const deduped = [];
|
|
802
|
+
for (const b of bindings) {
|
|
803
|
+
const rec = asRecord(b);
|
|
804
|
+
if (!rec) continue;
|
|
805
|
+
const match = asRecord(rec.match);
|
|
806
|
+
const key = JSON.stringify([
|
|
807
|
+
rec.agentId,
|
|
808
|
+
match?.channel,
|
|
809
|
+
match?.accountId
|
|
810
|
+
]);
|
|
811
|
+
if (seen.has(key)) continue;
|
|
812
|
+
seen.add(key);
|
|
813
|
+
deduped.push(rec);
|
|
814
|
+
}
|
|
815
|
+
const mainId = findMainAgent(config)?.id;
|
|
816
|
+
if (typeof mainId === "string" && mainId !== "") {
|
|
817
|
+
if (!deduped.some((b) => {
|
|
818
|
+
const m = asRecord(b.match);
|
|
819
|
+
return b.agentId === mainId && m?.channel === "feishu" && m?.accountId === expectedKey;
|
|
820
|
+
})) deduped.push({
|
|
821
|
+
type: "route",
|
|
822
|
+
agentId: mainId,
|
|
823
|
+
match: {
|
|
824
|
+
channel: "feishu",
|
|
825
|
+
accountId: expectedKey
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
config.bindings = deduped;
|
|
830
|
+
}
|
|
693
831
|
};
|
|
694
832
|
FeishuDefaultAccountRule = __decorate([Rule({
|
|
695
833
|
key: "feishu_default_account",
|
|
696
834
|
dependsOn: ["config_syntax_check"],
|
|
697
835
|
repairMode: "standard"
|
|
698
836
|
})], FeishuDefaultAccountRule);
|
|
837
|
+
function nonEmpty(v) {
|
|
838
|
+
return typeof v === "string" && v !== "" ? v : void 0;
|
|
839
|
+
}
|
|
840
|
+
function findMainBotAccount(config, accounts) {
|
|
841
|
+
const mainId = findMainAgent(config)?.id;
|
|
842
|
+
if (typeof mainId !== "string" || mainId === "") return void 0;
|
|
843
|
+
const bindings = Array.isArray(config.bindings) ? config.bindings : [];
|
|
844
|
+
for (const b of bindings) {
|
|
845
|
+
const rec = asRecord(b);
|
|
846
|
+
const match = asRecord(rec?.match);
|
|
847
|
+
if (rec && match && rec.agentId === mainId && match.channel === "feishu") {
|
|
848
|
+
const accountId = match.accountId;
|
|
849
|
+
if (typeof accountId === "string") {
|
|
850
|
+
const acc = asRecord(accounts[accountId]);
|
|
851
|
+
if (acc) return {
|
|
852
|
+
accountId,
|
|
853
|
+
acc
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
/** Bot accounts must carry the canonical provider-ref `appSecret`. */
|
|
860
|
+
function secretMatchesCanonical(secret) {
|
|
861
|
+
if (typeof secret !== "object" || secret === null || Array.isArray(secret)) return false;
|
|
862
|
+
return matchMap(secret, DEFAULT_FEISHU_APP_SECRET);
|
|
863
|
+
}
|
|
699
864
|
//#endregion
|
|
700
865
|
//#region src/rules/gateway.ts
|
|
701
866
|
var _GatewayRule;
|
|
@@ -2452,6 +2617,7 @@ function fillApp(src) {
|
|
|
2452
2617
|
return {
|
|
2453
2618
|
feishuAppID: src.feishuAppID ?? "",
|
|
2454
2619
|
feishuAppSecret: src.feishuAppSecret ?? "",
|
|
2620
|
+
teamChatID: typeof src.teamChatID === "string" && src.teamChatID !== "" ? src.teamChatID : void 0,
|
|
2455
2621
|
feishuOpenID: src.feishuOpenID ?? "",
|
|
2456
2622
|
openClawName: src.openClawName ?? "",
|
|
2457
2623
|
gatewayToken: src.gatewayToken ?? "",
|
|
@@ -2497,6 +2663,7 @@ function buildCheckInput(raw, configPathOverride) {
|
|
|
2497
2663
|
vars: {
|
|
2498
2664
|
feishuAppID: ctx.app.feishuAppID,
|
|
2499
2665
|
feishuAppSecret: ctx.app.feishuAppSecret,
|
|
2666
|
+
teamChatID: ctx.app.teamChatID,
|
|
2500
2667
|
innerAPIKey: ctx.app.innerAPIKey,
|
|
2501
2668
|
gatewayToken: ctx.app.gatewayToken,
|
|
2502
2669
|
baseURL: ctx.app.baseURL,
|
|
@@ -2522,6 +2689,7 @@ function buildRepairInput(raw, configPathOverride) {
|
|
|
2522
2689
|
vars: {
|
|
2523
2690
|
feishuAppID: ctx.app.feishuAppID,
|
|
2524
2691
|
feishuAppSecret: ctx.app.feishuAppSecret,
|
|
2692
|
+
teamChatID: ctx.app.teamChatID,
|
|
2525
2693
|
innerAPIKey: ctx.app.innerAPIKey,
|
|
2526
2694
|
gatewayToken: ctx.app.gatewayToken,
|
|
2527
2695
|
baseURL: ctx.app.baseURL,
|
|
@@ -2551,6 +2719,7 @@ function buildResetInput(raw, configPathOverride) {
|
|
|
2551
2719
|
vars: {
|
|
2552
2720
|
feishuAppID: ctx.app.feishuAppID,
|
|
2553
2721
|
feishuAppSecret: ctx.app.feishuAppSecret,
|
|
2722
|
+
teamChatID: ctx.app.teamChatID,
|
|
2554
2723
|
innerAPIKey: ctx.app.innerAPIKey,
|
|
2555
2724
|
gatewayToken: ctx.app.gatewayToken,
|
|
2556
2725
|
baseURL: ctx.app.baseURL,
|
|
@@ -2593,7 +2762,7 @@ async function runDoctor(rawCtx, opts) {
|
|
|
2593
2762
|
//#region src/help.ts
|
|
2594
2763
|
const BIN = "mclaw-diagnose";
|
|
2595
2764
|
function versionBanner() {
|
|
2596
|
-
return `v0.1.1-alpha.
|
|
2765
|
+
return `v0.1.1-alpha.31`;
|
|
2597
2766
|
}
|
|
2598
2767
|
const COMMANDS = [
|
|
2599
2768
|
{
|
package/package.json
CHANGED