@lark-apaas/openclaw-scripts-diagnose-cli 0.1.12-beta.0 → 0.1.13-alpha.0
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 +176 -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.0";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/rule-engine/base.ts
|
|
@@ -3555,6 +3555,86 @@ 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}`);
|
|
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
|
+
})], FeishuBotChannelConfigRule);
|
|
3637
|
+
//#endregion
|
|
3558
3638
|
//#region src/check.ts
|
|
3559
3639
|
/** Telemetry-aware entry: returns both the legacy CheckResult (for stdout)
|
|
3560
3640
|
* AND a DoctorReport-shape payload (for `openclaw.report_cli_run`). The
|
|
@@ -4154,9 +4234,10 @@ function makeLogger(logFile) {
|
|
|
4154
4234
|
/**
|
|
4155
4235
|
* Start an async reset task: spawn a detached child process and return the taskId.
|
|
4156
4236
|
*
|
|
4157
|
-
* The child process runs: node cli.js reset --worker --task-id=xxx
|
|
4237
|
+
* The child process runs: node cli.js reset --worker --task-id=xxx
|
|
4238
|
+
* The worker fetches ctx from innerApi itself — no --ctx passthrough.
|
|
4158
4239
|
*/
|
|
4159
|
-
function startAsyncReset(
|
|
4240
|
+
function startAsyncReset() {
|
|
4160
4241
|
const taskId = (0, node_crypto.randomUUID)();
|
|
4161
4242
|
const resultFile = resetResultFile(taskId);
|
|
4162
4243
|
const log = makeLogger(resetLogFile(taskId));
|
|
@@ -4180,8 +4261,7 @@ function startAsyncReset(ctxBase64) {
|
|
|
4180
4261
|
process.argv[1],
|
|
4181
4262
|
"reset",
|
|
4182
4263
|
"--worker",
|
|
4183
|
-
`--task-id=${taskId}
|
|
4184
|
-
`--ctx=${ctxBase64}`
|
|
4264
|
+
`--task-id=${taskId}`
|
|
4185
4265
|
], {
|
|
4186
4266
|
detached: true,
|
|
4187
4267
|
stdio: "ignore",
|
|
@@ -6695,6 +6775,60 @@ function mergeCoreBackupAndOrigins(configPath, vars, resetData, log) {
|
|
|
6695
6775
|
log(`allowedOrigins: added ${added.length} (${JSON.stringify(added)}), total now ${mergedOrigins.length}`);
|
|
6696
6776
|
}
|
|
6697
6777
|
/**
|
|
6778
|
+
* Fix bot account allowFrom and appSecret using larkApps from innerApi.
|
|
6779
|
+
*
|
|
6780
|
+
* For each bot account (key starts with `bot-cli_`):
|
|
6781
|
+
* - allowFrom must contain the bot's own creatorOpenID from larkApps
|
|
6782
|
+
* - appSecret must be either the canonical provider-ref or match larkApps plaintext
|
|
6783
|
+
*
|
|
6784
|
+
* Runs after mergeCoreBackupAndOrigins so it operates on the final config state.
|
|
6785
|
+
*/
|
|
6786
|
+
function fixBotChannelConfig(configPath, larkApps, log) {
|
|
6787
|
+
if (!larkApps || larkApps.length === 0) {
|
|
6788
|
+
log("no larkApps data, skip bot channel config fix");
|
|
6789
|
+
return;
|
|
6790
|
+
}
|
|
6791
|
+
const config = loadJSON5().parse(node_fs.default.readFileSync(configPath, "utf-8"));
|
|
6792
|
+
const accounts = asRecord(getNestedMap(config, "channels", "feishu")?.accounts);
|
|
6793
|
+
if (!accounts) {
|
|
6794
|
+
log("no feishu accounts in config, skip bot channel config fix");
|
|
6795
|
+
return;
|
|
6796
|
+
}
|
|
6797
|
+
let fixCount = 0;
|
|
6798
|
+
for (const [, account] of Object.entries(accounts)) {
|
|
6799
|
+
const bot = asRecord(account);
|
|
6800
|
+
if (!bot) continue;
|
|
6801
|
+
const appId = bot.appId;
|
|
6802
|
+
if (typeof appId !== "string" || !appId.startsWith("cli_")) continue;
|
|
6803
|
+
const larkApp = larkApps.find((e) => e.larkAppID === appId);
|
|
6804
|
+
if (!larkApp) continue;
|
|
6805
|
+
const creatorOpenID = larkApp.creatorOpenID;
|
|
6806
|
+
if (typeof creatorOpenID === "string" && creatorOpenID !== "") {
|
|
6807
|
+
const allowFrom = Array.isArray(bot.allowFrom) ? [...bot.allowFrom] : [];
|
|
6808
|
+
if (!allowFrom.includes(creatorOpenID)) {
|
|
6809
|
+
allowFrom.push(creatorOpenID);
|
|
6810
|
+
bot.allowFrom = allowFrom;
|
|
6811
|
+
fixCount++;
|
|
6812
|
+
}
|
|
6813
|
+
}
|
|
6814
|
+
const secret = bot.appSecret;
|
|
6815
|
+
let needsFix = false;
|
|
6816
|
+
if (typeof secret === "object" && secret !== null && !Array.isArray(secret)) {
|
|
6817
|
+
if (!matchMap(secret, DEFAULT_FEISHU_APP_SECRET)) needsFix = true;
|
|
6818
|
+
} else if (typeof secret === "string") {
|
|
6819
|
+
if (secret !== larkApp.appSecret) needsFix = true;
|
|
6820
|
+
} else needsFix = true;
|
|
6821
|
+
if (needsFix) {
|
|
6822
|
+
bot.appSecret = { ...DEFAULT_FEISHU_APP_SECRET };
|
|
6823
|
+
fixCount++;
|
|
6824
|
+
}
|
|
6825
|
+
}
|
|
6826
|
+
if (fixCount > 0) {
|
|
6827
|
+
node_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
6828
|
+
log(`fixed ${fixCount} bot channel config issue(s) (allowFrom/appSecret)`);
|
|
6829
|
+
} else log("bot channel config ok, no fixes needed");
|
|
6830
|
+
}
|
|
6831
|
+
/**
|
|
6698
6832
|
* Step 7: Verify startup scripts landed in configDir/scripts/.
|
|
6699
6833
|
*
|
|
6700
6834
|
* Scripts are extracted directly to configDir/scripts/ during stageTemplate —
|
|
@@ -6839,6 +6973,7 @@ async function runReset(input, taskId, resultFile) {
|
|
|
6839
6973
|
await step5InstallOpenclaw(openclawTag, ossFileMap, log);
|
|
6840
6974
|
step(6);
|
|
6841
6975
|
mergeCoreBackupAndOrigins(configPath, vars, resetData, log);
|
|
6976
|
+
fixBotChannelConfig(configPath, vars.larkApps, log);
|
|
6842
6977
|
step(7);
|
|
6843
6978
|
verifyStartupScripts(configDir, log);
|
|
6844
6979
|
step(8);
|
|
@@ -7637,7 +7772,8 @@ function normalizeCtx(raw) {
|
|
|
7637
7772
|
reset: {
|
|
7638
7773
|
templateVars: r.reset.templateVars ?? {},
|
|
7639
7774
|
coreBackup: r.reset.coreBackup
|
|
7640
|
-
}
|
|
7775
|
+
},
|
|
7776
|
+
larkApps: Array.isArray(r.larkApps) ? r.larkApps : []
|
|
7641
7777
|
};
|
|
7642
7778
|
}
|
|
7643
7779
|
const vars = r.vars ?? {};
|
|
@@ -7662,7 +7798,8 @@ function normalizeCtx(raw) {
|
|
|
7662
7798
|
reset: {
|
|
7663
7799
|
templateVars: resetData.templateVars ?? {},
|
|
7664
7800
|
coreBackup: resetData.coreBackup
|
|
7665
|
-
}
|
|
7801
|
+
},
|
|
7802
|
+
larkApps: Array.isArray(r.larkApps) ? r.larkApps : []
|
|
7666
7803
|
};
|
|
7667
7804
|
}
|
|
7668
7805
|
function fillApp(src) {
|
|
@@ -7727,7 +7864,8 @@ function buildCheckInput(raw, configPathOverride) {
|
|
|
7727
7864
|
providerFilePath: PROVIDER_FILE_PATH,
|
|
7728
7865
|
secretsFilePath: SECRETS_FILE_PATH,
|
|
7729
7866
|
templateVars: ctx.app.templateVars,
|
|
7730
|
-
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag
|
|
7867
|
+
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag,
|
|
7868
|
+
larkApps: ctx.larkApps
|
|
7731
7869
|
},
|
|
7732
7870
|
templateVars: ctx.app.templateVars
|
|
7733
7871
|
};
|
|
@@ -7759,7 +7897,8 @@ function buildRepairInput(raw, configPathOverride) {
|
|
|
7759
7897
|
providerFilePath: PROVIDER_FILE_PATH,
|
|
7760
7898
|
secretsFilePath: SECRETS_FILE_PATH,
|
|
7761
7899
|
templateVars: ctx.app.templateVars,
|
|
7762
|
-
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag
|
|
7900
|
+
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag,
|
|
7901
|
+
larkApps: ctx.larkApps
|
|
7763
7902
|
},
|
|
7764
7903
|
repairData: {
|
|
7765
7904
|
secretsContent: ctx.secrets.secretsContent,
|
|
@@ -7795,7 +7934,8 @@ function buildResetInput(raw, configPathOverride) {
|
|
|
7795
7934
|
providerFilePath: PROVIDER_FILE_PATH,
|
|
7796
7935
|
secretsFilePath: SECRETS_FILE_PATH,
|
|
7797
7936
|
templateVars: ctx.app.templateVars,
|
|
7798
|
-
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag
|
|
7937
|
+
recommendedOpenclawTag: ctx.app.recommendedOpenclawTag,
|
|
7938
|
+
larkApps: ctx.larkApps
|
|
7799
7939
|
},
|
|
7800
7940
|
resetData: {
|
|
7801
7941
|
templateVars: ctx.reset.templateVars,
|
|
@@ -10105,7 +10245,7 @@ async function reportCliRun(opts) {
|
|
|
10105
10245
|
//#region src/help.ts
|
|
10106
10246
|
const BIN = "mclaw-diagnose";
|
|
10107
10247
|
function versionBanner() {
|
|
10108
|
-
return `v0.1.
|
|
10248
|
+
return `v0.1.13-alpha.0`;
|
|
10109
10249
|
}
|
|
10110
10250
|
const COMMANDS = [
|
|
10111
10251
|
{
|
|
@@ -10528,6 +10668,20 @@ function planVarsFields(opts = {}) {
|
|
|
10528
10668
|
}
|
|
10529
10669
|
return [...fields].sort();
|
|
10530
10670
|
}
|
|
10671
|
+
/** Check if any enabled rule declares a specific Vars field in usesVars. */
|
|
10672
|
+
function doesAnyRuleUseVar(field, opts = {}) {
|
|
10673
|
+
const disabled = new Set(opts.disabled ?? []);
|
|
10674
|
+
const only = opts.onlyRules && opts.onlyRules.length > 0 ? new Set(opts.onlyRules) : null;
|
|
10675
|
+
const profile = opts.profile ?? "standard";
|
|
10676
|
+
for (const rule of getAllRules()) {
|
|
10677
|
+
const key = rule.meta.key;
|
|
10678
|
+
if (disabled.has(key)) continue;
|
|
10679
|
+
if (only && !only.has(key)) continue;
|
|
10680
|
+
if (!isProfileEnabled(rule, profile)) continue;
|
|
10681
|
+
if ((rule.meta.usesVars ?? []).includes(field)) return true;
|
|
10682
|
+
}
|
|
10683
|
+
return false;
|
|
10684
|
+
}
|
|
10531
10685
|
/**
|
|
10532
10686
|
* Plan a `populate` selector for a given subcommand.
|
|
10533
10687
|
*
|
|
@@ -10552,6 +10706,11 @@ function planCtxPopulate(opts) {
|
|
|
10552
10706
|
profile: opts.profile
|
|
10553
10707
|
});
|
|
10554
10708
|
if (appFields.length > 0) populate.app = appFields;
|
|
10709
|
+
if (doesAnyRuleUseVar("larkApps", {
|
|
10710
|
+
disabled: opts.disabled,
|
|
10711
|
+
onlyRules: opts.onlyRules,
|
|
10712
|
+
profile: opts.profile
|
|
10713
|
+
})) populate.larkApps = true;
|
|
10555
10714
|
if (opts.command === "repair") populate.secrets = true;
|
|
10556
10715
|
else if (opts.command === "reset") {
|
|
10557
10716
|
populate.secrets = true;
|
|
@@ -10658,8 +10817,8 @@ function getMultiFlag(args, name) {
|
|
|
10658
10817
|
* case but is no longer consulted.
|
|
10659
10818
|
*/
|
|
10660
10819
|
async function reportRun(command, rc, _raw, invocation, durationMs, outcome, slardar = {
|
|
10661
|
-
scene,
|
|
10662
|
-
profile,
|
|
10820
|
+
scene: void 0,
|
|
10821
|
+
profile: "standard",
|
|
10663
10822
|
fix: false
|
|
10664
10823
|
}) {
|
|
10665
10824
|
console.error(`${command}: telemetry calling report_cli_run`);
|
|
@@ -10819,27 +10978,15 @@ async function main() {
|
|
|
10819
10978
|
break;
|
|
10820
10979
|
}
|
|
10821
10980
|
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")) {
|
|
10981
|
+
if (args.includes("--async")) console.log(JSON.stringify(startAsyncReset()));
|
|
10982
|
+
else if (args.includes("--worker")) {
|
|
10836
10983
|
const taskId = args.find((a) => a.startsWith("--task-id="))?.slice(10);
|
|
10837
10984
|
if (!taskId) {
|
|
10838
10985
|
console.error("Error: --task-id=<id> is required for worker");
|
|
10839
10986
|
node_process.default.exit(1);
|
|
10840
10987
|
}
|
|
10841
10988
|
const resultFile = resetResultFile(taskId);
|
|
10842
|
-
const raw =
|
|
10989
|
+
const raw = await fetchCtxViaInnerApi({
|
|
10843
10990
|
populate: planCtxPopulate({ command: "reset" }),
|
|
10844
10991
|
caller,
|
|
10845
10992
|
traceId
|
|
@@ -10863,7 +11010,7 @@ async function main() {
|
|
|
10863
11010
|
return;
|
|
10864
11011
|
}
|
|
10865
11012
|
} else {
|
|
10866
|
-
console.error("Usage: reset --async
|
|
11013
|
+
console.error("Usage: reset --async | reset --worker --task-id=<id>");
|
|
10867
11014
|
node_process.default.exit(1);
|
|
10868
11015
|
}
|
|
10869
11016
|
break;
|
package/package.json
CHANGED