@lark-apaas/openclaw-scripts-diagnose-cli 0.1.6-alpha.8 → 0.1.6-alpha.9
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 +128 -321
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -23,12 +23,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
//#endregion
|
|
24
24
|
let node_process = require("node:process");
|
|
25
25
|
node_process = __toESM(node_process);
|
|
26
|
+
let node_fs = require("node:fs");
|
|
27
|
+
node_fs = __toESM(node_fs);
|
|
26
28
|
let node_path = require("node:path");
|
|
27
29
|
node_path = __toESM(node_path);
|
|
28
30
|
let json5 = require("json5");
|
|
29
31
|
json5 = __toESM(json5);
|
|
30
|
-
let node_fs = require("node:fs");
|
|
31
|
-
node_fs = __toESM(node_fs);
|
|
32
32
|
let node_child_process = require("node:child_process");
|
|
33
33
|
let node_crypto = require("node:crypto");
|
|
34
34
|
node_crypto = __toESM(node_crypto);
|
|
@@ -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.6-alpha.
|
|
56
|
+
return "0.1.6-alpha.9";
|
|
57
57
|
}
|
|
58
58
|
//#endregion
|
|
59
59
|
//#region src/rule-engine/base.ts
|
|
@@ -108,6 +108,14 @@ function topoSort(rules) {
|
|
|
108
108
|
function getExtensionsDir(configPath) {
|
|
109
109
|
return node_path.default.join(node_path.default.dirname(configPath), "extensions");
|
|
110
110
|
}
|
|
111
|
+
/** 判断 `<extDir>/<name>/package.json` 是否存在,即插件是否已安装到磁盘。 */
|
|
112
|
+
function isPluginInstalledOnDisk(extDir, name) {
|
|
113
|
+
try {
|
|
114
|
+
return node_fs.default.existsSync(node_path.default.join(extDir, name, "package.json"));
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
111
119
|
/**
|
|
112
120
|
* Canonical provider-ref for the feishu app secret. Both
|
|
113
121
|
* `feishu_default_account` (multi-agent path) and `feishu_channel`
|
|
@@ -1381,11 +1389,11 @@ OldMiaodaPluginsCleanupRule = __decorate([Rule({
|
|
|
1381
1389
|
//#region src/rules/lark-plugin-allow.ts
|
|
1382
1390
|
const LARK_PLUGIN = "openclaw-lark";
|
|
1383
1391
|
const LEGACY_LARK_PLUGIN = "feishu-openclaw-plugin";
|
|
1384
|
-
const LARK_PLUGIN_NAMES
|
|
1392
|
+
const LARK_PLUGIN_NAMES = [LARK_PLUGIN, LEGACY_LARK_PLUGIN];
|
|
1385
1393
|
let LarkPluginAllowRule = class LarkPluginAllowRule extends DiagnoseRule {
|
|
1386
1394
|
validate(ctx) {
|
|
1387
|
-
const allow = getAllow(ctx.config);
|
|
1388
|
-
if (LARK_PLUGIN_NAMES
|
|
1395
|
+
const allow = getAllow$1(ctx.config);
|
|
1396
|
+
if (LARK_PLUGIN_NAMES.some((name) => allow.includes(name))) return { pass: true };
|
|
1389
1397
|
const installed = detectInstalledLarkPlugin(getExtensionsDir(ctx.configPath));
|
|
1390
1398
|
if (installed == null) return { pass: true };
|
|
1391
1399
|
return {
|
|
@@ -1404,7 +1412,7 @@ let LarkPluginAllowRule = class LarkPluginAllowRule extends DiagnoseRule {
|
|
|
1404
1412
|
const rawAllow = pluginsMap.allow;
|
|
1405
1413
|
const original = Array.isArray(rawAllow) ? rawAllow : [];
|
|
1406
1414
|
const stringAllow = original.filter((e) => typeof e === "string");
|
|
1407
|
-
if (LARK_PLUGIN_NAMES
|
|
1415
|
+
if (LARK_PLUGIN_NAMES.some((name) => stringAllow.includes(name))) return;
|
|
1408
1416
|
original.push(installed);
|
|
1409
1417
|
pluginsMap.allow = original;
|
|
1410
1418
|
}
|
|
@@ -1414,7 +1422,7 @@ LarkPluginAllowRule = __decorate([Rule({
|
|
|
1414
1422
|
dependsOn: ["config_syntax_check"],
|
|
1415
1423
|
repairMode: "standard"
|
|
1416
1424
|
})], LarkPluginAllowRule);
|
|
1417
|
-
function getAllow(config) {
|
|
1425
|
+
function getAllow$1(config) {
|
|
1418
1426
|
const plugins = config.plugins;
|
|
1419
1427
|
if (plugins == null || typeof plugins !== "object" || Array.isArray(plugins)) return [];
|
|
1420
1428
|
const allow = plugins.allow;
|
|
@@ -1438,6 +1446,117 @@ function pluginPackageJsonExists(extDir, pluginDir) {
|
|
|
1438
1446
|
}
|
|
1439
1447
|
}
|
|
1440
1448
|
//#endregion
|
|
1449
|
+
//#region src/rules/miaoda-plugin-allow.ts
|
|
1450
|
+
const MIAODA_PLUGIN = "openclaw-extension-miaoda";
|
|
1451
|
+
let MiaodaPluginAllowRule = class MiaodaPluginAllowRule extends DiagnoseRule {
|
|
1452
|
+
validate(ctx) {
|
|
1453
|
+
if (!isPluginInstalledOnDisk(getExtensionsDir(ctx.configPath), MIAODA_PLUGIN)) return { pass: true };
|
|
1454
|
+
if (getAllow(ctx.config).includes(MIAODA_PLUGIN)) return { pass: true };
|
|
1455
|
+
return {
|
|
1456
|
+
pass: false,
|
|
1457
|
+
message: `plugins.allow 缺少 ${MIAODA_PLUGIN}(已在 extensions/ 下装但未启用)`
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
repair(ctx) {
|
|
1461
|
+
if (!isPluginInstalledOnDisk(getExtensionsDir(ctx.configPath), MIAODA_PLUGIN)) return;
|
|
1462
|
+
const plugins = ctx.config.plugins;
|
|
1463
|
+
if (plugins == null || typeof plugins !== "object" || Array.isArray(plugins)) {
|
|
1464
|
+
ctx.config.plugins = { allow: [MIAODA_PLUGIN] };
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
const pluginsMap = plugins;
|
|
1468
|
+
const rawAllow = pluginsMap.allow;
|
|
1469
|
+
const allow = Array.isArray(rawAllow) ? rawAllow : [];
|
|
1470
|
+
if (allow.includes(MIAODA_PLUGIN)) return;
|
|
1471
|
+
allow.push(MIAODA_PLUGIN);
|
|
1472
|
+
pluginsMap.allow = allow;
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
MiaodaPluginAllowRule = __decorate([Rule({
|
|
1476
|
+
key: "miaoda_plugin_allow",
|
|
1477
|
+
dependsOn: ["config_syntax_check"],
|
|
1478
|
+
repairMode: "standard",
|
|
1479
|
+
profile: "experimental"
|
|
1480
|
+
})], MiaodaPluginAllowRule);
|
|
1481
|
+
function getAllow(config) {
|
|
1482
|
+
const plugins = config.plugins;
|
|
1483
|
+
if (plugins == null || typeof plugins !== "object" || Array.isArray(plugins)) return [];
|
|
1484
|
+
const allow = plugins.allow;
|
|
1485
|
+
if (!Array.isArray(allow)) return [];
|
|
1486
|
+
return allow.filter((e) => typeof e === "string");
|
|
1487
|
+
}
|
|
1488
|
+
//#endregion
|
|
1489
|
+
//#region src/rules/builtin-plugin-missing.ts
|
|
1490
|
+
/**
|
|
1491
|
+
* 遍历 plugins.installs 中所有条目(install-extension --all 写入的运行时记录),
|
|
1492
|
+
* 若对应插件在 extensions/ 磁盘上不存在,视为内置插件缺失,引导重新安装。
|
|
1493
|
+
*/
|
|
1494
|
+
function findMissingInstalledPlugins(ctx) {
|
|
1495
|
+
const extDir = getExtensionsDir(ctx.configPath);
|
|
1496
|
+
const installs = getNestedMap(ctx.config, "plugins", "installs");
|
|
1497
|
+
if (!installs) return [];
|
|
1498
|
+
return Object.keys(installs).filter((name) => !isPluginInstalledOnDisk(extDir, name)).sort();
|
|
1499
|
+
}
|
|
1500
|
+
let BuiltinPluginMissingRule = class BuiltinPluginMissingRule extends DiagnoseRule {
|
|
1501
|
+
validate(ctx) {
|
|
1502
|
+
const missing = findMissingInstalledPlugins(ctx);
|
|
1503
|
+
if (missing.length === 0) return { pass: true };
|
|
1504
|
+
return {
|
|
1505
|
+
pass: false,
|
|
1506
|
+
action: "upgrade_lark",
|
|
1507
|
+
message: `内置插件缺失,请重新安装: ${missing.join(",")}`
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
BuiltinPluginMissingRule = __decorate([Rule({
|
|
1512
|
+
key: "builtin_plugin_missing",
|
|
1513
|
+
dependsOn: ["config_syntax_check"],
|
|
1514
|
+
repairMode: "user-confirm",
|
|
1515
|
+
profile: "experimental"
|
|
1516
|
+
})], BuiltinPluginMissingRule);
|
|
1517
|
+
//#endregion
|
|
1518
|
+
//#region src/rules/builtin-plugin-installs-cleanup.ts
|
|
1519
|
+
/**
|
|
1520
|
+
* 前置规则 builtin_plugin_missing 通过后执行。
|
|
1521
|
+
* 遍历 plugins.installs 中所有条目,若对应插件在 extensions/ 下不存在,
|
|
1522
|
+
* 则将其从 installs 删除并从 allow 中移除。
|
|
1523
|
+
*/
|
|
1524
|
+
function findOrphanedInstalls(ctx) {
|
|
1525
|
+
const extDir = getExtensionsDir(ctx.configPath);
|
|
1526
|
+
const installs = getNestedMap(ctx.config, "plugins", "installs");
|
|
1527
|
+
if (!installs) return [];
|
|
1528
|
+
return Object.keys(installs).filter((name) => !isPluginInstalledOnDisk(extDir, name)).sort();
|
|
1529
|
+
}
|
|
1530
|
+
let BuiltinPluginInstallsCleanupRule = class BuiltinPluginInstallsCleanupRule extends DiagnoseRule {
|
|
1531
|
+
validate(ctx) {
|
|
1532
|
+
const orphaned = findOrphanedInstalls(ctx);
|
|
1533
|
+
if (orphaned.length === 0) return { pass: true };
|
|
1534
|
+
return {
|
|
1535
|
+
pass: false,
|
|
1536
|
+
message: `plugins.installs 存在磁盘缺失的插件: ${orphaned.join(",")}`
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
repair(ctx) {
|
|
1540
|
+
const orphaned = findOrphanedInstalls(ctx);
|
|
1541
|
+
if (orphaned.length === 0) return;
|
|
1542
|
+
const orphanSet = new Set(orphaned);
|
|
1543
|
+
const plugins = asRecord(ctx.config.plugins);
|
|
1544
|
+
const installs = asRecord(plugins.installs);
|
|
1545
|
+
if (installs) for (const name of orphaned) delete installs[name];
|
|
1546
|
+
const rawAllow = plugins.allow;
|
|
1547
|
+
if (Array.isArray(rawAllow)) for (let i = rawAllow.length - 1; i >= 0; i--) {
|
|
1548
|
+
const v = rawAllow[i];
|
|
1549
|
+
if (typeof v === "string" && orphanSet.has(v)) rawAllow.splice(i, 1);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
BuiltinPluginInstallsCleanupRule = __decorate([Rule({
|
|
1554
|
+
key: "builtin_plugin_installs_cleanup",
|
|
1555
|
+
dependsOn: ["builtin_plugin_missing"],
|
|
1556
|
+
repairMode: "standard",
|
|
1557
|
+
profile: "experimental"
|
|
1558
|
+
})], BuiltinPluginInstallsCleanupRule);
|
|
1559
|
+
//#endregion
|
|
1441
1560
|
//#region src/fs-utils.ts
|
|
1442
1561
|
/**
|
|
1443
1562
|
* Rename src → dst, falling back to `mv` (which handles cross-device copy)
|
|
@@ -4210,246 +4329,6 @@ function finalize(results, aborted) {
|
|
|
4210
4329
|
};
|
|
4211
4330
|
}
|
|
4212
4331
|
//#endregion
|
|
4213
|
-
//#region src/lark-cli-init.ts
|
|
4214
|
-
const LARK_PLUGIN_NAMES = ["openclaw-lark", "feishu-openclaw-plugin"];
|
|
4215
|
-
const PE_XML_TAG = "lark-cli-pe";
|
|
4216
|
-
const PE_PLACEHOLDER = `
|
|
4217
|
-
<${PE_XML_TAG}>
|
|
4218
|
-
**【强制要求 - 无例外】飞书所有操作必须先读 feishu-lark-cli skill。未读skill不得调用任何飞书工具,违者视为操作失误。**
|
|
4219
|
-
</${PE_XML_TAG}>
|
|
4220
|
-
`;
|
|
4221
|
-
function isLarkPluginInstalled(configPath) {
|
|
4222
|
-
const extDir = getExtensionsDir(configPath);
|
|
4223
|
-
return LARK_PLUGIN_NAMES.some((name) => {
|
|
4224
|
-
try {
|
|
4225
|
-
return node_fs.default.existsSync(node_path.default.join(extDir, name, "package.json"));
|
|
4226
|
-
} catch {
|
|
4227
|
-
return false;
|
|
4228
|
-
}
|
|
4229
|
-
});
|
|
4230
|
-
}
|
|
4231
|
-
function isLarkCliAvailable() {
|
|
4232
|
-
try {
|
|
4233
|
-
return (0, node_child_process.spawnSync)("lark-cli", ["--version"], {
|
|
4234
|
-
encoding: "utf-8",
|
|
4235
|
-
timeout: 5e3,
|
|
4236
|
-
stdio: [
|
|
4237
|
-
"ignore",
|
|
4238
|
-
"pipe",
|
|
4239
|
-
"ignore"
|
|
4240
|
-
]
|
|
4241
|
-
}).status === 0;
|
|
4242
|
-
} catch {
|
|
4243
|
-
return false;
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4246
|
-
function readConfig(configPath) {
|
|
4247
|
-
try {
|
|
4248
|
-
const raw = node_fs.default.readFileSync(configPath, "utf-8");
|
|
4249
|
-
const parsed = loadJSON5().parse(raw);
|
|
4250
|
-
return parsed != null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
4251
|
-
} catch {
|
|
4252
|
-
return null;
|
|
4253
|
-
}
|
|
4254
|
-
}
|
|
4255
|
-
/**
|
|
4256
|
-
* Resolve the feishu app secret for the given appId.
|
|
4257
|
-
*
|
|
4258
|
-
* Lookup order:
|
|
4259
|
-
* 1. channels.feishu.appSecret (single-agent: feishu.appId === appId)
|
|
4260
|
-
* 2. channels.feishu.accounts[key].appSecret (multi-agent: account.appId === appId)
|
|
4261
|
-
*
|
|
4262
|
-
* Value interpretation:
|
|
4263
|
-
* - string → use directly
|
|
4264
|
-
* - object → secret is managed by a provider; use `feishuAppSecret` param instead
|
|
4265
|
-
*
|
|
4266
|
-
* Returns null when the secret cannot be determined.
|
|
4267
|
-
*/
|
|
4268
|
-
function resolveAppSecret(appId, config, feishuAppSecret) {
|
|
4269
|
-
const feishu = getNestedMap(config, "channels", "feishu");
|
|
4270
|
-
if (!feishu) return null;
|
|
4271
|
-
let rawSecret;
|
|
4272
|
-
if (typeof feishu.appId === "string" && feishu.appId === appId) rawSecret = feishu.appSecret;
|
|
4273
|
-
else {
|
|
4274
|
-
const accounts = asRecord(feishu.accounts);
|
|
4275
|
-
if (accounts) for (const [, val] of Object.entries(accounts)) {
|
|
4276
|
-
const account = asRecord(val);
|
|
4277
|
-
if (account?.appId === appId) {
|
|
4278
|
-
rawSecret = account.appSecret ?? feishu.appSecret;
|
|
4279
|
-
break;
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
if (typeof rawSecret === "string" && rawSecret) return rawSecret;
|
|
4284
|
-
if (rawSecret != null && typeof rawSecret === "object") return feishuAppSecret ?? null;
|
|
4285
|
-
return null;
|
|
4286
|
-
}
|
|
4287
|
-
/**
|
|
4288
|
-
* Resolve the agents.md path for the given appId from the openclaw config.
|
|
4289
|
-
*
|
|
4290
|
-
* Case 1: appId matches channels.feishu.appId (single-agent path)
|
|
4291
|
-
* → WORKSPACE_DIR/AGENTS.md
|
|
4292
|
-
*
|
|
4293
|
-
* Case 2: appId found in channels.feishu.accounts (multi-agent path)
|
|
4294
|
-
* → find account key where account.appId === appId
|
|
4295
|
-
* → find binding where match.channel=feishu && match.accountId=that key
|
|
4296
|
-
* → if agentId === 'main' → WORKSPACE_DIR/agents.md
|
|
4297
|
-
* → else find agent in agents.list by id → agent.workspace/agents.md
|
|
4298
|
-
*
|
|
4299
|
-
* Returns null when the path cannot be determined.
|
|
4300
|
-
*/
|
|
4301
|
-
function resolveAgentsMdPath(appId, config) {
|
|
4302
|
-
const feishu = getNestedMap(config, "channels", "feishu");
|
|
4303
|
-
if (!feishu) {
|
|
4304
|
-
console.error("resolveAgentsMdPath: channels.feishu not found");
|
|
4305
|
-
return null;
|
|
4306
|
-
}
|
|
4307
|
-
if (typeof feishu.appId === "string" && feishu.appId === appId) {
|
|
4308
|
-
console.error(`resolveAgentsMdPath: case=single-agent feishu.appId=${feishu.appId}`);
|
|
4309
|
-
return node_path.default.join(WORKSPACE_DIR, "workspace", "AGENTS.md");
|
|
4310
|
-
}
|
|
4311
|
-
const accounts = asRecord(feishu.accounts);
|
|
4312
|
-
if (!accounts) {
|
|
4313
|
-
console.error("resolveAgentsMdPath: feishu.accounts not found");
|
|
4314
|
-
return null;
|
|
4315
|
-
}
|
|
4316
|
-
let accountId;
|
|
4317
|
-
for (const [key, val] of Object.entries(accounts)) if (asRecord(val)?.appId === appId) {
|
|
4318
|
-
accountId = key;
|
|
4319
|
-
break;
|
|
4320
|
-
}
|
|
4321
|
-
if (!accountId) {
|
|
4322
|
-
console.error(`resolveAgentsMdPath: no account found with appId=${appId} in feishu.accounts keys=[${Object.keys(accounts).join(",")}]`);
|
|
4323
|
-
return null;
|
|
4324
|
-
}
|
|
4325
|
-
console.error(`resolveAgentsMdPath: found accountId=${accountId}`);
|
|
4326
|
-
const bindings = Array.isArray(config.bindings) ? config.bindings : [];
|
|
4327
|
-
let agentId;
|
|
4328
|
-
for (const b of bindings) {
|
|
4329
|
-
const binding = asRecord(b);
|
|
4330
|
-
if (!binding) continue;
|
|
4331
|
-
const match = asRecord(binding.match);
|
|
4332
|
-
if (match?.channel === "feishu" && match?.accountId === accountId) {
|
|
4333
|
-
if (typeof binding.agentId === "string") {
|
|
4334
|
-
agentId = binding.agentId;
|
|
4335
|
-
break;
|
|
4336
|
-
}
|
|
4337
|
-
}
|
|
4338
|
-
}
|
|
4339
|
-
if (!agentId) {
|
|
4340
|
-
console.error(`resolveAgentsMdPath: no binding found for accountId=${accountId} in bindings(count=${bindings.length})`);
|
|
4341
|
-
return null;
|
|
4342
|
-
}
|
|
4343
|
-
console.error(`resolveAgentsMdPath: found agentId=${agentId}`);
|
|
4344
|
-
if (agentId === "main") {
|
|
4345
|
-
console.error("resolveAgentsMdPath: case=multi-agent-main");
|
|
4346
|
-
return node_path.default.join(WORKSPACE_DIR, "workspace", "AGENTS.md");
|
|
4347
|
-
}
|
|
4348
|
-
const agentsObj = asRecord(config.agents);
|
|
4349
|
-
const list = Array.isArray(agentsObj?.list) ? agentsObj.list : [];
|
|
4350
|
-
for (const a of list) {
|
|
4351
|
-
const agent = asRecord(a);
|
|
4352
|
-
if (agent?.id === agentId) {
|
|
4353
|
-
const ws = typeof agent.workspace === "string" ? agent.workspace : node_path.default.join(WORKSPACE_DIR, "workspace");
|
|
4354
|
-
console.error(`resolveAgentsMdPath: case=multi-agent-custom agentId=${agentId} workspace=${ws}`);
|
|
4355
|
-
return node_path.default.join(ws, "AGENTS.md");
|
|
4356
|
-
}
|
|
4357
|
-
}
|
|
4358
|
-
console.error(`resolveAgentsMdPath: agentId=${agentId} not found in agents.list(count=${list.length})`);
|
|
4359
|
-
return null;
|
|
4360
|
-
}
|
|
4361
|
-
function appendPeToAgentsMd(agentsMdPath) {
|
|
4362
|
-
const dir = node_path.default.dirname(agentsMdPath);
|
|
4363
|
-
if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
|
|
4364
|
-
const existing = node_fs.default.existsSync(agentsMdPath) ? node_fs.default.readFileSync(agentsMdPath, "utf-8") : "";
|
|
4365
|
-
if (existing.includes(`<${PE_XML_TAG}>`)) {
|
|
4366
|
-
console.error(`lark-cli-init: <${PE_XML_TAG}> already present in ${agentsMdPath}, skipping`);
|
|
4367
|
-
return;
|
|
4368
|
-
}
|
|
4369
|
-
const sep = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
4370
|
-
node_fs.default.appendFileSync(agentsMdPath, `${sep}${PE_PLACEHOLDER}`, "utf-8");
|
|
4371
|
-
console.error(`lark-cli-init: appended PE placeholder to ${agentsMdPath}`);
|
|
4372
|
-
}
|
|
4373
|
-
function runLarkCliInit(opts) {
|
|
4374
|
-
const configPath = opts.configPath ?? CONFIG_PATH;
|
|
4375
|
-
if (!isLarkPluginInstalled(configPath)) {
|
|
4376
|
-
console.error("lark-cli-init: skipping — openclaw-lark plugin not installed");
|
|
4377
|
-
return {
|
|
4378
|
-
ok: true,
|
|
4379
|
-
skipped: true,
|
|
4380
|
-
skipReason: "openclaw-lark plugin not installed"
|
|
4381
|
-
};
|
|
4382
|
-
}
|
|
4383
|
-
if (!isLarkCliAvailable()) {
|
|
4384
|
-
console.error("lark-cli-init: skipping — lark-cli command not found");
|
|
4385
|
-
return {
|
|
4386
|
-
ok: true,
|
|
4387
|
-
skipped: true,
|
|
4388
|
-
skipReason: "lark-cli command not found"
|
|
4389
|
-
};
|
|
4390
|
-
}
|
|
4391
|
-
const config = readConfig(configPath);
|
|
4392
|
-
if (!config) return {
|
|
4393
|
-
ok: false,
|
|
4394
|
-
error: `could not read config at ${configPath}`
|
|
4395
|
-
};
|
|
4396
|
-
const agentsMdPath = resolveAgentsMdPath(opts.appId, config);
|
|
4397
|
-
console.error(`lark-cli-init: resolved agents.md path=${agentsMdPath ?? "(null)"}`);
|
|
4398
|
-
if (!agentsMdPath) return {
|
|
4399
|
-
ok: false,
|
|
4400
|
-
error: `could not resolve agents.md path for appId=${opts.appId}`
|
|
4401
|
-
};
|
|
4402
|
-
const appSecret = resolveAppSecret(opts.appId, config, opts.feishuAppSecret);
|
|
4403
|
-
if (!appSecret) return {
|
|
4404
|
-
ok: false,
|
|
4405
|
-
error: `could not resolve appSecret for appId=${opts.appId}`
|
|
4406
|
-
};
|
|
4407
|
-
console.error(`lark-cli-init: running lark-cli config init --name ${opts.appId} --app-id ${opts.appId} --brand feishu --app-secret-stdin --force-init`);
|
|
4408
|
-
const initRes = (0, node_child_process.spawnSync)("lark-cli", [
|
|
4409
|
-
"config",
|
|
4410
|
-
"init",
|
|
4411
|
-
"--name",
|
|
4412
|
-
opts.appId,
|
|
4413
|
-
"--app-id",
|
|
4414
|
-
opts.appId,
|
|
4415
|
-
"--brand",
|
|
4416
|
-
"feishu",
|
|
4417
|
-
"--app-secret-stdin",
|
|
4418
|
-
"--force-init"
|
|
4419
|
-
], {
|
|
4420
|
-
stdio: [
|
|
4421
|
-
"pipe",
|
|
4422
|
-
"pipe",
|
|
4423
|
-
"pipe"
|
|
4424
|
-
],
|
|
4425
|
-
encoding: "utf-8",
|
|
4426
|
-
input: appSecret
|
|
4427
|
-
});
|
|
4428
|
-
const configInitStdout = initRes.stdout?.trim() || void 0;
|
|
4429
|
-
const configInitStderr = initRes.stderr?.trim() || void 0;
|
|
4430
|
-
if (configInitStdout) console.error(`lark-cli config init stdout: ${configInitStdout}`);
|
|
4431
|
-
if (configInitStderr) console.error(`lark-cli config init stderr: ${configInitStderr}`);
|
|
4432
|
-
if (initRes.error) return {
|
|
4433
|
-
ok: false,
|
|
4434
|
-
configInitStdout,
|
|
4435
|
-
configInitStderr,
|
|
4436
|
-
error: `lark-cli config init spawn error: ${initRes.error.message}`
|
|
4437
|
-
};
|
|
4438
|
-
if (initRes.status !== 0) return {
|
|
4439
|
-
ok: false,
|
|
4440
|
-
configInitExitCode: initRes.status ?? void 0,
|
|
4441
|
-
configInitStdout,
|
|
4442
|
-
configInitStderr,
|
|
4443
|
-
error: `lark-cli config init exited with code ${initRes.status}`
|
|
4444
|
-
};
|
|
4445
|
-
appendPeToAgentsMd(agentsMdPath);
|
|
4446
|
-
return {
|
|
4447
|
-
ok: true,
|
|
4448
|
-
configInitExitCode: 0,
|
|
4449
|
-
agentsMdPath
|
|
4450
|
-
};
|
|
4451
|
-
}
|
|
4452
|
-
//#endregion
|
|
4453
4332
|
//#region src/innerapi/reportCliRun.ts
|
|
4454
4333
|
/**
|
|
4455
4334
|
* CLI-side client for studio_server's `openclaw.report_cli_run` inner
|
|
@@ -4529,7 +4408,7 @@ async function reportCliRun(opts) {
|
|
|
4529
4408
|
//#region src/help.ts
|
|
4530
4409
|
const BIN = "mclaw-diagnose";
|
|
4531
4410
|
function versionBanner() {
|
|
4532
|
-
return `v0.1.6-alpha.
|
|
4411
|
+
return `v0.1.6-alpha.9`;
|
|
4533
4412
|
}
|
|
4534
4413
|
const COMMANDS = [
|
|
4535
4414
|
{
|
|
@@ -4738,55 +4617,6 @@ OPTIONS
|
|
|
4738
4617
|
--skip-config-update Leave plugins.installs in openclaw.json untouched.
|
|
4739
4618
|
--ctx=<base64> Opaque ctx; see install-openclaw for semantics.
|
|
4740
4619
|
--oss_file_map=... Pre-built OSS URL map (base64 JSON).
|
|
4741
|
-
`
|
|
4742
|
-
},
|
|
4743
|
-
{
|
|
4744
|
-
name: "lark-cli-init",
|
|
4745
|
-
hidden: false,
|
|
4746
|
-
summary: "Initialize lark-cli bot config and append PE to agents.md",
|
|
4747
|
-
help: `USAGE
|
|
4748
|
-
${BIN} lark-cli-init --app-id=<app-id> [--feishu-app-secret=<secret>]
|
|
4749
|
-
|
|
4750
|
-
DESCRIPTION
|
|
4751
|
-
Two-step initialization for a Lark (Feishu) bot when prerequisites are met:
|
|
4752
|
-
|
|
4753
|
-
Prerequisites (both must be satisfied, otherwise the command exits 0 with
|
|
4754
|
-
skipped=true and no side effects):
|
|
4755
|
-
1. openclaw-lark plugin installed under extensions/.
|
|
4756
|
-
2. lark-cli command available on PATH.
|
|
4757
|
-
|
|
4758
|
-
The app secret is resolved from config before running lark-cli:
|
|
4759
|
-
- channels.feishu.appSecret (single-agent) or
|
|
4760
|
-
channels.feishu.accounts[key].appSecret (multi-agent, matched by appId)
|
|
4761
|
-
- If the value is a plain string → used directly.
|
|
4762
|
-
- If the value is a provider-ref object → --feishu-app-secret must be supplied.
|
|
4763
|
-
|
|
4764
|
-
Step 1 — lark-cli config init:
|
|
4765
|
-
Pipes the resolved secret via stdin and runs:
|
|
4766
|
-
lark-cli config init \\
|
|
4767
|
-
--name <app-id> \\
|
|
4768
|
-
--app-id <app-id> \\
|
|
4769
|
-
--brand feishu \\
|
|
4770
|
-
--app-secret-stdin
|
|
4771
|
-
|
|
4772
|
-
Step 2 — append PE to agents.md:
|
|
4773
|
-
Resolves the target agents.md from config (see path resolution below)
|
|
4774
|
-
and appends a <lark-pe> placeholder block (idempotent: skipped if already present).
|
|
4775
|
-
|
|
4776
|
-
agents.md path resolution:
|
|
4777
|
-
- channels.feishu.appId === appId → WORKSPACE/workspace/AGENTS.md (single-agent)
|
|
4778
|
-
- accounts[key].appId === appId → look up binding by accountId:
|
|
4779
|
-
agentId === 'main' → WORKSPACE/workspace/AGENTS.md
|
|
4780
|
-
otherwise → agents.list[agentId].workspace/AGENTS.md
|
|
4781
|
-
|
|
4782
|
-
ARGUMENTS
|
|
4783
|
-
--app-id=<app-id> Required. Bot app ID, e.g. cli_a9659e1f0ab89ccd.
|
|
4784
|
-
|
|
4785
|
-
OPTIONS
|
|
4786
|
-
|
|
4787
|
-
EXIT CODES
|
|
4788
|
-
0 Success or skipped (prerequisites not met).
|
|
4789
|
-
1 Secret/path unresolvable, lark-cli failed, or config unreadable.
|
|
4790
4620
|
`
|
|
4791
4621
|
},
|
|
4792
4622
|
{
|
|
@@ -5266,29 +5096,6 @@ async function main() {
|
|
|
5266
5096
|
if (error) throw error;
|
|
5267
5097
|
break;
|
|
5268
5098
|
}
|
|
5269
|
-
case "lark-cli-init": {
|
|
5270
|
-
const appId = getFlag(args, "app-id");
|
|
5271
|
-
if (!appId) {
|
|
5272
|
-
console.error("Usage: lark-cli-init --app-id=<app-id>");
|
|
5273
|
-
node_process.default.exit(1);
|
|
5274
|
-
}
|
|
5275
|
-
const result = runLarkCliInit({
|
|
5276
|
-
appId,
|
|
5277
|
-
feishuAppSecret: normalizeCtx(await fetchCtxViaInnerApi({
|
|
5278
|
-
populate: { app: ["feishuAppSecret"] },
|
|
5279
|
-
caller: rc.caller,
|
|
5280
|
-
traceId: rc.traceId
|
|
5281
|
-
})).app.feishuAppSecret || void 0
|
|
5282
|
-
});
|
|
5283
|
-
console.log(JSON.stringify(result));
|
|
5284
|
-
await reportRun("lark-cli-init", rc, void 0, args.join(" "), Date.now() - t0, {
|
|
5285
|
-
success: result.ok,
|
|
5286
|
-
result,
|
|
5287
|
-
error: result.ok ? void 0 : new Error(result.error ?? "lark-cli-init failed")
|
|
5288
|
-
});
|
|
5289
|
-
if (!result.ok) node_process.default.exit(1);
|
|
5290
|
-
break;
|
|
5291
|
-
}
|
|
5292
5099
|
default:
|
|
5293
5100
|
node_process.default.stderr.write(`Unknown command: ${mode}\n\n`);
|
|
5294
5101
|
node_process.default.stderr.write(formatTopLevelHelp(helpFlags.expert));
|