evolclaw 3.1.3 → 3.1.4
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/CHANGELOG.md +17 -0
- package/assets/.env.template +4 -0
- package/assets/config.json.template +6 -0
- package/assets/wechat-group-qr.jpeg +0 -0
- package/dist/agents/kit-renderer.js +35 -21
- package/dist/aun/aid/agentmd.js +25 -54
- package/dist/aun/aid/client.js +22 -7
- package/dist/aun/aid/identity.js +314 -28
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/rpc/connection.js +8 -13
- package/dist/channels/aun.js +31 -72
- package/dist/cli/agent.js +15 -22
- package/dist/cli/bench.js +8 -14
- package/dist/cli/help.js +23 -0
- package/dist/cli/index.js +371 -36
- package/dist/cli/init-channel.js +2 -3
- package/dist/cli/link-rules.js +2 -1
- package/dist/cli/net-check.js +10 -11
- package/dist/core/command-handler.js +6 -7
- package/dist/core/message/message-processor.js +19 -18
- package/dist/core/relation/peer-identity.js +64 -21
- package/dist/core/session/session-manager.js +6 -2
- package/dist/core/trigger/manager.js +37 -0
- package/dist/index.js +4 -1
- package/dist/paths.js +87 -16
- package/dist/utils/npm-ops.js +18 -11
- package/kits/eck_manifest.json +8 -8
- package/kits/rules/05-venue.md +2 -2
- package/kits/templates/system-fragments/baseagent.md +7 -1
- package/kits/templates/system-fragments/channel.md +4 -1
- package/kits/templates/system-fragments/identity.md +4 -4
- package/kits/templates/system-fragments/relation.md +8 -5
- package/kits/templates/system-fragments/session.md +20 -0
- package/kits/templates/system-fragments/venue.md +4 -1
- package/package.json +4 -2
- package/dist/net-check.js +0 -640
- package/dist/watch-msg.js +0 -544
- package/kits/templates/system-fragments/eckruntime.md +0 -14
package/dist/cli/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { migrateProject } from '../config-store.js';
|
|
|
11
11
|
import { cmdInit } from './init.js';
|
|
12
12
|
import { ipcQuery } from '../ipc.js';
|
|
13
13
|
import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom } from './init-channel.js';
|
|
14
|
+
import { isHelpFlag, wantsHelp } from './help.js';
|
|
14
15
|
import * as platform from '../utils/cross-platform.js';
|
|
15
16
|
import { EventBus } from '../core/event-bus.js';
|
|
16
17
|
import { tryUpgrade, tryUpgradeAunSdk } from '../utils/npm-ops.js';
|
|
@@ -2765,7 +2766,7 @@ Agent:
|
|
|
2765
2766
|
process.exit(1);
|
|
2766
2767
|
}
|
|
2767
2768
|
// help 不需要连接服务,直接复用无参数时的帮助输出
|
|
2768
|
-
if (args[0]
|
|
2769
|
+
if (isHelpFlag(args[0])) {
|
|
2769
2770
|
return cmdCtl([]);
|
|
2770
2771
|
}
|
|
2771
2772
|
const sessionId = process.env.EVOLCLAW_SESSION_ID;
|
|
@@ -2800,7 +2801,7 @@ Agent:
|
|
|
2800
2801
|
async function cmdAgent(args) {
|
|
2801
2802
|
const sub = args[0];
|
|
2802
2803
|
const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
2803
|
-
if (!sub || sub
|
|
2804
|
+
if (!sub || isHelpFlag(sub)) {
|
|
2804
2805
|
console.log(`用法: evolclaw agent <command>
|
|
2805
2806
|
|
|
2806
2807
|
Commands:
|
|
@@ -2818,6 +2819,7 @@ Commands:
|
|
|
2818
2819
|
|
|
2819
2820
|
Options:
|
|
2820
2821
|
--format json 输出 JSON 格式
|
|
2822
|
+
--help, -h 各子命令均支持,查看详细用法
|
|
2821
2823
|
|
|
2822
2824
|
示例:
|
|
2823
2825
|
evolclaw agent list
|
|
@@ -2832,7 +2834,13 @@ Options:
|
|
|
2832
2834
|
}
|
|
2833
2835
|
const { agentList, agentShow, agentCreateInteractive, agentCreateNonInteractive, agentReload, agentEnable, agentDisable, agentGet, agentSet, agentDelete, agentRename, } = await import('./agent.js');
|
|
2834
2836
|
// --- list ---
|
|
2835
|
-
if (
|
|
2837
|
+
if (sub === 'list') {
|
|
2838
|
+
if (wantsHelp(args)) {
|
|
2839
|
+
console.log(`用法: evolclaw agent list [--format json]
|
|
2840
|
+
|
|
2841
|
+
列出所有 agent,显示名称、状态、渠道、项目、基座、最后活跃时间。`);
|
|
2842
|
+
return;
|
|
2843
|
+
}
|
|
2836
2844
|
const result = await agentList();
|
|
2837
2845
|
if (!result.ok) {
|
|
2838
2846
|
if (formatJson) {
|
|
@@ -2893,6 +2901,24 @@ Options:
|
|
|
2893
2901
|
}
|
|
2894
2902
|
// --- new ---
|
|
2895
2903
|
if (sub === 'new') {
|
|
2904
|
+
if (wantsHelp(args)) {
|
|
2905
|
+
console.log(`用法: evolclaw agent new [aid] 交互式创建
|
|
2906
|
+
evolclaw agent new <aid> --non-interactive [选项]
|
|
2907
|
+
|
|
2908
|
+
非交互模式选项:
|
|
2909
|
+
--baseagent <claude|codex|gemini> 默认: PATH 中第一个可用
|
|
2910
|
+
--project <absolute path> 必填
|
|
2911
|
+
--owner <aid>
|
|
2912
|
+
--name <display-name>
|
|
2913
|
+
--description <text>
|
|
2914
|
+
--force 覆盖已有 config.json
|
|
2915
|
+
--format json 输出 JSON
|
|
2916
|
+
|
|
2917
|
+
示例:
|
|
2918
|
+
evolclaw agent new mybot.agentid.pub
|
|
2919
|
+
evolclaw agent new mybot.agentid.pub --non-interactive --project /abs/path --baseagent claude`);
|
|
2920
|
+
return;
|
|
2921
|
+
}
|
|
2896
2922
|
const name = args[1];
|
|
2897
2923
|
const nonInteractive = args.includes('--non-interactive');
|
|
2898
2924
|
if (nonInteractive) {
|
|
@@ -2989,6 +3015,14 @@ Options:
|
|
|
2989
3015
|
// }
|
|
2990
3016
|
// --- reload ---
|
|
2991
3017
|
if (sub === 'reload') {
|
|
3018
|
+
if (wantsHelp(args)) {
|
|
3019
|
+
console.log(`用法: evolclaw agent reload [aid] [--format json]
|
|
3020
|
+
|
|
3021
|
+
热重载 agent 配置。
|
|
3022
|
+
无参数 全量 resync(扫磁盘,新增上线、删除下线、修改热更新)
|
|
3023
|
+
<aid> 仅热重载指定 agent`);
|
|
3024
|
+
return;
|
|
3025
|
+
}
|
|
2992
3026
|
const target = args[1] && !args[1].startsWith('--') ? args[1] : undefined;
|
|
2993
3027
|
const result = await agentReload(target);
|
|
2994
3028
|
if (!result.ok) {
|
|
@@ -3016,6 +3050,12 @@ Options:
|
|
|
3016
3050
|
}
|
|
3017
3051
|
// --- enable ---
|
|
3018
3052
|
if (sub === 'enable') {
|
|
3053
|
+
if (wantsHelp(args)) {
|
|
3054
|
+
console.log(`用法: evolclaw agent enable <aid> [--format json]
|
|
3055
|
+
|
|
3056
|
+
启用 agent。若服务运行中会热重载,否则下次 evolclaw start 时生效。`);
|
|
3057
|
+
return;
|
|
3058
|
+
}
|
|
3019
3059
|
const aid = args[1];
|
|
3020
3060
|
if (!aid) {
|
|
3021
3061
|
console.error('用法: evolclaw agent enable <aid>');
|
|
@@ -3041,6 +3081,12 @@ Options:
|
|
|
3041
3081
|
}
|
|
3042
3082
|
// --- disable ---
|
|
3043
3083
|
if (sub === 'disable') {
|
|
3084
|
+
if (wantsHelp(args)) {
|
|
3085
|
+
console.log(`用法: evolclaw agent disable <aid> [--format json]
|
|
3086
|
+
|
|
3087
|
+
停用 agent。若服务运行中会热重载离线,否则在配置中标记为禁用。`);
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
3044
3090
|
const aid = args[1];
|
|
3045
3091
|
if (!aid) {
|
|
3046
3092
|
console.error('用法: evolclaw agent disable <aid>');
|
|
@@ -3066,6 +3112,16 @@ Options:
|
|
|
3066
3112
|
}
|
|
3067
3113
|
// --- get ---
|
|
3068
3114
|
if (sub === 'get') {
|
|
3115
|
+
if (wantsHelp(args)) {
|
|
3116
|
+
console.log(`用法: evolclaw agent get <aid> <key> [--format json]
|
|
3117
|
+
|
|
3118
|
+
读取单个配置字段。key 支持点路径,如 "channels.aun.enabled"。
|
|
3119
|
+
|
|
3120
|
+
示例:
|
|
3121
|
+
evolclaw agent get mybot.agentid.pub active_baseagent
|
|
3122
|
+
evolclaw agent get mybot.agentid.pub channels.aun.enabled`);
|
|
3123
|
+
return;
|
|
3124
|
+
}
|
|
3069
3125
|
const aid = args[1];
|
|
3070
3126
|
const key = args[2];
|
|
3071
3127
|
if (!aid || !key) {
|
|
@@ -3093,6 +3149,16 @@ Options:
|
|
|
3093
3149
|
}
|
|
3094
3150
|
// --- set ---
|
|
3095
3151
|
if (sub === 'set') {
|
|
3152
|
+
if (wantsHelp(args)) {
|
|
3153
|
+
console.log(`用法: evolclaw agent set <aid> <key> <value> [--format json]
|
|
3154
|
+
|
|
3155
|
+
修改单个配置字段。key 支持点路径。修改后若服务运行中会自动热重载。
|
|
3156
|
+
|
|
3157
|
+
示例:
|
|
3158
|
+
evolclaw agent set mybot.agentid.pub active_baseagent codex
|
|
3159
|
+
evolclaw agent set mybot.agentid.pub channels.aun.enabled true`);
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
3096
3162
|
const aid = args[1];
|
|
3097
3163
|
const key = args[2];
|
|
3098
3164
|
const val = args[3];
|
|
@@ -3120,6 +3186,15 @@ Options:
|
|
|
3120
3186
|
}
|
|
3121
3187
|
// --- rename ---
|
|
3122
3188
|
if (sub === 'rename') {
|
|
3189
|
+
if (wantsHelp(args)) {
|
|
3190
|
+
console.log(`用法: evolclaw agent rename <aid> <name> [--format json]
|
|
3191
|
+
|
|
3192
|
+
修改 agent 显示名称。同时更新本地 agent.md 并尝试重新上传。
|
|
3193
|
+
|
|
3194
|
+
示例:
|
|
3195
|
+
evolclaw agent rename mybot.agentid.pub "My Bot"`);
|
|
3196
|
+
return;
|
|
3197
|
+
}
|
|
3123
3198
|
const aid = args[1];
|
|
3124
3199
|
const newName = args[2];
|
|
3125
3200
|
if (!aid || !newName) {
|
|
@@ -3146,6 +3221,14 @@ Options:
|
|
|
3146
3221
|
}
|
|
3147
3222
|
// --- delete ---
|
|
3148
3223
|
if (sub === 'delete') {
|
|
3224
|
+
if (wantsHelp(args)) {
|
|
3225
|
+
console.log(`用法: evolclaw agent delete <aid> [--purge] [--format json]
|
|
3226
|
+
|
|
3227
|
+
删除 agent 的配置。
|
|
3228
|
+
--purge 同时清除该 agent 的会话、消息、日志等运行时数据
|
|
3229
|
+
默认 仅删除 config.json,运行时数据保留`);
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3149
3232
|
const aid = args[1];
|
|
3150
3233
|
if (!aid) {
|
|
3151
3234
|
console.error('用法: evolclaw agent delete <aid> [--purge]');
|
|
@@ -3172,6 +3255,12 @@ Options:
|
|
|
3172
3255
|
}
|
|
3173
3256
|
// --- show ---
|
|
3174
3257
|
if (sub === 'show') {
|
|
3258
|
+
if (wantsHelp(args)) {
|
|
3259
|
+
console.log(`用法: evolclaw agent show <aid> [--format json]
|
|
3260
|
+
|
|
3261
|
+
查看 agent 详情:身份、配置、连接状态、会话路径等。`);
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3175
3264
|
const aid = args[1];
|
|
3176
3265
|
if (!aid) {
|
|
3177
3266
|
console.error('用法: evolclaw agent show <aid>');
|
|
@@ -3285,63 +3374,134 @@ function resolveAunPath(args) {
|
|
|
3285
3374
|
return process.env.AUN_HOME || undefined;
|
|
3286
3375
|
}
|
|
3287
3376
|
async function cmdAid(args) {
|
|
3288
|
-
const sub = args[0]
|
|
3377
|
+
const sub = args[0];
|
|
3289
3378
|
const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
3290
3379
|
const aunPath = resolveAunPath(args);
|
|
3291
|
-
if (!sub || sub
|
|
3380
|
+
if (!sub || isHelpFlag(sub)) {
|
|
3292
3381
|
console.log(`用法: evolclaw aid <command>
|
|
3293
3382
|
|
|
3294
3383
|
Commands:
|
|
3295
|
-
list 列出本地所有 AID
|
|
3296
|
-
show <aid> 查看本地 AID
|
|
3384
|
+
list 列出本地所有 AID(实测 sign+verify)
|
|
3385
|
+
show <aid> 查看本地 AID 详情(证书、私钥、签名能力)
|
|
3297
3386
|
new <aid> 创建新 AID 身份
|
|
3298
|
-
delete <aid>
|
|
3387
|
+
delete <aid> 删除指定本地 AID(无网络注销)
|
|
3388
|
+
delete --orphan 批量清理无私钥的外部 AID 缓存
|
|
3389
|
+
delete --no-cert 批量清理无私钥也无公钥证书的孤儿目录
|
|
3390
|
+
delete --unrecoverable 批量清理云端公钥已变更、本地不可恢复的 AID
|
|
3391
|
+
批量删除默认 dry-run,加 --yes 执行
|
|
3299
3392
|
lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
|
|
3300
3393
|
agentmd put <aid> 读本地 agent.md → 签名 → 上传
|
|
3301
3394
|
agentmd get <aid> 下载 agent.md → 验签 → 本地持久化
|
|
3302
3395
|
|
|
3303
3396
|
Options:
|
|
3304
3397
|
--format json 输出 JSON 格式
|
|
3398
|
+
--help, -h 各子命令均支持,查看详细用法
|
|
3305
3399
|
|
|
3306
3400
|
示例:
|
|
3307
3401
|
evolclaw aid list
|
|
3308
3402
|
evolclaw aid show toleiliang2.agentid.pub
|
|
3309
3403
|
evolclaw aid new reviewer.agentid.pub
|
|
3404
|
+
evolclaw aid delete --help
|
|
3310
3405
|
evolclaw aid delete old.agentid.pub
|
|
3406
|
+
evolclaw aid delete --orphan
|
|
3407
|
+
evolclaw aid delete --unrecoverable --yes
|
|
3311
3408
|
evolclaw aid lookup someone.agentid.pub
|
|
3312
3409
|
evolclaw aid agentmd put mybot.agentid.pub
|
|
3313
3410
|
evolclaw aid agentmd get someone.agentid.pub`);
|
|
3314
3411
|
return;
|
|
3315
3412
|
}
|
|
3316
|
-
const { aidList, aidCreate, aidShow, aidDelete, aidLookup, agentmdPut, agentmdGet, buildInitialAgentMd, isValidAid } = await import('../aun/aid/index.js');
|
|
3413
|
+
const { aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, agentmdPut, agentmdGet, buildInitialAgentMd, isValidAid } = await import('../aun/aid/index.js');
|
|
3317
3414
|
if (sub === 'list') {
|
|
3318
|
-
|
|
3415
|
+
if (wantsHelp(args)) {
|
|
3416
|
+
console.log(`用法: evolclaw aid list [筛选选项] [--no-verify] [--format json]
|
|
3417
|
+
|
|
3418
|
+
列出本地 AID 并跑 sign+verify 自检。
|
|
3419
|
+
|
|
3420
|
+
筛选选项(可组合,不指定 = 列出 mine + broken + peer-cert):
|
|
3421
|
+
--mine 仅本地可用身份(实测可签名+验签通过)
|
|
3422
|
+
--broken 仅有私钥但不可用(公钥不匹配 / 证书过期 / sign 失败)
|
|
3423
|
+
--peer-cert 仅对端 AID(无私钥,有公钥证书)
|
|
3424
|
+
--no-cert 仅无私钥无证书的目录(默认隐藏,需用 aid delete --no-cert 清理)
|
|
3425
|
+
|
|
3426
|
+
选项:
|
|
3427
|
+
--no-verify 跳过 sign+verify 实测,仅静态扫描(更快,mine/broken 仅按静态判定近似)
|
|
3428
|
+
--format json JSON 格式输出
|
|
3429
|
+
|
|
3430
|
+
输出图标:
|
|
3431
|
+
🔑 有私钥
|
|
3432
|
+
✅ 实测可签名/验签
|
|
3433
|
+
❌ 不可签名(公钥不匹配 / sign 失败 / verify 失败等)
|
|
3434
|
+
⌛ 证书过期
|
|
3435
|
+
📜 有公钥证书
|
|
3436
|
+
📄 有 agent.md
|
|
3437
|
+
|
|
3438
|
+
示例:
|
|
3439
|
+
evolclaw aid list 列出 mine + broken + peer-cert
|
|
3440
|
+
evolclaw aid list --mine 仅可用身份
|
|
3441
|
+
evolclaw aid list --mine --broken 所有有私钥的 AID
|
|
3442
|
+
evolclaw aid list --no-cert 仅无私钥无证书的孤儿目录
|
|
3443
|
+
evolclaw aid list --no-verify 跳过实测,快速静态扫描`);
|
|
3444
|
+
return;
|
|
3445
|
+
}
|
|
3446
|
+
const wantMine = args.includes('--mine');
|
|
3447
|
+
const wantBroken = args.includes('--broken');
|
|
3448
|
+
const wantPeerCert = args.includes('--peer-cert');
|
|
3449
|
+
const wantNoCert = args.includes('--no-cert');
|
|
3450
|
+
const noVerify = args.includes('--no-verify');
|
|
3451
|
+
const anyFilter = wantMine || wantBroken || wantPeerCert || wantNoCert;
|
|
3452
|
+
// 默认: mine + broken + peer-cert(隐藏 no-cert,需显式 --no-cert 才列)
|
|
3453
|
+
const showMine = anyFilter ? wantMine : true;
|
|
3454
|
+
const showBroken = anyFilter ? wantBroken : true;
|
|
3455
|
+
const showPeerCert = anyFilter ? wantPeerCert : true;
|
|
3456
|
+
const showNoCert = anyFilter ? wantNoCert : false;
|
|
3457
|
+
const all = noVerify ? aidList(aunPath) : await aidListVerified(aunPath);
|
|
3458
|
+
const aids = all.filter(a => (showMine && a.category === 'mine') ||
|
|
3459
|
+
(showBroken && a.category === 'broken') ||
|
|
3460
|
+
(showPeerCert && a.category === 'peer-cert') ||
|
|
3461
|
+
(showNoCert && a.category === 'no-cert'));
|
|
3319
3462
|
if (formatJson) {
|
|
3320
3463
|
console.log(JSON.stringify(aids, null, 2));
|
|
3321
3464
|
return;
|
|
3322
3465
|
}
|
|
3323
3466
|
if (aids.length === 0) {
|
|
3324
|
-
console.log('
|
|
3467
|
+
console.log('无匹配 AID');
|
|
3325
3468
|
return;
|
|
3326
3469
|
}
|
|
3327
|
-
console.log('
|
|
3470
|
+
console.log(`本地 AID${noVerify ? '(静态扫描,未实测)' : ''}:`);
|
|
3328
3471
|
for (const a of aids) {
|
|
3329
|
-
const
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3472
|
+
const keyIcon = a.hasPrivateKey ? '🔑' : ' ';
|
|
3473
|
+
let signIcon = ' ';
|
|
3474
|
+
// --no-verify 时 signVerified 始终为 null,用 canSign 作为静态近似
|
|
3475
|
+
const effectiveOk = noVerify ? a.canSign : a.signVerified === true;
|
|
3476
|
+
const effectiveFail = noVerify ? (a.hasPrivateKey && !a.canSign) : (a.hasPrivateKey && a.signVerified === false);
|
|
3477
|
+
if (effectiveOk)
|
|
3478
|
+
signIcon = '✅';
|
|
3479
|
+
else if (a.hasPrivateKey && a.certExpired)
|
|
3480
|
+
signIcon = '⌛';
|
|
3481
|
+
else if (effectiveFail)
|
|
3482
|
+
signIcon = '❌';
|
|
3483
|
+
const certIcon = a.hasCert ? '📜' : ' ';
|
|
3484
|
+
const mdIcon = a.hasAgentMd ? '📄' : ' ';
|
|
3485
|
+
const tail = !noVerify && a.signVerified === false && a.signError && !(a.keyMatchesCert === false || a.certExpired || !a.hasPrivateKey || !a.hasCert)
|
|
3486
|
+
? ` (${a.signError})` : '';
|
|
3487
|
+
console.log(` ${keyIcon} ${signIcon} ${certIcon} ${mdIcon} ${a.aid}${tail}`);
|
|
3488
|
+
}
|
|
3489
|
+
console.log('\n🔑=私钥 ✅=可签名/验签 ❌=不可签名 ⌛=证书过期 📜=公钥证书 📄=agent.md');
|
|
3336
3490
|
return;
|
|
3337
3491
|
}
|
|
3338
3492
|
if (sub === 'show') {
|
|
3493
|
+
if (wantsHelp(args)) {
|
|
3494
|
+
console.log(`用法: evolclaw aid show <aid> [--format json]
|
|
3495
|
+
|
|
3496
|
+
查看本地 AID 详情:私钥/证书/agent.md 状态、签名能力实测。`);
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3339
3499
|
const aid = args[1];
|
|
3340
3500
|
if (!aid) {
|
|
3341
3501
|
console.error('用法: evolclaw aid show <aid>');
|
|
3342
3502
|
process.exit(1);
|
|
3343
3503
|
}
|
|
3344
|
-
const info = aidShow(aid, { aunPath });
|
|
3504
|
+
const info = await aidShow(aid, { aunPath });
|
|
3345
3505
|
if (formatJson) {
|
|
3346
3506
|
console.log(JSON.stringify(info, null, 2));
|
|
3347
3507
|
return;
|
|
@@ -3349,12 +3509,37 @@ Options:
|
|
|
3349
3509
|
console.log(`AID: ${info.aid}`);
|
|
3350
3510
|
console.log(` 私钥: ${info.hasPrivateKey ? '有' : '无'}`);
|
|
3351
3511
|
console.log(` agent.md: ${info.hasAgentMd ? '有' : '无'}`);
|
|
3352
|
-
|
|
3512
|
+
if (info.hasAgentMd) {
|
|
3513
|
+
const sigLabel = info.agentMdSignature === 'verified' ? '✓ 已验签'
|
|
3514
|
+
: info.agentMdSignature === 'unsigned' ? '⚠ 未签名'
|
|
3515
|
+
: info.agentMdSignature === 'invalid' ? `✗ 签名无效${info.agentMdSignatureReason ? ': ' + info.agentMdSignatureReason : ''}`
|
|
3516
|
+
: '? 未知';
|
|
3517
|
+
console.log(` 签名状态: ${sigLabel}`);
|
|
3518
|
+
}
|
|
3519
|
+
console.log(` 证书到期: ${info.certExpiresAt ?? '无证书'}${info.certExpired ? ' (已过期!)' : ''}`);
|
|
3353
3520
|
if (info.certSubject)
|
|
3354
3521
|
console.log(` 证书主体: ${info.certSubject}`);
|
|
3522
|
+
if (info.keyMatchesCert === false)
|
|
3523
|
+
console.log(` 密钥/证书: ✗ 公钥不匹配(cert.pem 与 key.json 公钥不一致)`);
|
|
3524
|
+
else if (info.keyMatchesCert === true)
|
|
3525
|
+
console.log(` 密钥/证书: ✓ 公钥一致`);
|
|
3526
|
+
if (info.signVerified === true)
|
|
3527
|
+
console.log(` 可签名/验签: ✓ 实测通过`);
|
|
3528
|
+
else if (info.signVerified === false)
|
|
3529
|
+
console.log(` 可签名/验签: ✗ 失败${info.signError ? `(${info.signError})` : ''}`);
|
|
3530
|
+
else
|
|
3531
|
+
console.log(` 可签名/验签: ? 未知`);
|
|
3355
3532
|
return;
|
|
3356
3533
|
}
|
|
3357
3534
|
if (sub === 'new') {
|
|
3535
|
+
if (wantsHelp(args)) {
|
|
3536
|
+
console.log(`用法: evolclaw aid new <完整AID>
|
|
3537
|
+
|
|
3538
|
+
创建新 AID 身份:生成 ECDSA 密钥对、向 Issuer 申请证书、构建并上传初始 agent.md。
|
|
3539
|
+
|
|
3540
|
+
例: evolclaw aid new reviewer.agentid.pub`);
|
|
3541
|
+
return;
|
|
3542
|
+
}
|
|
3358
3543
|
const aid = args[1];
|
|
3359
3544
|
if (!aid) {
|
|
3360
3545
|
console.error('用法: evolclaw aid new <完整AID>\n例: evolclaw aid new reviewer.agentid.pub');
|
|
@@ -3385,22 +3570,162 @@ Options:
|
|
|
3385
3570
|
return;
|
|
3386
3571
|
}
|
|
3387
3572
|
if (sub === 'delete') {
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3573
|
+
if (wantsHelp(args)) {
|
|
3574
|
+
console.log(`用法: evolclaw aid delete <子命令>
|
|
3575
|
+
|
|
3576
|
+
单个删除:
|
|
3577
|
+
evolclaw aid delete <aid> 删除指定 AID 的本地数据(无网络注销)
|
|
3578
|
+
|
|
3579
|
+
批量删除(默认 dry-run,加 --yes 才真删):
|
|
3580
|
+
evolclaw aid delete --orphan 删除所有"无私钥"的本地缓存(外部 AID)
|
|
3581
|
+
evolclaw aid delete --no-cert 删除所有"无私钥也无公钥证书"的目录
|
|
3582
|
+
条件:!hasPrivateKey && !hasCert
|
|
3583
|
+
这些目录最多只剩 agent.md 或 SQLite 残留,
|
|
3584
|
+
对验签和加密通信都没用,删除安全。
|
|
3585
|
+
evolclaw aid delete --unrecoverable 删除所有不可恢复的 AID
|
|
3586
|
+
条件:本地 sign+verify 实测失败
|
|
3587
|
+
且 PKI 探测确认云端公钥也不等本地 key.json
|
|
3588
|
+
|
|
3589
|
+
选项:
|
|
3590
|
+
--yes 跳过 dry-run,立即执行
|
|
3591
|
+
--skip-pki --unrecoverable 时跳过 PKI 探测,仅依据本地 sign+verify 失败判断(危险,可能误删可恢复 AID)
|
|
3592
|
+
--format json 输出 JSON 格式
|
|
3593
|
+
|
|
3594
|
+
示例:
|
|
3595
|
+
evolclaw aid delete old.agentid.pub
|
|
3596
|
+
evolclaw aid delete --orphan 列出会被清理的孤儿
|
|
3597
|
+
evolclaw aid delete --orphan --yes 实际清理
|
|
3598
|
+
evolclaw aid delete --no-cert 列出无证书孤儿目录
|
|
3599
|
+
evolclaw aid delete --no-cert --yes 实际清理
|
|
3600
|
+
evolclaw aid delete --unrecoverable 联网探测后列出无救 AID
|
|
3601
|
+
evolclaw aid delete --unrecoverable --yes`);
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
3604
|
+
const yes = args.includes('--yes');
|
|
3605
|
+
const skipPki = args.includes('--skip-pki');
|
|
3606
|
+
const orphan = args.includes('--orphan');
|
|
3607
|
+
const noCert = args.includes('--no-cert');
|
|
3608
|
+
const unrecoverable = args.includes('--unrecoverable');
|
|
3609
|
+
const modes = [orphan, noCert, unrecoverable].filter(Boolean).length;
|
|
3610
|
+
if (modes > 1) {
|
|
3611
|
+
console.error('❌ --orphan / --no-cert / --unrecoverable 互斥,不能同时使用');
|
|
3391
3612
|
process.exit(1);
|
|
3392
3613
|
}
|
|
3393
|
-
|
|
3394
|
-
if (
|
|
3395
|
-
|
|
3614
|
+
// 单个 aid 删除:保留原有行为
|
|
3615
|
+
if (modes === 0) {
|
|
3616
|
+
const aid = args[1];
|
|
3617
|
+
if (!aid) {
|
|
3618
|
+
console.error('用法: evolclaw aid delete <aid>\n evolclaw aid delete --orphan | --no-cert | --unrecoverable [--yes]\n evolclaw aid delete --help 查看完整用法');
|
|
3619
|
+
process.exit(1);
|
|
3620
|
+
}
|
|
3621
|
+
const deleted = aidDelete(aid, { aunPath });
|
|
3622
|
+
if (deleted) {
|
|
3623
|
+
console.log(`✓ ${aid} 已删除`);
|
|
3624
|
+
}
|
|
3625
|
+
else {
|
|
3626
|
+
console.error(`❌ 本地不存在: ${aid}`);
|
|
3627
|
+
process.exit(1);
|
|
3628
|
+
}
|
|
3629
|
+
return;
|
|
3630
|
+
}
|
|
3631
|
+
// 批量模式:先选出候选
|
|
3632
|
+
const { probePkiRecoverability } = await import('../aun/aid/index.js');
|
|
3633
|
+
const candidates = [];
|
|
3634
|
+
if (orphan) {
|
|
3635
|
+
const aids = aidList(aunPath);
|
|
3636
|
+
for (const a of aids) {
|
|
3637
|
+
if (!a.hasPrivateKey)
|
|
3638
|
+
candidates.push({ aid: a.aid, reason: 'no private key (external AID cache)' });
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
else if (noCert) {
|
|
3642
|
+
const aids = aidList(aunPath);
|
|
3643
|
+
for (const a of aids) {
|
|
3644
|
+
if (!a.hasPrivateKey && !a.hasCert) {
|
|
3645
|
+
const traits = [a.hasAgentMd ? 'agent.md' : null].filter(Boolean).join(', ');
|
|
3646
|
+
candidates.push({ aid: a.aid, reason: `no private key, no cert${traits ? ` (only: ${traits})` : ''}` });
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3396
3649
|
}
|
|
3397
3650
|
else {
|
|
3398
|
-
|
|
3399
|
-
|
|
3651
|
+
// unrecoverable: 必须先做 sign+verify 实测
|
|
3652
|
+
if (!formatJson)
|
|
3653
|
+
console.log('扫描中: 本地签名/验签实测...');
|
|
3654
|
+
const aids = await aidListVerified(aunPath);
|
|
3655
|
+
const localBroken = aids.filter(a => a.hasPrivateKey && a.signVerified === false);
|
|
3656
|
+
if (skipPki) {
|
|
3657
|
+
for (const a of localBroken) {
|
|
3658
|
+
candidates.push({ aid: a.aid, reason: `sign+verify failed (${a.signError ?? 'unknown'}) [--skip-pki: 未联网验证]` });
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
else {
|
|
3662
|
+
if (!formatJson)
|
|
3663
|
+
console.log(`扫描中: 对 ${localBroken.length} 个本地损坏 AID 做 PKI 探测...`);
|
|
3664
|
+
for (const a of localBroken) {
|
|
3665
|
+
const r = await probePkiRecoverability(a.aid, { aunPath });
|
|
3666
|
+
if (r.kind === 'unrecoverable') {
|
|
3667
|
+
candidates.push({ aid: a.aid, reason: `local broken; PKI: ${r.reason}`, pki: 'unrecoverable' });
|
|
3668
|
+
}
|
|
3669
|
+
else if (r.kind === 'no-server-record') {
|
|
3670
|
+
candidates.push({ aid: a.aid, reason: `local broken; PKI: ${r.reason}`, pki: 'no-server-record' });
|
|
3671
|
+
}
|
|
3672
|
+
else {
|
|
3673
|
+
// recoverable / no-key / unknown 一律保守不删
|
|
3674
|
+
if (!formatJson)
|
|
3675
|
+
console.log(` · 跳过 ${a.aid}: PKI=${r.kind}${('reason' in r) ? ' — ' + r.reason : ''}`);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
if (formatJson) {
|
|
3681
|
+
console.log(JSON.stringify({
|
|
3682
|
+
mode: orphan ? 'orphan' : noCert ? 'no-cert' : 'unrecoverable',
|
|
3683
|
+
dryRun: !yes,
|
|
3684
|
+
skipPki: unrecoverable ? skipPki : undefined,
|
|
3685
|
+
candidates,
|
|
3686
|
+
}, null, 2));
|
|
3687
|
+
if (yes) {
|
|
3688
|
+
for (const c of candidates)
|
|
3689
|
+
aidDelete(c.aid, { aunPath });
|
|
3690
|
+
}
|
|
3691
|
+
return;
|
|
3692
|
+
}
|
|
3693
|
+
if (candidates.length === 0) {
|
|
3694
|
+
console.log(orphan ? '✓ 无孤儿 AID' : noCert ? '✓ 无无证书孤儿目录' : '✓ 无不可恢复 AID');
|
|
3695
|
+
return;
|
|
3400
3696
|
}
|
|
3697
|
+
console.log(`\n${yes ? '将删除' : '候选删除(dry-run)'}:${candidates.length} 个 AID`);
|
|
3698
|
+
for (const c of candidates) {
|
|
3699
|
+
console.log(` - ${c.aid}`);
|
|
3700
|
+
console.log(` ${c.reason}`);
|
|
3701
|
+
}
|
|
3702
|
+
if (!yes) {
|
|
3703
|
+
console.log('\n(dry-run,未真删除。加 --yes 执行真删。)');
|
|
3704
|
+
return;
|
|
3705
|
+
}
|
|
3706
|
+
let ok = 0;
|
|
3707
|
+
let fail = 0;
|
|
3708
|
+
for (const c of candidates) {
|
|
3709
|
+
const deleted = aidDelete(c.aid, { aunPath });
|
|
3710
|
+
if (deleted) {
|
|
3711
|
+
console.log(` ✓ 删除 ${c.aid}`);
|
|
3712
|
+
ok++;
|
|
3713
|
+
}
|
|
3714
|
+
else {
|
|
3715
|
+
console.log(` ✗ 失败 ${c.aid}(已不存在?)`);
|
|
3716
|
+
fail++;
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3719
|
+
console.log(`\n完成:成功 ${ok},失败 ${fail}`);
|
|
3401
3720
|
return;
|
|
3402
3721
|
}
|
|
3403
3722
|
if (sub === 'lookup') {
|
|
3723
|
+
if (wantsHelp(args)) {
|
|
3724
|
+
console.log(`用法: evolclaw aid lookup <aid> [--format json]
|
|
3725
|
+
|
|
3726
|
+
远程探测 AID:是否注册、所在网关、是否有 agent.md(不验签,仅获取)。`);
|
|
3727
|
+
return;
|
|
3728
|
+
}
|
|
3404
3729
|
const aid = args[1];
|
|
3405
3730
|
if (!aid) {
|
|
3406
3731
|
console.error('用法: evolclaw aid lookup <aid>');
|
|
@@ -3438,6 +3763,13 @@ Options:
|
|
|
3438
3763
|
if (sub === 'agentmd') {
|
|
3439
3764
|
const verb = args[1];
|
|
3440
3765
|
const aid = args[2];
|
|
3766
|
+
if (!verb || isHelpFlag(verb) || wantsHelp(args)) {
|
|
3767
|
+
console.log(`用法: evolclaw aid agentmd <put|get> <aid> [--format json]
|
|
3768
|
+
|
|
3769
|
+
put <aid> 读本地 agent.md → 用本地私钥签名 → 上传到 PKI
|
|
3770
|
+
get <aid> 从 PKI 下载 agent.md → 验签 → 持久化到本地`);
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3441
3773
|
if (verb === 'put') {
|
|
3442
3774
|
if (!aid) {
|
|
3443
3775
|
console.error('用法: evolclaw aid agentmd put <aid>');
|
|
@@ -3509,7 +3841,7 @@ Options:
|
|
|
3509
3841
|
}
|
|
3510
3842
|
// ==================== RPC ====================
|
|
3511
3843
|
async function cmdRpc(args) {
|
|
3512
|
-
if (args
|
|
3844
|
+
if (args.length === 0 || isHelpFlag(args[0])) {
|
|
3513
3845
|
console.log(`用法: evolclaw rpc --as <aid> --params <params>
|
|
3514
3846
|
|
|
3515
3847
|
通用 AUN RPC 调用。
|
|
@@ -3588,7 +3920,7 @@ async function cmdStorage(args) {
|
|
|
3588
3920
|
const sub = args[0];
|
|
3589
3921
|
const aunPath = resolveAunPath(args);
|
|
3590
3922
|
const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
3591
|
-
if (!sub || sub
|
|
3923
|
+
if (!sub || isHelpFlag(sub)) {
|
|
3592
3924
|
console.log(`用法: evolclaw storage <command> <aid> [options]
|
|
3593
3925
|
|
|
3594
3926
|
Commands:
|
|
@@ -3738,7 +4070,7 @@ async function cmdMsg(args) {
|
|
|
3738
4070
|
const appIdx = args.indexOf('--app');
|
|
3739
4071
|
const appSlot = appIdx >= 0 ? args[appIdx + 1] : undefined;
|
|
3740
4072
|
const asDaemon = args.includes('--as-daemon');
|
|
3741
|
-
if (!sub || sub
|
|
4073
|
+
if (!sub || isHelpFlag(sub)) {
|
|
3742
4074
|
console.log(`用法: evolclaw msg <command> <from-aid> [args...] [options]
|
|
3743
4075
|
|
|
3744
4076
|
Commands:
|
|
@@ -4024,7 +4356,7 @@ async function cmdGroup(args) {
|
|
|
4024
4356
|
const appIdx = args.indexOf('--app');
|
|
4025
4357
|
const appSlot = appIdx >= 0 ? args[appIdx + 1] : undefined;
|
|
4026
4358
|
const asDaemon = args.includes('--as-daemon');
|
|
4027
|
-
if (!sub || sub
|
|
4359
|
+
if (!sub || isHelpFlag(sub)) {
|
|
4028
4360
|
console.log(`用法: evolclaw group <command> <from-aid> [args...] [options]
|
|
4029
4361
|
|
|
4030
4362
|
消息:
|
|
@@ -4424,7 +4756,7 @@ export async function main(args) {
|
|
|
4424
4756
|
}
|
|
4425
4757
|
switch (cmd) {
|
|
4426
4758
|
case 'init':
|
|
4427
|
-
if (args[1]
|
|
4759
|
+
if (isHelpFlag(args[1])) {
|
|
4428
4760
|
console.log(`用法: evolclaw init [渠道] [选项]
|
|
4429
4761
|
|
|
4430
4762
|
仅初始化 defaults.json:
|
|
@@ -4500,7 +4832,7 @@ export async function main(args) {
|
|
|
4500
4832
|
await cmdWatchAid();
|
|
4501
4833
|
}
|
|
4502
4834
|
else if (args[1] === 'msg') {
|
|
4503
|
-
if (args[2]
|
|
4835
|
+
if (isHelpFlag(args[2])) {
|
|
4504
4836
|
console.log(`用法: evolclaw watch msg
|
|
4505
4837
|
|
|
4506
4838
|
三面板交互式消息监控 TUI。
|
|
@@ -4642,10 +4974,13 @@ Commands:
|
|
|
4642
4974
|
aid list 列出本地所有 AID
|
|
4643
4975
|
aid show <aid> 查看本地 AID 详情(证书有效期、私钥状态)
|
|
4644
4976
|
aid new <aid> 创建新 AID 身份
|
|
4645
|
-
aid delete <aid> 删除本地 AID
|
|
4646
4977
|
aid lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
|
|
4647
4978
|
aid agentmd put <aid> 签名并上传 agent.md
|
|
4648
4979
|
aid agentmd get <aid> 下载并验签 agent.md
|
|
4980
|
+
aid delete <aid> 删除指定 AID
|
|
4981
|
+
aid delete --orphan 清理无私钥的外部 AID 缓存
|
|
4982
|
+
aid delete --unrecoverable 清理云端公钥已变更、不可恢复的 AID
|
|
4983
|
+
默认 dry-run,加 --yes 执行
|
|
4649
4984
|
net 网络链路诊断
|
|
4650
4985
|
net check [<aid>] 10 步链路检测(DNS→Discovery→TCP→TLS→WSS→Auth→Ping→Echo)
|
|
4651
4986
|
net help 查看详细帮助
|
package/dist/cli/init-channel.js
CHANGED
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
import fs from 'fs';
|
|
9
9
|
import readline from 'readline';
|
|
10
10
|
import path from 'path';
|
|
11
|
-
import os from 'os';
|
|
12
11
|
import crypto from 'crypto';
|
|
13
|
-
import { aidLocalDir } from '../paths.js';
|
|
12
|
+
import { aidLocalDir, aunPath as defaultAunPath } from '../paths.js';
|
|
14
13
|
import { selectInstance } from './init.js';
|
|
15
14
|
import { npmInstallGlobal } from '../utils/npm-ops.js';
|
|
16
15
|
import { loadAllAgents, loadAgent } from '../config-store.js';
|
|
@@ -442,7 +441,7 @@ export async function setupAunAid(rl, _config) {
|
|
|
442
441
|
}
|
|
443
442
|
}
|
|
444
443
|
// Check if AID exists locally
|
|
445
|
-
const aunPath =
|
|
444
|
+
const aunPath = defaultAunPath();
|
|
446
445
|
const aidDir = path.join(aunPath, 'AIDs', aid);
|
|
447
446
|
if (fs.existsSync(aidDir) && fs.existsSync(path.join(aidDir, 'private'))) {
|
|
448
447
|
console.log(` ✓ AID ${aid} 已存在`);
|
package/dist/cli/link-rules.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { kitsRulesDir, resolvePaths } from '../paths.js';
|
|
4
4
|
import { atomicWriteJson, atomicReadJson } from '../utils/atomic-write.js';
|
|
5
|
+
import { wantsHelp } from './help.js';
|
|
5
6
|
const isWindows = process.platform === 'win32';
|
|
6
7
|
const KNOWN_BASEAGENTS = ['cc', 'codex', 'gemini'];
|
|
7
8
|
function statePath() {
|
|
@@ -196,7 +197,7 @@ function disconnect(ba) {
|
|
|
196
197
|
}
|
|
197
198
|
// ── 入口 ──
|
|
198
199
|
export function cmdLinkRules(args) {
|
|
199
|
-
if (
|
|
200
|
+
if (wantsHelp(args)) {
|
|
200
201
|
showHelp();
|
|
201
202
|
return;
|
|
202
203
|
}
|