evolclaw 2.8.3 → 3.1.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.
Files changed (142) hide show
  1. package/README.md +21 -12
  2. package/bin/ec.js +29 -0
  3. package/dist/agents/baseagent-normalize.js +19 -0
  4. package/dist/agents/claude-runner.js +108 -46
  5. package/dist/agents/codex-runner.js +13 -14
  6. package/dist/agents/gemini-runner.js +15 -17
  7. package/dist/agents/kit-renderer.js +281 -0
  8. package/dist/agents/resolve.js +134 -0
  9. package/dist/aun/aid/agentmd.js +186 -0
  10. package/dist/aun/aid/client.js +134 -0
  11. package/dist/aun/aid/identity.js +159 -0
  12. package/dist/aun/aid/index.js +3 -0
  13. package/dist/aun/aid/lifecycle-log.js +33 -0
  14. package/dist/aun/aid/types.js +1 -0
  15. package/dist/aun/aid/validation.js +21 -0
  16. package/dist/aun/msg/group.js +293 -0
  17. package/dist/aun/msg/index.js +4 -0
  18. package/dist/aun/msg/p2p.js +147 -0
  19. package/dist/aun/msg/payload-type.js +27 -0
  20. package/dist/aun/msg/upload.js +98 -0
  21. package/dist/aun/outbox.js +138 -0
  22. package/dist/aun/rpc/caller.js +42 -0
  23. package/dist/aun/rpc/connection.js +34 -0
  24. package/dist/aun/rpc/index.js +2 -0
  25. package/dist/aun/storage/download.js +29 -0
  26. package/dist/aun/storage/index.js +3 -0
  27. package/dist/aun/storage/manage.js +10 -0
  28. package/dist/aun/storage/upload.js +35 -0
  29. package/dist/channels/aun.js +1340 -349
  30. package/dist/channels/dingtalk.js +59 -5
  31. package/dist/channels/feishu.js +381 -32
  32. package/dist/channels/qqbot.js +68 -12
  33. package/dist/channels/wechat.js +63 -4
  34. package/dist/channels/wecom.js +59 -5
  35. package/dist/cli/agent.js +800 -0
  36. package/dist/cli/bench.js +1219 -0
  37. package/dist/cli/index.js +4513 -0
  38. package/dist/{utils → cli}/init-channel.js +211 -621
  39. package/dist/cli/init.js +178 -0
  40. package/dist/cli/link-rules.js +245 -0
  41. package/dist/cli/net-check.js +640 -0
  42. package/dist/cli/watch-msg.js +589 -0
  43. package/dist/config-store.js +645 -0
  44. package/dist/core/{agent-loader.js → baseagent-loader.js} +6 -12
  45. package/dist/core/channel-loader.js +176 -12
  46. package/dist/core/command-handler.js +883 -848
  47. package/dist/core/evolagent-registry.js +191 -371
  48. package/dist/core/evolagent.js +202 -238
  49. package/dist/core/interaction-router.js +52 -5
  50. package/dist/core/message/im-renderer.js +486 -0
  51. package/dist/core/message/items-formatter.js +68 -0
  52. package/dist/core/message/message-bridge.js +109 -56
  53. package/dist/core/message/message-log.js +93 -0
  54. package/dist/core/message/message-processor.js +430 -212
  55. package/dist/core/message/message-queue.js +13 -6
  56. package/dist/core/permission.js +116 -11
  57. package/dist/core/session/adapters/codex-session-file-adapter.js +24 -2
  58. package/dist/core/session/session-fs-store.js +230 -0
  59. package/dist/core/session/session-manager.js +740 -777
  60. package/dist/core/session/session-mapper.js +87 -0
  61. package/dist/core/trigger/manager.js +122 -0
  62. package/dist/core/trigger/parser.js +128 -0
  63. package/dist/core/trigger/scheduler.js +224 -0
  64. package/dist/data/error-dict.json +118 -0
  65. package/dist/eck/baseagent-caps.js +18 -0
  66. package/dist/eck/detect.js +47 -0
  67. package/dist/eck/init.js +77 -0
  68. package/dist/eck/rules-loader.js +28 -0
  69. package/dist/index.js +560 -283
  70. package/dist/ipc.js +49 -0
  71. package/dist/net-check.js +640 -0
  72. package/dist/paths.js +73 -9
  73. package/dist/types.js +8 -2
  74. package/dist/utils/aid-lifecycle-log.js +33 -0
  75. package/dist/utils/atomic-write.js +89 -0
  76. package/dist/utils/channel-helpers.js +46 -0
  77. package/dist/utils/cross-platform.js +17 -26
  78. package/dist/utils/error-utils.js +10 -2
  79. package/dist/utils/instance-registry.js +434 -0
  80. package/dist/utils/log-writer.js +217 -0
  81. package/dist/utils/logger.js +34 -77
  82. package/dist/utils/media-cache.js +23 -0
  83. package/dist/utils/npm-ops.js +163 -0
  84. package/dist/utils/process-introspect.js +122 -0
  85. package/dist/utils/stats.js +192 -0
  86. package/dist/watch-msg.js +544 -0
  87. package/evolclaw-install-aun.md +127 -47
  88. package/kits/docs/GUIDE.md +20 -0
  89. package/kits/docs/INDEX.md +52 -0
  90. package/kits/docs/aun/CHEATSHEET.md +17 -0
  91. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  92. package/kits/docs/channels/aun.md +25 -0
  93. package/kits/docs/channels/feishu.md +27 -0
  94. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  95. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  96. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  97. package/kits/docs/eck_templates/runtime.template.md +19 -0
  98. package/kits/docs/evolclaw/AGENT_CMD.md +31 -0
  99. package/kits/docs/evolclaw/MSG_GROUP.md +30 -0
  100. package/kits/docs/evolclaw/MSG_PRIVATE.md +25 -0
  101. package/kits/docs/evolclaw/self-summary.md +29 -0
  102. package/kits/docs/evolclaw/tools.md +25 -0
  103. package/kits/docs/identity/AID_PROFILE_SPEC.md +27 -0
  104. package/kits/docs/identity/PATH_OPS.md +16 -0
  105. package/kits/docs/identity/ROLE_DETAIL.md +20 -0
  106. package/kits/docs/identity/identity-tools.md +26 -0
  107. package/kits/docs/path-registry.md +43 -0
  108. package/kits/eck_manifest.json +95 -0
  109. package/kits/rules/01-overview.md +120 -0
  110. package/kits/rules/02-navigation.md +75 -0
  111. package/kits/rules/03-identity.md +34 -0
  112. package/kits/rules/04-relation.md +49 -0
  113. package/kits/rules/05-venue.md +45 -0
  114. package/kits/rules/06-channel.md +43 -0
  115. package/kits/templates/system-fragments/baseagent.md +2 -0
  116. package/kits/templates/system-fragments/channel.md +10 -0
  117. package/kits/templates/system-fragments/identity.md +12 -0
  118. package/kits/templates/system-fragments/relation.md +9 -0
  119. package/kits/templates/system-fragments/runtime.md +19 -0
  120. package/kits/templates/system-fragments/venue.md +5 -0
  121. package/package.json +10 -6
  122. package/data/evolclaw.sample.json +0 -60
  123. package/dist/agents/templates.js +0 -122
  124. package/dist/channels/aun-ops.js +0 -275
  125. package/dist/cli.js +0 -2178
  126. package/dist/config.js +0 -591
  127. package/dist/core/agent-registry.js +0 -450
  128. package/dist/core/evolagent-schema.js +0 -72
  129. package/dist/core/message/stream-flusher.js +0 -238
  130. package/dist/core/message/thought-emitter.js +0 -162
  131. package/dist/core/reload-hooks.js +0 -87
  132. package/dist/prompts/templates.js +0 -122
  133. package/dist/templates/prompts.md +0 -104
  134. package/dist/templates/skills.md +0 -66
  135. package/dist/utils/channel-fingerprint.js +0 -59
  136. package/dist/utils/error-dict.js +0 -63
  137. package/dist/utils/format.js +0 -32
  138. package/dist/utils/init.js +0 -645
  139. package/dist/utils/migrate-project.js +0 -122
  140. package/dist/utils/reload-hooks.js +0 -87
  141. package/dist/utils/stats-collector.js +0 -99
  142. package/dist/utils/upgrade.js +0 -100
@@ -1,7 +1,8 @@
1
1
  import { logger } from '../utils/logger.js';
2
2
  import { markdownToPlainText } from '../utils/rich-content-renderer.js';
3
- import { requireOptional } from '../utils/init-channel.js';
4
- import { normalizeChannelInstances, getChannelShowActivities } from '../config.js';
3
+ import { requireOptional } from '../utils/npm-ops.js';
4
+ import { normalizeChannelInstances, getChannelShowActivities } from '../utils/channel-helpers.js';
5
+ import { formatItemsAsText } from '../core/message/items-formatter.js';
5
6
  // ── QQBotChannel ────────────────────────────────────────────────────────────
6
7
  export class QQBotChannel {
7
8
  config;
@@ -245,11 +246,11 @@ export class QQBotChannel {
245
246
  async sendImage(chatId, png) {
246
247
  if (!this.client)
247
248
  return;
249
+ const fs = await import('fs');
250
+ const path = await import('path');
251
+ const os = await import('os');
252
+ const tmpPath = path.join(os.tmpdir(), `evolclaw-qqbot-${Date.now()}.png`);
248
253
  try {
249
- const fs = await import('fs');
250
- const path = await import('path');
251
- const os = await import('os');
252
- const tmpPath = path.join(os.tmpdir(), `evolclaw-qqbot-${Date.now()}.png`);
253
254
  fs.writeFileSync(tmpPath, png);
254
255
  const chatType = this.chatTypeCache.get(chatId);
255
256
  const msgId = this.msgIdCache.get(chatId);
@@ -260,14 +261,16 @@ export class QQBotChannel {
260
261
  else {
261
262
  await this.client.sendPrivateImage(chatId, `file://${tmpPath}`, msgId);
262
263
  }
264
+ }
265
+ catch (error) {
266
+ logger.error(`[QQBot] sendImage failed for ${chatId}:`, error?.message || error);
267
+ }
268
+ finally {
263
269
  try {
264
270
  fs.unlinkSync(tmpPath);
265
271
  }
266
272
  catch { /* ignore */ }
267
273
  }
268
- catch (error) {
269
- logger.error(`[QQBot] sendImage failed for ${chatId}:`, error?.message || error);
270
- }
271
274
  }
272
275
  // ── Outbound: file ─────────────────────────────────────────────────────────
273
276
  async sendFile(chatId, filePath) {
@@ -331,9 +334,47 @@ export class QQBotChannelPlugin {
331
334
  });
332
335
  const adapter = {
333
336
  channelName: inst.name,
334
- sendText: (id, text) => channel.sendMessage(id, text),
335
- sendFile: (id, filePath) => channel.sendFile(id, filePath),
336
- sendImage: (id, png) => channel.sendImage(id, png),
337
+ capabilities: { file: true, image: true, interaction: false, markdown: true, thought: false, status: false },
338
+ send: async (envelope, payload) => {
339
+ const ctx = envelope.replyContext;
340
+ const channelId = envelope.channelId;
341
+ switch (payload.kind) {
342
+ case 'result.text':
343
+ case 'command.result':
344
+ case 'command.error':
345
+ case 'system.notice':
346
+ case 'system.error':
347
+ case 'result.error':
348
+ await channel.sendMessage(channelId, payload.text);
349
+ return;
350
+ case 'result.file':
351
+ await channel.sendFile(channelId, payload.filePath);
352
+ return;
353
+ case 'result.image':
354
+ await channel.sendImage(channelId, payload.data);
355
+ return;
356
+ case 'activity.batch': {
357
+ const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
358
+ const text = formatItemsAsText(filtered);
359
+ if (text)
360
+ await channel.sendMessage(channelId, text);
361
+ return;
362
+ }
363
+ case 'interaction':
364
+ if (payload.fallbackText)
365
+ await channel.sendMessage(channelId, payload.fallbackText);
366
+ return;
367
+ case 'status.started':
368
+ case 'status.completed':
369
+ case 'status.interrupted':
370
+ case 'status.error':
371
+ case 'status.timeout':
372
+ case 'custom':
373
+ return;
374
+ default:
375
+ logger.warn(`[QQBot] Unhandled payload kind: ${payload.kind}`);
376
+ }
377
+ },
337
378
  };
338
379
  const policy = {
339
380
  canSwitchProject: (_chatType, identity) => identity === 'owner' || identity === 'admin',
@@ -378,6 +419,21 @@ export class QQBotChannelPlugin {
378
419
  connect: () => channel.connect(),
379
420
  disconnect: () => channel.disconnect(),
380
421
  onProjectPathRequest: () => Promise.resolve(config.projects?.defaultPath || process.cwd()),
422
+ registerBridge(bridge, channelType) {
423
+ bridge.register(adapter.channelName, (handler) => channel.onMessage(async (event) => {
424
+ handler({
425
+ channel: adapter.channelName,
426
+ channelType,
427
+ channelId: event.channelId,
428
+ content: event.content,
429
+ images: event.images,
430
+ chatType: event.chatType || 'private',
431
+ peerId: event.peerId || '',
432
+ peerName: event.peerName,
433
+ messageId: event.messageId,
434
+ });
435
+ }), (channelId, text) => channel.sendMessage(channelId, text), adapter, channelType);
436
+ },
381
437
  });
382
438
  }
383
439
  return result;
@@ -5,6 +5,7 @@ import { resolvePaths } from '../paths.js';
5
5
  import { logger } from '../utils/logger.js';
6
6
  import { sanitizeFileName, saveToUploads, safeFetch } from '../utils/media-cache.js';
7
7
  import { markdownToPlainText } from '../utils/rich-content-renderer.js';
8
+ import { formatItemsAsText } from '../core/message/items-formatter.js';
8
9
  const CHANNEL_VERSION = '1.0.0';
9
10
  const ILINK_APP_ID = 'bot';
10
11
  // iLink-App-ClientVersion: major<<16 | minor<<8 | patch (uint32)
@@ -382,7 +383,7 @@ export class WechatChannel {
382
383
  const authMsg = `⚠️ 微信 token 已过期,通道暂停 ${pauseMin} 分钟后自动重试。\n如需立即恢复,请运行: evolclaw init wechat`;
383
384
  if (this.eventBus) {
384
385
  this.eventBus.publish({
385
- type: 'channel:health',
386
+ type: 'channel:error',
386
387
  channel: 'wechat',
387
388
  status: 'auth_error',
388
389
  message: authMsg,
@@ -705,7 +706,7 @@ export class WechatChannel {
705
706
  });
706
707
  }
707
708
  }
708
- import { normalizeChannelInstances, getChannelShowActivities } from '../config.js';
709
+ import { normalizeChannelInstances, getChannelShowActivities } from '../utils/channel-helpers.js';
709
710
  export class WechatChannelPlugin {
710
711
  name = 'wechat';
711
712
  isEnabled(config) {
@@ -729,8 +730,48 @@ export class WechatChannelPlugin {
729
730
  });
730
731
  const adapter = {
731
732
  channelName: inst.name,
732
- sendText: (id, text) => channel.sendMessage(id, text),
733
- sendFile: (id, filePath) => channel.sendFile(id, filePath),
733
+ capabilities: { file: false, image: false, interaction: false, markdown: false, thought: false, status: true },
734
+ send: async (envelope, payload) => {
735
+ const channelId = envelope.channelId;
736
+ switch (payload.kind) {
737
+ case 'result.text':
738
+ case 'command.result':
739
+ case 'command.error':
740
+ case 'system.notice':
741
+ case 'system.error':
742
+ case 'result.error':
743
+ await channel.sendMessage(channelId, payload.text);
744
+ return;
745
+ case 'result.file': {
746
+ const name = payload.fileName || payload.filePath;
747
+ await channel.sendMessage(channelId, `\ud83d\udcce \u6587\u4ef6\u5df2\u751f\u6210\uff1a${name}\n\u8def\u5f84\uff1a${payload.filePath}`);
748
+ return;
749
+ }
750
+ case 'result.image':
751
+ return;
752
+ case 'activity.batch': {
753
+ // WeChat 不发送成功的 tool_result
754
+ const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
755
+ const text = formatItemsAsText(filtered);
756
+ if (text)
757
+ await channel.sendMessage(channelId, text);
758
+ return;
759
+ }
760
+ case 'interaction':
761
+ if (payload.fallbackText)
762
+ await channel.sendMessage(channelId, payload.fallbackText);
763
+ return;
764
+ case 'status.started':
765
+ case 'status.completed':
766
+ case 'status.interrupted':
767
+ case 'status.error':
768
+ case 'status.timeout':
769
+ case 'custom':
770
+ return;
771
+ default:
772
+ logger.warn(`[WeChat] Unhandled payload kind: ${payload.kind}`);
773
+ }
774
+ },
734
775
  };
735
776
  const policy = {
736
777
  canSwitchProject: (chatType, identity) => identity === 'owner' || identity === 'admin',
@@ -774,6 +815,24 @@ export class WechatChannelPlugin {
774
815
  connect: () => channel.connect(),
775
816
  disconnect: () => channel.disconnect(),
776
817
  onProjectPathRequest: (channelId) => Promise.resolve(config.projects?.defaultPath || process.cwd()),
818
+ registerBridge(bridge, channelType) {
819
+ bridge.register(adapter.channelName, (handler) => channel.onMessage(async (channelId, content, peerId, images, chatType) => {
820
+ await handler({
821
+ channel: adapter.channelName,
822
+ channelType,
823
+ channelId,
824
+ content,
825
+ images,
826
+ chatType: chatType || 'private',
827
+ peerId: peerId || '',
828
+ });
829
+ }), (channelId, text) => channel.sendMessage(channelId, text), adapter, channelType);
830
+ },
831
+ registerHooks(ctx) {
832
+ if (channel.setEventBus) {
833
+ channel.setEventBus(ctx.eventBus);
834
+ }
835
+ },
777
836
  });
778
837
  }
779
838
  return result;
@@ -1,7 +1,8 @@
1
1
  import crypto from 'node:crypto';
2
2
  import { logger } from '../utils/logger.js';
3
- import { requireOptional } from '../utils/init-channel.js';
4
- import { normalizeChannelInstances, getChannelShowActivities } from '../config.js';
3
+ import { requireOptional } from '../utils/npm-ops.js';
4
+ import { normalizeChannelInstances, getChannelShowActivities } from '../utils/channel-helpers.js';
5
+ import { formatItemsAsText } from '../core/message/items-formatter.js';
5
6
  // ── WecomChannel ───────────────────────────────────────────────────────────────
6
7
  export class WecomChannel {
7
8
  config;
@@ -489,9 +490,47 @@ export class WecomChannelPlugin {
489
490
  });
490
491
  const adapter = {
491
492
  channelName: inst.name,
492
- sendText: (id, text) => channel.sendMessage(id, text),
493
- sendFile: (id, filePath) => channel.sendFile(id, filePath),
494
- sendImage: (id, png) => channel.sendImage(id, png),
493
+ capabilities: { file: true, image: true, interaction: false, markdown: true, thought: false, status: false },
494
+ send: async (envelope, payload) => {
495
+ const ctx = envelope.replyContext;
496
+ const channelId = envelope.channelId;
497
+ switch (payload.kind) {
498
+ case 'result.text':
499
+ case 'command.result':
500
+ case 'command.error':
501
+ case 'system.notice':
502
+ case 'system.error':
503
+ case 'result.error':
504
+ await channel.sendMessage(channelId, payload.text);
505
+ return;
506
+ case 'result.file':
507
+ await channel.sendFile(channelId, payload.filePath);
508
+ return;
509
+ case 'result.image':
510
+ await channel.sendImage(channelId, payload.data);
511
+ return;
512
+ case 'activity.batch': {
513
+ const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
514
+ const text = formatItemsAsText(filtered);
515
+ if (text)
516
+ await channel.sendMessage(channelId, text);
517
+ return;
518
+ }
519
+ case 'interaction':
520
+ if (payload.fallbackText)
521
+ await channel.sendMessage(channelId, payload.fallbackText);
522
+ return;
523
+ case 'status.started':
524
+ case 'status.completed':
525
+ case 'status.interrupted':
526
+ case 'status.error':
527
+ case 'status.timeout':
528
+ case 'custom':
529
+ return;
530
+ default:
531
+ logger.warn(`[WeCom] Unhandled payload kind: ${payload.kind}`);
532
+ }
533
+ },
495
534
  };
496
535
  const policy = {
497
536
  canSwitchProject: (_chatType, identity) => identity === 'owner' || identity === 'admin',
@@ -536,6 +575,21 @@ export class WecomChannelPlugin {
536
575
  connect: () => channel.connect(),
537
576
  disconnect: () => channel.disconnect(),
538
577
  onProjectPathRequest: () => Promise.resolve(config.projects?.defaultPath || process.cwd()),
578
+ registerBridge(bridge, channelType) {
579
+ bridge.register(adapter.channelName, (handler) => channel.onMessage(async (event) => {
580
+ handler({
581
+ channel: adapter.channelName,
582
+ channelType,
583
+ channelId: event.channelId,
584
+ content: event.content,
585
+ images: event.images,
586
+ chatType: event.chatType || 'private',
587
+ peerId: event.peerId || '',
588
+ peerName: event.peerName,
589
+ messageId: event.messageId,
590
+ });
591
+ }), (channelId, text) => channel.sendMessage(channelId, text), adapter, channelType);
592
+ },
539
593
  });
540
594
  }
541
595
  return result;