evolclaw 2.1.2 → 2.2.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 (42) hide show
  1. package/README.md +10 -3
  2. package/data/evolclaw.sample.json +9 -1
  3. package/dist/agents/claude-runner.js +612 -0
  4. package/dist/agents/codex-runner.js +310 -0
  5. package/dist/channels/aun.js +416 -9
  6. package/dist/channels/feishu.js +397 -104
  7. package/dist/channels/wechat.js +84 -2
  8. package/dist/cli.js +427 -126
  9. package/dist/config.js +102 -4
  10. package/dist/core/adapters/claude-session-file-adapter.js +144 -0
  11. package/dist/core/adapters/codex-session-file-adapter.js +196 -0
  12. package/dist/core/agent-loader.js +39 -0
  13. package/dist/core/channel-loader.js +60 -0
  14. package/dist/core/command-handler.js +908 -304
  15. package/dist/core/event-bus.js +32 -0
  16. package/dist/core/ipc-server.js +71 -0
  17. package/dist/core/message-bridge.js +187 -0
  18. package/dist/core/message-processor.js +370 -227
  19. package/dist/core/message-queue.js +153 -29
  20. package/dist/core/permission.js +58 -0
  21. package/dist/core/session-file-adapter.js +7 -0
  22. package/dist/core/session-manager.js +567 -205
  23. package/dist/core/stats-collector.js +86 -0
  24. package/dist/index.js +309 -243
  25. package/dist/paths.js +1 -0
  26. package/dist/utils/init-feishu.js +2 -0
  27. package/dist/utils/init-wechat.js +2 -0
  28. package/dist/utils/init.js +285 -53
  29. package/dist/utils/ipc-client.js +36 -0
  30. package/dist/utils/migrate-project.js +122 -0
  31. package/dist/utils/{permission.js → permission-utils.js} +31 -3
  32. package/dist/utils/rich-content-renderer.js +228 -0
  33. package/dist/utils/session-file-health.js +11 -34
  34. package/dist/utils/stream-debouncer.js +122 -0
  35. package/dist/utils/stream-idle-monitor.js +1 -1
  36. package/package.json +3 -1
  37. package/dist/core/agent-runner.js +0 -348
  38. package/dist/core/message-stream.js +0 -59
  39. package/dist/index.js.bak +0 -340
  40. package/dist/utils/markdown-to-feishu.js +0 -94
  41. /package/dist/utils/{platform.js → cross-platform.js} +0 -0
  42. /package/dist/{core → utils}/message-cache.js +0 -0
@@ -132,6 +132,7 @@ export class WechatChannel {
132
132
  config;
133
133
  messageHandler;
134
134
  abortController;
135
+ connected = false;
135
136
  // 内部状态(不外泄到核心层)
136
137
  contextTokenCache = new Map();
137
138
  typingTicketCache = new Map();
@@ -181,16 +182,34 @@ export class WechatChannel {
181
182
  if (this.abortController?.signal.aborted)
182
183
  return;
183
184
  logger.error('[WeChat] Poll loop fatal error:', err);
185
+ this.connected = false;
184
186
  });
187
+ this.connected = true;
185
188
  logger.info('[WeChat] Channel connected');
186
189
  }
187
190
  async disconnect() {
191
+ this.connected = false;
188
192
  if (this.abortController) {
189
193
  this.abortController.abort();
190
194
  this.abortController = undefined;
191
195
  }
192
196
  logger.info('[WeChat] Channel disconnected');
193
197
  }
198
+ /** Get current connection status */
199
+ getStatus() {
200
+ return { connected: this.connected };
201
+ }
202
+ /** Reconnect: disconnect then connect again */
203
+ async reconnect() {
204
+ await this.disconnect();
205
+ try {
206
+ await this.connect();
207
+ return '重连成功';
208
+ }
209
+ catch (err) {
210
+ return `重连失败: ${err instanceof Error ? err.message : String(err)}`;
211
+ }
212
+ }
194
213
  async sendMessage(to, text) {
195
214
  if (!text || text.trim() === '') {
196
215
  logger.warn('[WeChat] Attempted to send empty message, skipping');
@@ -447,7 +466,7 @@ export class WechatChannel {
447
466
  // 回调主流程
448
467
  if (this.messageHandler) {
449
468
  try {
450
- await this.messageHandler(fromUserId, finalContent || '', fromUserId, media.images.length ? media.images : undefined);
469
+ await this.messageHandler(fromUserId, finalContent || '', fromUserId, media.images.length ? media.images : undefined, 'private');
451
470
  }
452
471
  catch (err) {
453
472
  logger.error('[WeChat] Message handler error:', err);
@@ -529,7 +548,7 @@ export class WechatChannel {
529
548
  const projectPath = this.projectPathResolver
530
549
  ? await this.projectPathResolver(channelId)
531
550
  : process.cwd();
532
- const uploadsDir = path.join(projectPath, '.claude', 'uploads');
551
+ const uploadsDir = path.join(projectPath, '.evolclaw', 'uploads');
533
552
  fs.mkdirSync(uploadsDir, { recursive: true });
534
553
  const savePath = path.join(uploadsDir, fileName);
535
554
  fs.writeFileSync(savePath, buf);
@@ -682,3 +701,66 @@ export class WechatChannel {
682
701
  });
683
702
  }
684
703
  }
704
+ export class WechatChannelPlugin {
705
+ name = 'wechat';
706
+ isEnabled(config) {
707
+ return config.channels?.wechat?.enabled === true && !!config.channels?.wechat?.token;
708
+ }
709
+ async createChannel(config) {
710
+ const wechatConfig = config.channels?.wechat;
711
+ if (!wechatConfig?.token) {
712
+ throw new Error('WeChat config missing');
713
+ }
714
+ const channel = new WechatChannel({
715
+ baseUrl: wechatConfig.baseUrl || 'https://ilinkai.weixin.qq.com',
716
+ token: wechatConfig.token,
717
+ });
718
+ const adapter = {
719
+ name: 'wechat',
720
+ sendText: (id, text) => channel.sendMessage(id, text),
721
+ sendFile: (id, filePath) => channel.sendFile(id, filePath),
722
+ };
723
+ const policy = {
724
+ canSwitchProject: (chatType, identity) => identity === 'owner',
725
+ canListProjects: (chatType, identity) => identity === 'owner',
726
+ canCreateSession: (chatType, identity) => true,
727
+ canDeleteSession: (chatType, identity) => true,
728
+ canImportCliSession: (chatType, identity) => identity === 'owner',
729
+ messagePrefix: (chatType, peerName) => '',
730
+ showMiddleResult: (chatType, identity) => {
731
+ const mode = wechatConfig.showActivities ?? config.showActivities ?? 'all';
732
+ if (mode === 'none')
733
+ return false;
734
+ if (mode === 'dm-only')
735
+ return chatType === 'private';
736
+ if (mode === 'owner-dm-only')
737
+ return chatType === 'private' && identity === 'owner';
738
+ return true;
739
+ },
740
+ showIdleMonitor: (chatType, identity) => {
741
+ const mode = wechatConfig.showActivities ?? config.showActivities ?? 'all';
742
+ if (mode === 'none')
743
+ return false;
744
+ if (mode === 'dm-only')
745
+ return chatType === 'private';
746
+ if (mode === 'owner-dm-only')
747
+ return chatType === 'private' && identity === 'owner';
748
+ return true;
749
+ },
750
+ accumulateErrors: (chatType, identity) => true,
751
+ };
752
+ const options = {
753
+ fileMarkerPattern: /\[SEND_FILE:(?:(\w+):)?([^\]]+)\]/g,
754
+ flushDelay: wechatConfig.flushDelay ?? 3, // WeChat 默认 3s
755
+ };
756
+ return {
757
+ adapter,
758
+ channel,
759
+ policy,
760
+ options,
761
+ connect: () => channel.connect(),
762
+ disconnect: () => channel.disconnect(),
763
+ onProjectPathRequest: (channelId) => Promise.resolve(config.projects?.defaultPath || process.cwd()),
764
+ };
765
+ }
766
+ }