@lark-apaas/openclaw-scripts-diagnose-cli 0.1.12 → 0.1.13-alpha.1
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 +177 -29
- 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.13-alpha.1";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/rule-engine/base.ts
|
|
@@ -3555,6 +3555,87 @@ CleanupInstallBackupDirsRule = __decorate([Rule({
|
|
|
3555
3555
|
level: "critical"
|
|
3556
3556
|
})], CleanupInstallBackupDirsRule);
|
|
3557
3557
|
//#endregion
|
|
3558
|
+
//#region src/rules/feishu-bot-channel-config.ts
|
|
3559
|
+
/**
|
|
3560
|
+
* Ensures each bot account's channel config is correct:
|
|
3561
|
+
* 1. `allowFrom` contains its own `creatorOpenID` from larkApps
|
|
3562
|
+
* 2. `appSecret` is either the canonical provider-ref or matches larkApps plaintext
|
|
3563
|
+
*/
|
|
3564
|
+
let FeishuBotChannelConfigRule = class FeishuBotChannelConfigRule extends DiagnoseRule {
|
|
3565
|
+
validate(ctx) {
|
|
3566
|
+
const larkApps = ctx.vars.larkApps;
|
|
3567
|
+
if (!larkApps || larkApps.length === 0) return { pass: true };
|
|
3568
|
+
const accounts = asRecord(getNestedMap(ctx.config, "channels", "feishu")?.accounts);
|
|
3569
|
+
if (!accounts) return { pass: true };
|
|
3570
|
+
const issues = [];
|
|
3571
|
+
for (const [accountId, account] of Object.entries(accounts)) {
|
|
3572
|
+
const bot = asRecord(account);
|
|
3573
|
+
if (!bot) continue;
|
|
3574
|
+
const appId = bot.appId;
|
|
3575
|
+
if (typeof appId !== "string" || !appId.startsWith("cli_")) continue;
|
|
3576
|
+
const larkApp = larkApps.find((e) => e.larkAppID === appId);
|
|
3577
|
+
if (!larkApp) continue;
|
|
3578
|
+
const creatorOpenID = larkApp.creatorOpenID;
|
|
3579
|
+
if (typeof creatorOpenID === "string" && creatorOpenID !== "") {
|
|
3580
|
+
if (!(Array.isArray(bot.allowFrom) ? bot.allowFrom : []).includes(creatorOpenID)) issues.push(`${accountId} allowFrom missing creatorOpenID ${creatorOpenID.length > 8 ? creatorOpenID.slice(0, 4) + "***" + creatorOpenID.slice(-4) : "***"}`);
|
|
3581
|
+
}
|
|
3582
|
+
const secret = bot.appSecret;
|
|
3583
|
+
if (typeof secret === "object" && secret !== null && !Array.isArray(secret)) {
|
|
3584
|
+
if (!matchMap(secret, DEFAULT_FEISHU_APP_SECRET)) issues.push(`${accountId} appSecret is a provider-ref but not the canonical one`);
|
|
3585
|
+
} else if (typeof secret === "string") {
|
|
3586
|
+
if (secret !== larkApp.appSecret) issues.push(`${accountId} appSecret plaintext mismatch`);
|
|
3587
|
+
} else issues.push(`${accountId} appSecret has unexpected type`);
|
|
3588
|
+
}
|
|
3589
|
+
if (issues.length === 0) return { pass: true };
|
|
3590
|
+
return {
|
|
3591
|
+
pass: false,
|
|
3592
|
+
message: issues.join("; ")
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
repair(ctx) {
|
|
3596
|
+
const larkApps = ctx.vars.larkApps;
|
|
3597
|
+
if (!larkApps || larkApps.length === 0) return;
|
|
3598
|
+
const accounts = asRecord(getNestedMap(ctx.config, "channels", "feishu")?.accounts);
|
|
3599
|
+
if (!accounts) return;
|
|
3600
|
+
for (const [, account] of Object.entries(accounts)) {
|
|
3601
|
+
const bot = asRecord(account);
|
|
3602
|
+
if (!bot) continue;
|
|
3603
|
+
const appId = bot.appId;
|
|
3604
|
+
if (typeof appId !== "string" || !appId.startsWith("cli_")) continue;
|
|
3605
|
+
const larkApp = larkApps.find((e) => e.larkAppID === appId);
|
|
3606
|
+
if (!larkApp) continue;
|
|
3607
|
+
const creatorOpenID = larkApp.creatorOpenID;
|
|
3608
|
+
if (typeof creatorOpenID === "string" && creatorOpenID !== "") {
|
|
3609
|
+
const allowFrom = Array.isArray(bot.allowFrom) ? [...bot.allowFrom] : [];
|
|
3610
|
+
if (!allowFrom.includes(creatorOpenID)) {
|
|
3611
|
+
allowFrom.push(creatorOpenID);
|
|
3612
|
+
bot.allowFrom = allowFrom;
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
const secret = bot.appSecret;
|
|
3616
|
+
let needsFix = false;
|
|
3617
|
+
if (typeof secret === "object" && secret !== null && !Array.isArray(secret)) {
|
|
3618
|
+
if (!matchMap(secret, DEFAULT_FEISHU_APP_SECRET)) needsFix = true;
|
|
3619
|
+
} else if (typeof secret === "string") {
|
|
3620
|
+
if (secret !== larkApp.appSecret) needsFix = true;
|
|
3621
|
+
} else needsFix = true;
|
|
3622
|
+
if (needsFix) bot.appSecret = { ...DEFAULT_FEISHU_APP_SECRET };
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
};
|
|
3626
|
+
FeishuBotChannelConfigRule = __decorate([Rule({
|
|
3627
|
+
key: "feishu_bot_channel_config",
|
|
3628
|
+
description: "确保多账号飞书配置中每个 bot 账号的 allowFrom 包含其创建者 openID 且 appSecret 值正确",
|
|
3629
|
+
dependsOn: [
|
|
3630
|
+
"config_syntax_check",
|
|
3631
|
+
"feishu_default_account",
|
|
3632
|
+
"feishu_bot_id"
|
|
3633
|
+
],
|
|
3634
|
+
repairMode: "standard",
|
|
3635
|
+
usesVars: ["larkApps"],
|
|
3636
|
+
level: "critical"
|
|
3637
|
+
})], FeishuBotChannelConfigRule);
|
|
3638
|
+
//#endregion
|
|
3558
3639
|
//#region src/check.ts
|
|
3559
3640
|
/** Telemetry-aware entry: returns both the legacy CheckResult (for stdout)
|
|
3560
3641
|
* AND a DoctorReport-shape payload (for `openclaw.report_cli_run`). The
|
|
@@ -4154,9 +4235,10 @@ function makeLogger(logFile) {
|
|
|
4154
4235
|
/**
|
|
4155
4236
|
* Start an async reset task: spawn a detached child process and return the taskId.
|
|
4156
4237
|
*
|
|
4157
|
-
* The child process runs: node cli.js reset --worker --task-id=xxx
|
|
4238
|
+
* The child process runs: node cli.js reset --worker --task-id=xxx
|
|
4239
|
+
* The worker fetches ctx from innerApi itself — no --ctx passthrough.
|
|
4158
4240
|
*/
|
|
4159
|
-
function startAsyncReset(
|
|
4241
|
+
function startAsyncReset() {
|
|
4160
4242
|
const taskId = (0, node_crypto.randomUUID)();
|
|
4161
4243
|
const resultFile = resetResultFile(taskId);
|
|
4162
4244
|
const log = makeLogger(resetLogFile(taskId));
|
|
@@ -4180,8 +4262,7 @@ function startAsyncReset(ctxBase64) {
|
|
|
4180
4262
|
process.argv[1],
|
|
4181
4263
|
"reset",
|
|
4182
4264
|
"--worker",
|
|
4183
|
-
`--task-id=${taskId}
|
|
4184
|
-
`--ctx=${ctxBase64}`
|
|
4265
|
+
`--task-id=${taskId}`
|
|
4185
4266
|
], {
|
|
4186
4267
|
detached: true,
|
|
4187
4268
|
stdio: "ignore",
|
|
@@ -6695,6 +6776,60 @@ function mergeCoreBackupAndOrigins(configPath, vars, resetData, log) {
|
|
|
6695
6776
|
log(`allowedOrigins: added ${added.length} (${JSON.stringify(added)}), total now ${mergedOrigins.length}`);
|
|
6696
6777
|
}
|
|
6697
6778
|
/**
|
|
6779
|
+
* Fix bot account allowFrom and appSecret using larkApps from innerApi.
|
|
6780
|
+
*
|
|
6781
|
+
* For each bot account (key starts with `bot-cli_`):
|
|
6782
|
+
* - allowFrom must contain the bot's own creatorOpenID from larkApps
|
|
6783
|
+
* - appSecret must be either the canonical provider-ref or match larkApps plaintext
|
|
6784
|
+
*
|
|
6785
|
+
* Runs after mergeCoreBackupAndOrigins so it operates on the final config state.
|
|
6786
|
+
*/
|
|
6787
|
+
function fixBotChannelConfig(configPath, larkApps, log) {
|
|
6788
|
+
if (!larkApps || larkApps.length === 0) {
|
|
6789
|
+
log("no larkApps data, skip bot channel config fix");
|
|
6790
|
+
return;
|
|
6791
|
+
}
|
|
6792
|
+
const config = loadJSON5().parse(node_fs.default.readFileSync(configPath, "utf-8"));
|
|
6793
|
+
const accounts = asRecord(getNestedMap(config, "channels", "feishu")?.accounts);
|
|
6794
|
+
if (!accounts) {
|
|
6795
|
+
log("no feishu accounts in config, skip bot channel config fix");
|
|
6796
|
+
return;
|
|
6797
|
+
}
|
|
6798
|
+
let fixCount = 0;
|
|
6799
|
+
for (const [, account] of Object.entries(accounts)) {
|
|
6800
|
+
const bot = asRecord(account);
|
|
6801
|
+
if (!bot) continue;
|
|
6802
|
+
const appId = bot.appId;
|
|
6803
|
+
if (typeof appId !== "string" || !appId.startsWith("cli_")) continue;
|
|
6804
|
+
const larkApp = larkApps.find((e) => e.larkAppID === appId);
|
|
6805
|
+
if (!larkApp) continue;
|
|
6806
|
+
const creatorOpenID = larkApp.creatorOpenID;
|
|
6807
|
+
if (typeof creatorOpenID === "string" && creatorOpenID !== "") {
|
|
6808
|
+
const allowFrom = Array.isArray(bot.allowFrom) ? [...bot.allowFrom] : [];
|
|
6809
|
+
if (!allowFrom.includes(creatorOpenID)) {
|
|
6810
|
+
allowFrom.push(creatorOpenID);
|
|
6811
|
+
bot.allowFrom = allowFrom;
|
|
6812
|
+
fixCount++;
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6815
|
+
const secret = bot.appSecret;
|
|
6816
|
+
let needsFix = false;
|
|
6817
|
+
if (typeof secret === "object" && secret !== null && !Array.isArray(secret)) {
|
|
6818
|
+
if (!matchMap(secret, DEFAULT_FEISHU_APP_SECRET)) needsFix = true;
|
|
6819
|
+
} else if (typeof secret === "string") {
|
|
6820
|
+
if (secret !== larkApp.appSecret) needsFix = true;
|
|
6821
|
+
} else needsFix = true;
|
|
6822
|
+
if (needsFix) {
|
|
6823
|
+
bot.appSecret = { ...DEFAULT_FEISHU_APP_SECRET };
|
|
6824
|
+
fixCount++;
|
|
6825
|
+
}
|
|
6826
|
+
}
|
|
6827
|
+
if (fixCount > 0) {
|
|
6828
|
+
node_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
6829
|
+
log(`fixed ${fixCount} bot channel config issue(s) (allowFrom/appSecret)`);
|
|
6830
|
+
} else log("bot channel config ok, no fixes needed");
|
|
6831
|
+
}
|
|
6832
|
+
/**
|
|
6698
6833
|
* Step 7: Verify startup scripts landed in configDir/scripts/.
|
|
6699
6834
|
*
|
|
6700
6835
|
* Scripts are extracted directly to configDir/scripts/ during stageTemplate —
|
|
@@ -6839,6 +6974,7 @@ async function runReset(input, taskId, resultFile) {
|
|
|
6839
6974
|
await step5InstallOpenclaw(openclawTag, ossFileMap, log);
|
|
6840
6975
|
step(6);
|
|
6841
6976
|
mergeCoreBackupAndOrigins(configPath, vars, resetData, log);
|
|
6977
|
+
fixBotChannelConfig(configPath, vars.larkApps, log);
|
|
6842
6978
|
step(7);
|
|
6843
6979
|
verifyStartupScripts(configDir, log);
|
|
6844
6980
|
step(8);
|
|
@@ -7637,7 +7773,8 @@ function normalizeCtx(raw) {
|
|
|
7637
7773
|
reset: {
|
|
7638
7774
|
templateVars: r.reset.templateVars ?? {},
|
|
7639
7775
|
coreBackup: r.reset.coreBackup
|
|
7640
|
-
}
|
|
7776
|
+
},
|
|
7777
|
+
larkApps: Array.isArray(r.larkApps) ? r.larkApps : []
|
|
7641
7778
|
};
|
|
7642
7779
|
}
|
|
7643
7780
|
const vars = r.vars ?? {};
|
|
@@ -7662,7 +7799,8 @@ function normalizeCtx(raw) {
|
|
|
7662
7799
|
reset: {
|
|
7663
7800
|
templateVars: resetData.templateVars ?? {},
|
|
7664
7801
|
coreBackup: resetData.coreBackup
|
|
7665
|
-
}
|
|
7802
|
+
},
|
|
7803
|
+
larkApps: Array.isArray(r.larkApps) ? r.larkApps : []
|
|
7666
7804
|
};
|
|
7667
7805
|
}
|
|
7668
7806
|
function fillApp(src) {
|
|
@@ -7727,7 +7865,8 @@ function buildCheckInput(raw, configPathOverride) {
|
|
|
7727
7865
|
providerFilePath: PROVIDER_FILE_PATH,
|
|
7728
7866
|
secretsFilePath: SECRETS_FILE_PATH,
|
|
7729
7867
|
templateVars: ctx.app.templateVars,
|
|
7730
|
-
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag
|
|
7868
|
+
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag,
|
|
7869
|
+
larkApps: ctx.larkApps
|
|
7731
7870
|
},
|
|
7732
7871
|
templateVars: ctx.app.templateVars
|
|
7733
7872
|
};
|
|
@@ -7759,7 +7898,8 @@ function buildRepairInput(raw, configPathOverride) {
|
|
|
7759
7898
|
providerFilePath: PROVIDER_FILE_PATH,
|
|
7760
7899
|
secretsFilePath: SECRETS_FILE_PATH,
|
|
7761
7900
|
templateVars: ctx.app.templateVars,
|
|
7762
|
-
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag
|
|
7901
|
+
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag,
|
|
7902
|
+
larkApps: ctx.larkApps
|
|
7763
7903
|
},
|
|
7764
7904
|
repairData: {
|
|
7765
7905
|
secretsContent: ctx.secrets.secretsContent,
|
|
@@ -7795,7 +7935,8 @@ function buildResetInput(raw, configPathOverride) {
|
|
|
7795
7935
|
providerFilePath: PROVIDER_FILE_PATH,
|
|
7796
7936
|
secretsFilePath: SECRETS_FILE_PATH,
|
|
7797
7937
|
templateVars: ctx.app.templateVars,
|
|
7798
|
-
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag
|
|
7938
|
+
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag,
|
|
7939
|
+
larkApps: ctx.larkApps
|
|
7799
7940
|
},
|
|
7800
7941
|
resetData: {
|
|
7801
7942
|
templateVars: ctx.reset.templateVars,
|
|
@@ -10105,7 +10246,7 @@ async function reportCliRun(opts) {
|
|
|
10105
10246
|
//#region src/help.ts
|
|
10106
10247
|
const BIN = "mclaw-diagnose";
|
|
10107
10248
|
function versionBanner() {
|
|
10108
|
-
return `v0.1.
|
|
10249
|
+
return `v0.1.13-alpha.1`;
|
|
10109
10250
|
}
|
|
10110
10251
|
const COMMANDS = [
|
|
10111
10252
|
{
|
|
@@ -10528,6 +10669,20 @@ function planVarsFields(opts = {}) {
|
|
|
10528
10669
|
}
|
|
10529
10670
|
return [...fields].sort();
|
|
10530
10671
|
}
|
|
10672
|
+
/** Check if any enabled rule declares a specific Vars field in usesVars. */
|
|
10673
|
+
function doesAnyRuleUseVar(field, opts = {}) {
|
|
10674
|
+
const disabled = new Set(opts.disabled ?? []);
|
|
10675
|
+
const only = opts.onlyRules && opts.onlyRules.length > 0 ? new Set(opts.onlyRules) : null;
|
|
10676
|
+
const profile = opts.profile ?? "standard";
|
|
10677
|
+
for (const rule of getAllRules()) {
|
|
10678
|
+
const key = rule.meta.key;
|
|
10679
|
+
if (disabled.has(key)) continue;
|
|
10680
|
+
if (only && !only.has(key)) continue;
|
|
10681
|
+
if (!isProfileEnabled(rule, profile)) continue;
|
|
10682
|
+
if ((rule.meta.usesVars ?? []).includes(field)) return true;
|
|
10683
|
+
}
|
|
10684
|
+
return false;
|
|
10685
|
+
}
|
|
10531
10686
|
/**
|
|
10532
10687
|
* Plan a `populate` selector for a given subcommand.
|
|
10533
10688
|
*
|
|
@@ -10552,6 +10707,11 @@ function planCtxPopulate(opts) {
|
|
|
10552
10707
|
profile: opts.profile
|
|
10553
10708
|
});
|
|
10554
10709
|
if (appFields.length > 0) populate.app = appFields;
|
|
10710
|
+
if (doesAnyRuleUseVar("larkApps", {
|
|
10711
|
+
disabled: opts.disabled,
|
|
10712
|
+
onlyRules: opts.onlyRules,
|
|
10713
|
+
profile: opts.profile
|
|
10714
|
+
})) populate.larkApps = true;
|
|
10555
10715
|
if (opts.command === "repair") populate.secrets = true;
|
|
10556
10716
|
else if (opts.command === "reset") {
|
|
10557
10717
|
populate.secrets = true;
|
|
@@ -10658,8 +10818,8 @@ function getMultiFlag(args, name) {
|
|
|
10658
10818
|
* case but is no longer consulted.
|
|
10659
10819
|
*/
|
|
10660
10820
|
async function reportRun(command, rc, _raw, invocation, durationMs, outcome, slardar = {
|
|
10661
|
-
scene,
|
|
10662
|
-
profile,
|
|
10821
|
+
scene: void 0,
|
|
10822
|
+
profile: "standard",
|
|
10663
10823
|
fix: false
|
|
10664
10824
|
}) {
|
|
10665
10825
|
console.error(`${command}: telemetry calling report_cli_run`);
|
|
@@ -10819,27 +10979,15 @@ async function main() {
|
|
|
10819
10979
|
break;
|
|
10820
10980
|
}
|
|
10821
10981
|
case "reset":
|
|
10822
|
-
if (args.includes("--async"))
|
|
10823
|
-
|
|
10824
|
-
let ctxBase64;
|
|
10825
|
-
if (ctxArg) ctxBase64 = ctxArg.slice(6);
|
|
10826
|
-
else {
|
|
10827
|
-
const fetched = await fetchCtxViaInnerApi({
|
|
10828
|
-
populate: planCtxPopulate({ command: "reset" }),
|
|
10829
|
-
caller,
|
|
10830
|
-
traceId
|
|
10831
|
-
});
|
|
10832
|
-
ctxBase64 = Buffer.from(JSON.stringify(fetched), "utf-8").toString("base64");
|
|
10833
|
-
}
|
|
10834
|
-
console.log(JSON.stringify(startAsyncReset(ctxBase64)));
|
|
10835
|
-
} else if (args.includes("--worker")) {
|
|
10982
|
+
if (args.includes("--async")) console.log(JSON.stringify(startAsyncReset()));
|
|
10983
|
+
else if (args.includes("--worker")) {
|
|
10836
10984
|
const taskId = args.find((a) => a.startsWith("--task-id="))?.slice(10);
|
|
10837
10985
|
if (!taskId) {
|
|
10838
10986
|
console.error("Error: --task-id=<id> is required for worker");
|
|
10839
10987
|
node_process.default.exit(1);
|
|
10840
10988
|
}
|
|
10841
10989
|
const resultFile = resetResultFile(taskId);
|
|
10842
|
-
const raw =
|
|
10990
|
+
const raw = await fetchCtxViaInnerApi({
|
|
10843
10991
|
populate: planCtxPopulate({ command: "reset" }),
|
|
10844
10992
|
caller,
|
|
10845
10993
|
traceId
|
|
@@ -10863,7 +11011,7 @@ async function main() {
|
|
|
10863
11011
|
return;
|
|
10864
11012
|
}
|
|
10865
11013
|
} else {
|
|
10866
|
-
console.error("Usage: reset --async
|
|
11014
|
+
console.error("Usage: reset --async | reset --worker --task-id=<id>");
|
|
10867
11015
|
node_process.default.exit(1);
|
|
10868
11016
|
}
|
|
10869
11017
|
break;
|