evolclaw 3.0.0 → 3.1.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.
Files changed (104) hide show
  1. package/README.md +1 -1
  2. package/bin/ec.js +29 -0
  3. package/dist/agents/baseagent-normalize.js +19 -0
  4. package/dist/agents/claude-runner.js +47 -12
  5. package/dist/agents/codex-runner.js +2 -0
  6. package/dist/agents/gemini-runner.js +9 -9
  7. package/dist/agents/kit-renderer.js +281 -0
  8. package/dist/aun/aid/identity.js +28 -0
  9. package/dist/aun/aid/index.js +1 -1
  10. package/dist/aun/aid/lifecycle-log.js +33 -0
  11. package/dist/aun/msg/group.js +3 -1
  12. package/dist/aun/msg/p2p.js +42 -1
  13. package/dist/channels/aun.js +427 -146
  14. package/dist/channels/dingtalk.js +3 -1
  15. package/dist/channels/feishu.js +128 -7
  16. package/dist/channels/qqbot.js +3 -1
  17. package/dist/channels/wechat.js +4 -1
  18. package/dist/channels/wecom.js +3 -1
  19. package/dist/cli/bench.js +1219 -0
  20. package/dist/cli/index.js +418 -40
  21. package/dist/cli/init.js +3 -4
  22. package/dist/cli/link-rules.js +245 -0
  23. package/dist/cli/net-check.js +640 -0
  24. package/dist/cli/watch-msg.js +666 -0
  25. package/dist/config-store.js +82 -5
  26. package/dist/core/channel-loader.js +23 -10
  27. package/dist/core/command-handler.js +127 -99
  28. package/dist/core/evolagent.js +5 -10
  29. package/dist/core/message/im-renderer.js +93 -48
  30. package/dist/core/message/items-formatter.js +11 -4
  31. package/dist/core/message/message-bridge.js +11 -2
  32. package/dist/core/message/message-log.js +8 -1
  33. package/dist/core/message/message-processor.js +194 -127
  34. package/dist/core/message/message-queue.js +10 -3
  35. package/dist/core/permission.js +95 -3
  36. package/dist/core/relation/peer-identity.js +161 -0
  37. package/dist/core/session/session-manager.js +103 -65
  38. package/dist/core/trigger/manager.js +16 -0
  39. package/dist/core/trigger/parser.js +110 -0
  40. package/dist/core/trigger/scheduler.js +7 -1
  41. package/dist/data/error-dict.json +118 -0
  42. package/dist/eck/baseagent-caps.js +18 -0
  43. package/dist/eck/detect.js +47 -0
  44. package/dist/eck/init.js +77 -0
  45. package/dist/eck/rules-loader.js +28 -0
  46. package/dist/index.js +186 -19
  47. package/dist/net-check.js +640 -0
  48. package/dist/paths.js +31 -40
  49. package/dist/utils/aid-lifecycle-log.js +33 -0
  50. package/dist/utils/atomic-write.js +10 -0
  51. package/dist/utils/cross-platform.js +17 -8
  52. package/dist/utils/error-utils.js +27 -15
  53. package/dist/utils/instance-registry.js +6 -5
  54. package/dist/utils/log-writer.js +2 -1
  55. package/dist/utils/logger.js +10 -0
  56. package/dist/utils/npm-ops.js +35 -3
  57. package/dist/utils/process-introspect.js +16 -38
  58. package/dist/utils/stats.js +216 -2
  59. package/dist/watch-msg.js +26 -11
  60. package/evolclaw-install-aun.md +14 -2
  61. package/kits/docs/GUIDE.md +20 -0
  62. package/kits/docs/INDEX.md +52 -0
  63. package/kits/docs/aun/CHEATSHEET.md +17 -0
  64. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  65. package/kits/docs/channels/feishu.md +27 -0
  66. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  67. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  68. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  69. package/kits/docs/eck_templates/runtime.template.md +19 -0
  70. package/kits/docs/evolclaw/MSG_GROUP.md +30 -0
  71. package/kits/docs/evolclaw/MSG_PRIVATE.md +72 -0
  72. package/kits/docs/identity/AID_PROFILE_SPEC.md +27 -0
  73. package/kits/docs/identity/PATH_OPS.md +16 -0
  74. package/kits/docs/identity/ROLE_DETAIL.md +20 -0
  75. package/kits/docs/path-registry.md +43 -0
  76. package/kits/eck_manifest.json +95 -0
  77. package/kits/rules/01-overview.md +120 -0
  78. package/kits/rules/02-navigation.md +75 -0
  79. package/kits/rules/03-identity.md +34 -0
  80. package/kits/rules/04-relation.md +49 -0
  81. package/kits/rules/05-venue.md +45 -0
  82. package/kits/rules/06-channel.md +73 -0
  83. package/kits/templates/system-fragments/baseagent.md +2 -0
  84. package/kits/templates/system-fragments/channel.md +10 -0
  85. package/kits/templates/system-fragments/identity.md +12 -0
  86. package/kits/templates/system-fragments/relation.md +9 -0
  87. package/kits/templates/system-fragments/runtime.md +19 -0
  88. package/kits/templates/system-fragments/venue.md +5 -0
  89. package/package.json +7 -5
  90. package/dist/agents/templates.js +0 -122
  91. package/dist/data/prompts.md +0 -137
  92. package/kits/aun/meta.md +0 -25
  93. package/kits/aun/role.md +0 -25
  94. package/kits/templates/group.md +0 -20
  95. package/kits/templates/private.md +0 -9
  96. package/kits/templates/system-fragments/personal-context.md +0 -3
  97. package/kits/templates/system-fragments/self-intro.md +0 -5
  98. package/kits/templates/system-fragments/speaker-intro.md +0 -5
  99. package/kits/templates/system-fragments/venue-intro.md +0 -5
  100. /package/kits/{channels → docs/channels}/aun.md +0 -0
  101. /package/kits/{evolclaw/commands.md → docs/evolclaw/AGENT_CMD.md} +0 -0
  102. /package/kits/{evolclaw → docs/evolclaw}/self-summary.md +0 -0
  103. /package/kits/{evolclaw → docs/evolclaw}/tools.md +0 -0
  104. /package/kits/{evolclaw → docs/identity}/identity-tools.md +0 -0
package/dist/cli/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import os from 'os';
5
- import { spawn, execFile } from 'child_process';
5
+ import { spawn, execFileSync, execFile } from 'child_process';
6
6
  import { promisify } from 'util';
7
7
  import { resolveRoot, resolvePaths, ensureDataDirs, getPackageRoot } from '../paths.js';
8
8
  import { loadDefaults, loadAllAgents, mergeForAgent } from '../config-store.js';
@@ -13,7 +13,8 @@ import { ipcQuery } from '../ipc.js';
13
13
  import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom } from './init-channel.js';
14
14
  import * as platform from '../utils/cross-platform.js';
15
15
  import { EventBus } from '../core/event-bus.js';
16
- import { tryUpgrade } from '../utils/npm-ops.js';
16
+ import { tryUpgrade, tryUpgradeAunSdk } from '../utils/npm-ops.js';
17
+ import { resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG } from '../aun/aid/client.js';
17
18
  import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMonitor, isRestartMonitorWinner, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
18
19
  // Suppress Node.js ExperimentalWarning (e.g. SQLite) from cluttering CLI output
19
20
  process.removeAllListeners('warning');
@@ -230,7 +231,53 @@ function reportOrphans(orphans) {
230
231
  console.log(' 这些进程不属于当前 HOME 的实例登记簿,自动清理不会处理它们。');
231
232
  console.log(' 使用 evolclaw restart --clear 一并清掉,或手动 kill。');
232
233
  }
234
+ function formatLocalTime(ms) {
235
+ const d = new Date(ms);
236
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`;
237
+ }
238
+ function printStartupInfo() {
239
+ const pkgRoot = getPackageRoot();
240
+ const isNpmInstall = pkgRoot.includes('node_modules');
241
+ const cliRunsSource = !import.meta.url.includes('/dist/');
242
+ const daemonEntry = path.join(pkgRoot, 'dist', 'index.js');
243
+ const daemonRunsDist = fs.existsSync(daemonEntry);
244
+ const scanDir = path.join(pkgRoot, daemonRunsDist ? 'dist' : 'src');
245
+ let latestMtime = 0;
246
+ const scanRecursive = (dir) => {
247
+ try {
248
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
249
+ if (entry.name === 'node_modules')
250
+ continue;
251
+ const full = path.join(dir, entry.name);
252
+ if (entry.isDirectory()) {
253
+ scanRecursive(full);
254
+ continue;
255
+ }
256
+ if (entry.name.endsWith('.js') || entry.name.endsWith('.ts')) {
257
+ const mt = fs.statSync(full).mtimeMs;
258
+ if (mt > latestMtime)
259
+ latestMtime = mt;
260
+ }
261
+ }
262
+ }
263
+ catch { }
264
+ };
265
+ scanRecursive(scanDir);
266
+ let version = '?';
267
+ try {
268
+ version = JSON.parse(fs.readFileSync(path.join(pkgRoot, 'package.json'), 'utf-8')).version;
269
+ }
270
+ catch { }
271
+ console.log(` EvolClaw v${version}`);
272
+ console.log(` 包路径: ${pkgRoot}`);
273
+ console.log(` 安装类型: ${isNpmInstall ? 'npm全局安装' : '开发仓(link)'}`);
274
+ console.log(` CLI执行: ${cliRunsSource ? '源码(tsx)' : '编译产物(dist)'}`);
275
+ console.log(` Daemon执行: ${daemonRunsDist ? '编译产物(dist)' : '未知'}`);
276
+ console.log(` 代码时间: ${latestMtime ? formatLocalTime(latestMtime) : '?'}`);
277
+ }
233
278
  async function cmdStart() {
279
+ const cmdStartedAt = Date.now();
280
+ printStartupInfo();
234
281
  const p = resolvePaths();
235
282
  ensureDataDirs();
236
283
  // 旧配置自动迁移(evolclaw.json → 新结构)
@@ -258,7 +305,7 @@ async function cmdStart() {
258
305
  if (aliveMains.length > 0) {
259
306
  const first = aliveMains[0];
260
307
  console.log(`❌ EvolClaw is already running (PID: ${aliveMains.map(m => m.record.pid).join(', ')})`);
261
- console.log(` 启动于: ${first.record.startedAtIso}`);
308
+ console.log(` 启动于: ${new Date(first.record.startedAtIso).toLocaleString()}`);
262
309
  console.log(` 启动方式: ${first.record.launchedBy}`);
263
310
  // 报告 AID 状态
264
311
  if (status.aidLastActivity.size > 0) {
@@ -315,7 +362,14 @@ async function cmdStart() {
315
362
  const checkReady = () => {
316
363
  // ready signal 出现(优先检查,避免 Windows 上误判进程状态)
317
364
  if (fs.existsSync(p.readySignal)) {
318
- console.log(`✓ EvolClaw started successfully (PID: ${childPid})`);
365
+ const pkg = JSON.parse(fs.readFileSync(path.join(getPackageRoot(), 'package.json'), 'utf-8'));
366
+ let aunVer = 'unknown';
367
+ try {
368
+ const aunPkg = JSON.parse(fs.readFileSync(path.join(getPackageRoot(), 'node_modules', '@agentunion', 'fastaun', 'package.json'), 'utf-8'));
369
+ aunVer = aunPkg.version;
370
+ }
371
+ catch { /* ignore */ }
372
+ console.log(`✓ EvolClaw v${pkg.version} started successfully (PID: ${childPid}) fastaun v${aunVer}`);
319
373
  console.log(` EVOLCLAW_HOME: ${resolveRoot()}`);
320
374
  console.log(` Logs: ${p.logs}/`);
321
375
  // 从主日志提取渠道连接摘要
@@ -358,6 +412,7 @@ async function cmdStart() {
358
412
  if (resolveRoot() === getPackageRoot()) {
359
413
  countLines(getPackageRoot(), p.logs);
360
414
  }
415
+ console.log(`⏱ done in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
361
416
  return;
362
417
  }
363
418
  // 超时
@@ -369,6 +424,7 @@ async function cmdStart() {
369
424
  const content = fs.readFileSync(stdoutLog, 'utf-8').trim().split('\n');
370
425
  console.log(content.slice(-10).map(l => ` ${l}`).join('\n'));
371
426
  }
427
+ console.log(`⏱ failed after ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
372
428
  process.exit(1);
373
429
  return;
374
430
  }
@@ -383,6 +439,7 @@ async function cmdStart() {
383
439
  const content = fs.readFileSync(stdoutLog, 'utf-8').trim().split('\n');
384
440
  console.log(content.slice(-10).map(l => ` ${l}`).join('\n'));
385
441
  }
442
+ console.log(`⏱ failed after ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
386
443
  process.exit(1);
387
444
  return;
388
445
  }
@@ -428,6 +485,8 @@ async function cmdStop() {
428
485
  }
429
486
  }
430
487
  async function cmdRestart(opts = {}) {
488
+ const cmdStartedAt = Date.now();
489
+ printStartupInfo();
431
490
  console.log('🔄 Restarting EvolClaw...');
432
491
  // 版本检查与自动升级
433
492
  console.log('📦 Checking for updates...');
@@ -448,6 +507,18 @@ async function cmdRestart(opts = {}) {
448
507
  console.log(`⚠ Upgrade failed (${upgrade.from} → ${upgrade.to}), continuing with current version`);
449
508
  break;
450
509
  }
510
+ // AUN SDK 版本检查与升级
511
+ const aunUpgrade = await tryUpgradeAunSdk(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG);
512
+ switch (aunUpgrade.status) {
513
+ case 'upgraded':
514
+ console.log(`✅ AUN SDK upgraded: ${aunUpgrade.from} → ${aunUpgrade.to}`);
515
+ break;
516
+ case 'no-update':
517
+ break; // silent
518
+ case 'failed':
519
+ console.log(`⚠ AUN SDK upgrade failed (${aunUpgrade.from} → ${aunUpgrade.to})`);
520
+ break;
521
+ }
451
522
  // 停止所有活 main 进程(可能不止一个)
452
523
  const status = scanInstances();
453
524
  const aliveMains = status.mains.filter(m => m.alive);
@@ -457,20 +528,164 @@ async function cmdRestart(opts = {}) {
457
528
  }
458
529
  await Promise.all(aliveMains.map(m => stopPid(m.record.pid)));
459
530
  await sleep(500);
460
- cleanupInstances();
461
531
  }
462
- // 跨 HOME 孤儿处理:只在 --clear 时主动 kill;
463
- // 否则交给后续 cmdStart() 统一警告,避免重复输出。
464
- if (opts.clear) {
532
+ cleanupInstances();
533
+ // 孤儿处理:同 HOME 的孤儿无条件 kill(restart 必须替换旧实例);
534
+ // 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。
535
+ {
465
536
  const orphans = findOrphanProcesses();
466
- if (orphans.length > 0) {
467
- const killed = killOrphans(orphans);
468
- console.log(`☠ SIGKILL ${killed.length} 个孤儿进程: ${killed.join(', ')}`);
537
+ const currentHome = resolveRoot();
538
+ const sameHome = orphans.filter(o => o.evolclawHome === currentHome);
539
+ const otherHome = orphans.filter(o => o.evolclawHome !== currentHome);
540
+ if (sameHome.length > 0) {
541
+ const killed = killOrphans(sameHome);
542
+ console.log(`☠ 已 SIGKILL ${killed.length} 个同 HOME 孤儿进程: ${killed.join(', ')}`);
543
+ await sleep(500);
544
+ }
545
+ if (opts.clear && otherHome.length > 0) {
546
+ const killed = killOrphans(otherHome);
547
+ console.log(`☠ 已 SIGKILL ${killed.length} 个跨 HOME 孤儿进程: ${killed.join(', ')}`);
469
548
  await sleep(500);
470
549
  }
471
550
  }
551
+ console.log(`⏱ restart prep done in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s, starting...`);
472
552
  setTimeout(() => cmdStart(), 1000);
473
553
  }
554
+ async function cmdDev(args) {
555
+ const pkgRoot = getPackageRoot();
556
+ const isNpmInstall = pkgRoot.includes('node_modules');
557
+ const p = resolvePaths();
558
+ const devMarker = path.join(p.dataDir, 'dev-repo.path');
559
+ const sub = args[0];
560
+ if (!sub) {
561
+ if (!isNpmInstall) {
562
+ console.log(`当前: [dev] ${pkgRoot}`);
563
+ console.log('');
564
+ console.log('断开开发仓链接:');
565
+ console.log(' evolclaw dev off');
566
+ }
567
+ else {
568
+ console.log(`当前: [pkg] ${pkgRoot}`);
569
+ console.log('');
570
+ let devPath = null;
571
+ try {
572
+ devPath = fs.readFileSync(devMarker, 'utf-8').trim();
573
+ }
574
+ catch { }
575
+ if (devPath && fs.existsSync(devPath)) {
576
+ console.log('链接到开发仓:');
577
+ console.log(` evolclaw dev on`);
578
+ console.log(` (已记录路径: ${devPath})`);
579
+ }
580
+ else {
581
+ console.log('链接到开发仓:');
582
+ console.log(' evolclaw dev <开发仓路径>');
583
+ }
584
+ }
585
+ return;
586
+ }
587
+ if (sub === 'off') {
588
+ if (isNpmInstall) {
589
+ console.log('当前已是 [pkg] 模式,无需断开');
590
+ return;
591
+ }
592
+ console.log('🔗 断开开发仓链接...');
593
+ let npmPrefix;
594
+ if (process.platform === 'win32' && process.env.APPDATA) {
595
+ npmPrefix = path.join(process.env.APPDATA, 'npm');
596
+ }
597
+ else {
598
+ npmPrefix = execFileSync('npm', ['prefix', '-g'], { encoding: 'utf-8', shell: true }).trim();
599
+ }
600
+ const linkPath = path.join(npmPrefix, 'node_modules', 'evolclaw');
601
+ const binPath = path.join(npmPrefix, 'evolclaw');
602
+ try {
603
+ fs.rmSync(linkPath, { recursive: true });
604
+ }
605
+ catch { }
606
+ try {
607
+ fs.unlinkSync(binPath);
608
+ }
609
+ catch { }
610
+ try {
611
+ fs.unlinkSync(binPath + '.cmd');
612
+ }
613
+ catch { }
614
+ try {
615
+ fs.unlinkSync(binPath + '.ps1');
616
+ }
617
+ catch { }
618
+ console.log('✓ 已断开');
619
+ console.log(` 已删除: ${linkPath}`);
620
+ console.log(` 如需恢复: evolclaw dev on(需从已安装的 evolclaw 执行)`);
621
+ return;
622
+ }
623
+ if (sub === 'on') {
624
+ if (!isNpmInstall) {
625
+ console.log(`当前已是 [dev] 模式: ${pkgRoot}`);
626
+ return;
627
+ }
628
+ let devPath = null;
629
+ try {
630
+ devPath = fs.readFileSync(devMarker, 'utf-8').trim();
631
+ }
632
+ catch { }
633
+ if (!devPath || !fs.existsSync(devPath)) {
634
+ console.log('未记录开发仓路径');
635
+ console.log('');
636
+ console.log('用法: evolclaw dev <开发仓路径>');
637
+ process.exit(1);
638
+ }
639
+ console.log(`🔗 链接开发仓: ${devPath}`);
640
+ try {
641
+ execFileSync('npm', ['link'], { stdio: 'inherit', cwd: devPath, shell: true });
642
+ console.log(`✓ 已链接 [dev] ${devPath}`);
643
+ }
644
+ catch (e) {
645
+ console.error('❌ npm link 失败:', e.message);
646
+ process.exit(1);
647
+ }
648
+ return;
649
+ }
650
+ // evolclaw dev <path> — 记录路径 + 建立链接
651
+ const devPath = path.resolve(sub);
652
+ const pkgJson = path.join(devPath, 'package.json');
653
+ if (!fs.existsSync(pkgJson)) {
654
+ console.error(`❌ 路径不存在或无 package.json: ${devPath}`);
655
+ process.exit(1);
656
+ }
657
+ let pkg;
658
+ try {
659
+ pkg = JSON.parse(fs.readFileSync(pkgJson, 'utf-8'));
660
+ }
661
+ catch {
662
+ console.error(`❌ 无法解析 package.json: ${pkgJson}`);
663
+ process.exit(1);
664
+ }
665
+ if (pkg.name !== 'evolclaw') {
666
+ console.error(`❌ package.json name 不是 evolclaw(是 "${pkg.name}")`);
667
+ process.exit(1);
668
+ }
669
+ // 已经链接到同一路径,只记录不重复 link
670
+ if (!isNpmInstall && path.resolve(pkgRoot) === devPath) {
671
+ fs.mkdirSync(p.dataDir, { recursive: true });
672
+ fs.writeFileSync(devMarker, devPath, 'utf-8');
673
+ console.log(`✓ 当前已链接到该路径,路径已记录`);
674
+ return;
675
+ }
676
+ console.log(`🔗 链接开发仓: ${devPath}`);
677
+ try {
678
+ execFileSync('npm', ['link'], { stdio: 'inherit', cwd: devPath, shell: true });
679
+ }
680
+ catch (e) {
681
+ console.error('❌ npm link 失败:', e.message);
682
+ process.exit(1);
683
+ }
684
+ fs.mkdirSync(p.dataDir, { recursive: true });
685
+ fs.writeFileSync(devMarker, devPath, 'utf-8');
686
+ console.log(`✓ 已链接 [dev] ${devPath}`);
687
+ console.log(` 路径已记录,下次可用 evolclaw dev on 快速切换`);
688
+ }
474
689
  function formatTimeAgo(ms) {
475
690
  const sec = Math.floor(ms / 1000);
476
691
  if (sec < 60)
@@ -1250,7 +1465,7 @@ async function cmdWatchMenu() {
1250
1465
  await cmdWatchAid();
1251
1466
  }
1252
1467
  else if (chosen === 'msg') {
1253
- const { cmdWatchMsg } = await import('../watch-msg.js');
1468
+ const { cmdWatchMsg } = await import('./watch-msg.js');
1254
1469
  await cmdWatchMsg();
1255
1470
  }
1256
1471
  resolve();
@@ -1348,7 +1563,7 @@ function cmdWatch() {
1348
1563
  }
1349
1564
  const m = aliveMainEntries[0].record;
1350
1565
  const uptime = formatTimeAgo(Date.now() - m.startedAt);
1351
- console.log(`📦 Instance: PID ${m.pid} | 启动于 ${m.startedAtIso} (${uptime}) | via ${m.launchedBy}`);
1566
+ console.log(`📦 Instance: PID ${m.pid} | 启动于 ${new Date(m.startedAtIso).toLocaleString()} (${uptime}) | via ${m.launchedBy}`);
1352
1567
  if (instStatus.aidLastActivity.size > 0) {
1353
1568
  const now = Date.now();
1354
1569
  const aidLines = [];
@@ -1598,6 +1813,11 @@ async function cmdWatchAid() {
1598
1813
  const COL_LRECV = 10;
1599
1814
  const COL_LSENT = 10;
1600
1815
  const COL_PEERS = 5;
1816
+ // 表头跟随系统语言
1817
+ const isChinese = (process.env.LANG || process.env.LC_ALL || process.env.LANGUAGE || Intl.DateTimeFormat().resolvedOptions().locale || '').toLowerCase().includes('zh');
1818
+ const HEADERS = isChinese
1819
+ ? { aid: 'AID', status: '状态', uptime: '运行', state: '工作', reconn: '重连', recv: '收', sent: '发', sys: '系统', bin: '入流量', bout: '出流量', lrecv: '最后收', lsent: '最后发', peers: '对端' }
1820
+ : { aid: 'AID', status: 'STATUS', uptime: 'UPTIME', state: 'STATE', reconn: 'RECONN', recv: 'RECV', sent: 'SENT', sys: 'SYS R/S', bin: 'BYTES IN', bout: 'BYTES OUT', lrecv: 'LAST RECV', lsent: 'LAST SENT', peers: 'PEERS' };
1601
1821
  function formatDuration(ms) {
1602
1822
  const sec = Math.floor(ms / 1000);
1603
1823
  if (sec < 60)
@@ -1615,19 +1835,19 @@ async function cmdWatchAid() {
1615
1835
  }
1616
1836
  function renderHeader() {
1617
1837
  return ' ' +
1618
- padRight('AID', COL_AID) +
1619
- padRight('STATUS', COL_STATUS) +
1620
- padRight('UPTIME', COL_UPTIME) +
1621
- padRight('STATE', COL_STATE) +
1622
- padRight('RECONN', COL_RECONN) +
1623
- padRight('RECV', COL_RECV) +
1624
- padRight('SENT', COL_SENT) +
1625
- padRight('SYS R/S', COL_SYS) +
1626
- padRight('BYTES IN', COL_BIN) +
1627
- padRight('BYTES OUT', COL_BOUT) +
1628
- padRight('LAST RECV', COL_LRECV) +
1629
- padRight('LAST SENT', COL_LSENT) +
1630
- padRight('PEERS', COL_PEERS);
1838
+ padRight(HEADERS.aid, COL_AID) +
1839
+ padRight(HEADERS.status, COL_STATUS) +
1840
+ padRight(HEADERS.uptime, COL_UPTIME) +
1841
+ padRight(HEADERS.state, COL_STATE) +
1842
+ padRight(HEADERS.reconn, COL_RECONN) +
1843
+ padRight(HEADERS.recv, COL_RECV) +
1844
+ padRight(HEADERS.sent, COL_SENT) +
1845
+ padRight(HEADERS.sys, COL_SYS) +
1846
+ padRight(HEADERS.bin, COL_BIN) +
1847
+ padRight(HEADERS.bout, COL_BOUT) +
1848
+ padRight(HEADERS.lrecv, COL_LRECV) +
1849
+ padRight(HEADERS.lsent, COL_LSENT) +
1850
+ padRight(HEADERS.peers, COL_PEERS);
1631
1851
  }
1632
1852
  function renderRow(aid, stats, projectPath) {
1633
1853
  const aidLabel = aid.aid.length > COL_AID - 2 ? aid.aid.slice(0, COL_AID - 4) + '..' : aid.aid;
@@ -1666,6 +1886,13 @@ async function cmdWatchAid() {
1666
1886
  const nameReset = refreshedAids.has(aid.aid) ? '' : RST;
1667
1887
  const BLUE = useColor ? '\x1b[34m' : '';
1668
1888
  const ORANGE = useColor ? '\x1b[38;5;208m' : '';
1889
+ const MAGENTA = useColor ? '\x1b[35m' : '';
1890
+ // 标记生成:[明文/密文|自主/响应](紫色=工具渲染标记)
1891
+ const mkTags = (encrypt, chatmode) => {
1892
+ const enc = encrypt ? '密文' : '明文';
1893
+ const mode = chatmode === 'proactive' ? '自主' : '响应';
1894
+ return `${MAGENTA}[${enc}|${mode}]${RST}`;
1895
+ };
1669
1896
  let msgPreview = '';
1670
1897
  if (stats?.lastReceivedAt || stats?.lastSentAt) {
1671
1898
  const recvTs = stats.lastReceivedAt ?? 0;
@@ -1676,17 +1903,81 @@ async function cmdWatchAid() {
1676
1903
  }
1677
1904
  else if (stats.lastSentText) {
1678
1905
  const toShort = stats.lastSentTo ? stats.lastSentTo.split('.')[0] : '';
1679
- msgPreview = `${BLUE}↑ ${toShort ? `${ORANGE}${toShort}${RST}${BLUE}: ` : ''}${stats.lastSentText.replace(/\n/g, ' ').slice(0, 60)}${RST}`;
1906
+ const tags = mkTags(stats.lastSentEncrypt, stats.lastSentChatmode);
1907
+ // task 进行中时也显示计数(processing > 0 说明还在跑)
1908
+ const isWorking = (stats.processing ?? 0) > 0;
1909
+ const taskEnd = stats?.lastTaskEnd;
1910
+ const counts = isWorking && taskEnd
1911
+ ? `${MAGENTA}[大模型${taskEnd.numTurns}|调用${taskEnd.toolUseCount}|thought${taskEnd.thoughtPutCount}|msg${taskEnd.replyCount}]${RST}`
1912
+ : '';
1913
+ msgPreview = `${BLUE}↑${tags}${counts} ${toShort ? `${ORANGE}${toShort}${RST}${BLUE}: ` : ''}${stats.lastSentText.replace(/\n/g, ' ').slice(0, 60)}${RST}`;
1680
1914
  }
1681
1915
  else if (stats.lastReceivedText) {
1682
1916
  const fromShort = stats.lastReceivedFrom ? stats.lastReceivedFrom.split('.')[0] : '';
1683
1917
  msgPreview = `${GREEN}↓ ${fromShort ? `${ORANGE}${fromShort}${RST}${GREEN}: ` : ''}${stats.lastReceivedText.replace(/\n/g, ' ').slice(0, 60)}${RST}`;
1684
1918
  }
1685
1919
  }
1920
+ // 任务结束状态覆盖:仅当 taskEnd 比最后收发都新时才覆盖
1921
+ const taskEnd = stats?.lastTaskEnd;
1922
+ if (taskEnd && taskEnd.ts >= (stats?.lastSentAt ?? 0) && taskEnd.ts >= (stats?.lastReceivedAt ?? 0)) {
1923
+ const tags = mkTags(taskEnd.encrypt, taskEnd.chatmode);
1924
+ // 计数标记: [大模型N|调用N|thoughtN(streamN)|msgN]
1925
+ const thoughtLabel = taskEnd.thoughtPutCount > 0
1926
+ ? `thought${taskEnd.numTurns}(stream${taskEnd.thoughtPutCount})`
1927
+ : `thought${taskEnd.numTurns}`;
1928
+ const counts = `${MAGENTA}[大模型${taskEnd.numTurns}|调用${taskEnd.toolUseCount}|${thoughtLabel}|msg${taskEnd.replyCount}]${RST}`;
1929
+ if (taskEnd.status === 'error') {
1930
+ msgPreview = `${RED}${tags}${counts} 错误: ${taskEnd.errorType ?? '未知错误'}${RST}`;
1931
+ }
1932
+ else if (taskEnd.sentDuringTask) {
1933
+ // 有 message.send:蓝色加粗 + 内容
1934
+ const toShort = stats?.lastSentTo ? stats.lastSentTo.split('.')[0] : '';
1935
+ const textPreview = stats?.lastSentText ? stats.lastSentText.replace(/\n/g, ' ').slice(0, 60) : '';
1936
+ msgPreview = `${BOLD}${BLUE}↑${tags}${counts} ${toShort ? `${ORANGE}${toShort}${RST}${BOLD}${BLUE}: ` : ''}${textPreview}${RST}`;
1937
+ }
1938
+ else if (taskEnd.thoughtDuringTask) {
1939
+ // 只有 thought:普通蓝色 + thought 内容
1940
+ const textPreview = taskEnd.lastThoughtText
1941
+ ? taskEnd.lastThoughtText.replace(/\n/g, ' ').slice(0, 60)
1942
+ : (taskEnd.finalText ? taskEnd.finalText.replace(/\n/g, ' ').slice(0, 60) : '');
1943
+ msgPreview = `${BLUE}↑${tags}${counts} ${textPreview}${RST}`;
1944
+ }
1945
+ else {
1946
+ // 既没 send 也没 thought
1947
+ const textPreview = taskEnd.finalText
1948
+ ? taskEnd.finalText.replace(/\n/g, ' ').slice(0, 60)
1949
+ : '(无输出)';
1950
+ msgPreview = `${ORANGE}${tags}${counts} ${textPreview}${RST}`;
1951
+ }
1952
+ }
1686
1953
  const subLine1 = ` ${nameColor}${namePart}${nameReset}${msgPreview ? ' ' + msgPreview : ''}`;
1687
1954
  const dirLabel = projectPath || '—';
1688
1955
  const subLine2 = `${DIM} ${dirLabel}${RST}`;
1689
- return [mainLine, subLine1, subLine2];
1956
+ const result = [mainLine, subLine1, subLine2];
1957
+ if (aid.status === 'failed' || aid.status === 'kicked' || aid.status === 'kicked_no_retry') {
1958
+ const parts = [];
1959
+ if (aid.lastAttemptAt) {
1960
+ const d = new Date(aid.lastAttemptAt);
1961
+ const ts = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`;
1962
+ parts.push(`last_attempt=${ts}`);
1963
+ }
1964
+ if (aid.kickDetail?.code) {
1965
+ parts.push(`code=${aid.kickDetail.code}`);
1966
+ }
1967
+ if (aid.kickDetail?.reason) {
1968
+ parts.push(`reason=${aid.kickDetail.reason}`);
1969
+ }
1970
+ if (aid.lastError) {
1971
+ parts.push(`error=${aid.lastError}`);
1972
+ }
1973
+ if (aid.gatewayUrl) {
1974
+ parts.push(`gateway=${aid.gatewayUrl}`);
1975
+ }
1976
+ if (parts.length > 0) {
1977
+ result.push(`${RED} ⚠ ${parts.join(' ')}${RST}`);
1978
+ }
1979
+ }
1980
+ return result;
1690
1981
  }
1691
1982
  let lastLineCount = 0;
1692
1983
  async function render() {
@@ -1905,6 +2196,19 @@ async function cmdRestartMonitor() {
1905
2196
  await notifyChannel(p, pendingInfo, `⚠️ 升级失败,使用当前版本继续`, log);
1906
2197
  break;
1907
2198
  }
2199
+ // AUN SDK 版本检查与升级
2200
+ const aunUpgrade = await tryUpgradeAunSdk(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG);
2201
+ switch (aunUpgrade.status) {
2202
+ case 'upgraded':
2203
+ log(`✅ AUN SDK upgraded: ${aunUpgrade.from} → ${aunUpgrade.to}`);
2204
+ await notifyChannel(p, pendingInfo, `📦 AUN SDK 已升级 ${aunUpgrade.from} → ${aunUpgrade.to}`, log);
2205
+ break;
2206
+ case 'no-update':
2207
+ break;
2208
+ case 'failed':
2209
+ log(`⚠ AUN SDK upgrade failed (${aunUpgrade.from} → ${aunUpgrade.to}): ${aunUpgrade.error}`);
2210
+ break;
2211
+ }
1908
2212
  // 启动并检测 ready signal
1909
2213
  let started = await spawnAndWaitReady(p, log, READY_TIMEOUT);
1910
2214
  if (started) {
@@ -2486,7 +2790,7 @@ async function cmdCtl(args) {
2486
2790
  async function cmdAgent(args) {
2487
2791
  const sub = args[0];
2488
2792
  const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
2489
- if (sub === 'help') {
2793
+ if (!sub || sub === 'help' || sub === '--help' || sub === '-h' || args.includes('--help') || args.includes('-h')) {
2490
2794
  console.log(`用法: evolclaw agent <command>
2491
2795
 
2492
2796
  Commands:
@@ -2538,17 +2842,43 @@ Options:
2538
2842
  console.log('No agents configured.');
2539
2843
  return;
2540
2844
  }
2541
- console.log('NAME'.padEnd(14) + 'STATUS'.padEnd(10) + 'CHANNELS'.padEnd(24) +
2542
- 'PROJECT'.padEnd(22) + 'BASEAGENT'.padEnd(11) + 'LAST ACTIVE');
2845
+ // 表头跟随系统语言
2846
+ const isChinese = (process.env.LANG || process.env.LC_ALL || process.env.LANGUAGE || Intl.DateTimeFormat().resolvedOptions().locale || '').toLowerCase().includes('zh');
2847
+ const headers = isChinese
2848
+ ? { name: '名称', status: '状态', channels: '渠道', project: '项目', baseagent: '基座', lastActive: '最后活跃' }
2849
+ : { name: 'NAME', status: 'STATUS', channels: 'CHANNELS', project: 'PROJECT', baseagent: 'BASEAGENT', lastActive: 'LAST ACTIVE' };
2850
+ // 计算各列实际需要的宽度
2851
+ let maxNameLen = headers.name.length;
2852
+ let maxStatusLen = headers.status.length;
2853
+ let maxChannelsLen = headers.channels.length;
2854
+ let maxProjectLen = headers.project.length;
2855
+ let maxBaseagentLen = headers.baseagent.length;
2856
+ for (const info of result.agents) {
2857
+ maxNameLen = Math.max(maxNameLen, info.name.length);
2858
+ maxStatusLen = Math.max(maxStatusLen, (info.status || 'stopped').length);
2859
+ const channelsStr = info.channels?.length > 0 ? info.channels.join(', ') : '—';
2860
+ maxChannelsLen = Math.max(maxChannelsLen, channelsStr.length);
2861
+ const projectStr = info.projectPath ? path.basename(info.projectPath) : '—';
2862
+ maxProjectLen = Math.max(maxProjectLen, projectStr.length);
2863
+ maxBaseagentLen = Math.max(maxBaseagentLen, (info.baseagent || '—').length);
2864
+ }
2865
+ // 加 2 作为列间距
2866
+ const colName = maxNameLen + 2;
2867
+ const colStatus = maxStatusLen + 2;
2868
+ const colChannels = maxChannelsLen + 1;
2869
+ const colProject = maxProjectLen + 2;
2870
+ const colBaseagent = maxBaseagentLen + 2;
2871
+ console.log(headers.name.padEnd(colName) + headers.status.padEnd(colStatus) + headers.channels.padEnd(colChannels) +
2872
+ headers.project.padEnd(colProject) + headers.baseagent.padEnd(colBaseagent) + headers.lastActive);
2543
2873
  for (const info of result.agents) {
2544
2874
  const name = info.name;
2545
2875
  const status = info.status || 'stopped';
2546
- const channels = info.channels?.length > 0 ? info.channels.join(', ').slice(0, 22) : '—';
2876
+ const channels = info.channels?.length > 0 ? info.channels.join(', ') : '—';
2547
2877
  const project = info.projectPath ? path.basename(info.projectPath) : '—';
2548
2878
  const baseagent = info.baseagent || '—';
2549
2879
  const lastActive = info.lastActivity ? formatTimeAgo(Date.now() - info.lastActivity) : '—';
2550
- console.log(name.padEnd(14) + status.padEnd(10) + channels.padEnd(24) +
2551
- project.padEnd(22) + baseagent.padEnd(11) + lastActive);
2880
+ console.log(name.padEnd(colName) + status.padEnd(colStatus) + channels.padEnd(colChannels) +
2881
+ project.padEnd(colProject) + baseagent.padEnd(colBaseagent) + lastActive);
2552
2882
  }
2553
2883
  return;
2554
2884
  }
@@ -2949,7 +3279,7 @@ async function cmdAid(args) {
2949
3279
  const sub = args[0] || 'list';
2950
3280
  const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
2951
3281
  const aunPath = resolveAunPath(args);
2952
- if (sub === 'help') {
3282
+ if (!sub || sub === 'help' || sub === '--help' || sub === '-h' || args.includes('--help') || args.includes('-h')) {
2953
3283
  console.log(`用法: evolclaw aid <command>
2954
3284
 
2955
3285
  Commands:
@@ -3495,7 +3825,8 @@ Options:
3495
3825
  }
3496
3826
  body = { mode: 'text', text };
3497
3827
  }
3498
- const result = await msgSend({ from, to, body, ...commonOpts });
3828
+ const encrypt = args.includes('--encrypt');
3829
+ const result = await msgSend({ from, to, body, encrypt, ...commonOpts });
3499
3830
  if (!result.ok) {
3500
3831
  if (formatJson) {
3501
3832
  console.log(JSON.stringify(result));
@@ -3789,7 +4120,8 @@ Options:
3789
4120
  body = { mode: 'text', text };
3790
4121
  }
3791
4122
  const mentions = collectMentions();
3792
- const result = await groupSend({ from, groupId, body, mentions: mentions.length ? mentions : undefined, ...commonOpts });
4123
+ const encryptGroup = args.includes('--encrypt');
4124
+ const result = await groupSend({ from, groupId, body, mentions: mentions.length ? mentions : undefined, encrypt: encryptGroup, ...commonOpts });
3793
4125
  outputResult(result, () => {
3794
4126
  const r = result;
3795
4127
  console.log(`✓ 已发送 message_id=${r.message?.message_id ?? '-'} seq=${r.message?.seq ?? '-'}`);
@@ -4125,7 +4457,26 @@ export async function main(args) {
4125
4457
  await cmdWatchAid();
4126
4458
  }
4127
4459
  else if (args[1] === 'msg') {
4128
- const { cmdWatchMsg } = await import('../watch-msg.js');
4460
+ if (args[2] === '--help' || args[2] === '-h' || args[2] === 'help') {
4461
+ console.log(`用法: evolclaw watch msg
4462
+
4463
+ 三面板交互式消息监控 TUI。
4464
+
4465
+ 面板:
4466
+ 左 (Scope) 本地 AID 列表,显示收发统计和对端数量
4467
+ 中 (Stats) 选中 AID 的对端列表(默认 All),显示 per-peer 收发数
4468
+ 右 (Messages) 消息流,带滚动条
4469
+
4470
+ 操作:
4471
+ ↑↓ 当前面板内导航
4472
+ ←→ / Tab 切换面板
4473
+ Enter 选中 AID / 选中对端
4474
+ Backspace 返回上一级
4475
+ Page Up/Down 消息滚动
4476
+ ESC 退出`);
4477
+ break;
4478
+ }
4479
+ const { cmdWatchMsg } = await import('./watch-msg.js');
4129
4480
  await cmdWatchMsg();
4130
4481
  }
4131
4482
  else if (args[1] === 'log') {
@@ -4141,12 +4492,20 @@ export async function main(args) {
4141
4492
  case 'restart-monitor':
4142
4493
  await cmdRestartMonitor();
4143
4494
  break;
4495
+ case 'dev':
4496
+ await cmdDev(args.slice(1));
4497
+ break;
4144
4498
  case 'mv':
4145
4499
  await cmdMv(args[1], args[2]);
4146
4500
  break;
4147
4501
  case 'diagnose':
4148
4502
  await cmdDiagnose();
4149
4503
  break;
4504
+ case 'net': {
4505
+ const { cmdNet } = await import('./net-check.js');
4506
+ await cmdNet(args.slice(1));
4507
+ break;
4508
+ }
4150
4509
  case 'ctl':
4151
4510
  await cmdCtl(args.slice(1));
4152
4511
  break;
@@ -4183,8 +4542,20 @@ export async function main(args) {
4183
4542
  await cmdGroup(args.slice(1));
4184
4543
  break;
4185
4544
  }
4545
+ case 'bench': {
4546
+ const { suppressSdkLogs } = await import('../aun/aid/index.js');
4547
+ suppressSdkLogs();
4548
+ const { cmdBench } = await import('./bench.js');
4549
+ await cmdBench(args.slice(1));
4550
+ break;
4551
+ }
4552
+ case 'link-rules': {
4553
+ const { cmdLinkRules } = await import('./link-rules.js');
4554
+ cmdLinkRules(args.slice(1));
4555
+ break;
4556
+ }
4186
4557
  default:
4187
- console.log(`Usage: evolclaw {init|start|stop|restart|status|logs|watch|ctl|diagnose|mv}
4558
+ console.log(`Usage: evolclaw {init|start|stop|restart|status|logs|watch|ctl|diagnose|net|mv}
4188
4559
 
4189
4560
  Commands:
4190
4561
  init 初始化 evolclaw home (${resolvePaths().defaultsConfig})
@@ -4202,8 +4573,10 @@ Commands:
4202
4573
  --level error|warn 只显示指定级别及以上
4203
4574
  --module <name> 只显示指定模块(如 feishu、AgentRunner)
4204
4575
  --raw 原始输出,不着色
4205
- watch 监控 logs/ 下所有 .log 文件(汇总实时输出,启动时显示最近 20 条)
4576
+ watch 监控面板选择菜单(↑↓ 选择 log/aid/msg)
4577
+ watch log 监控 logs/ 下所有 .log 文件(汇总实时输出,启动时显示最近 20 条)
4206
4578
  watch aid AID 连接状态实时监控(显示各 AID 在线/离线/重连状态)
4579
+ watch msg 消息监控(三面板交互式 TUI:AID 列表 / 对端统计 / 消息流)
4207
4580
  ctl 运行时自管理(模型切换、推理强度、压缩上下文等)
4208
4581
  evolclaw ctl help 查看完整命令列表
4209
4582
  agent 管理 EvolAgent
@@ -4228,6 +4601,9 @@ Commands:
4228
4601
  aid lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
4229
4602
  aid agentmd put <aid> 签名并上传 agent.md
4230
4603
  aid agentmd get <aid> 下载并验签 agent.md
4604
+ net 网络链路诊断
4605
+ net check [<aid>] 10 步链路检测(DNS→Discovery→TCP→TLS→WSS→Auth→Ping→Echo)
4606
+ net help 查看详细帮助
4231
4607
  rpc AUN RPC 调用
4232
4608
  rpc --as <aid> --params <json|jsonl|file>
4233
4609
  storage 文件存储
@@ -4238,6 +4614,8 @@ Commands:
4238
4614
  storage quota <aid>
4239
4615
  diagnose 诊断启动环境(配置、数据库、进程)
4240
4616
  mv <old> <new> 迁移项目目录(保留 Claude/Codex/EvolClaw 会话)
4617
+ bench AUN 消息性能基准测试
4618
+ bench --aids 5 --rounds 10 --concurrency 5
4241
4619
 
4242
4620
  Environment:
4243
4621
  EVOLCLAW_HOME 数据目录 (默认: ~/.evolclaw)