@wu529778790/open-im 1.11.1-beta.16 → 1.11.1-beta.18

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.
@@ -402,6 +402,10 @@ export class ClaudeSDKAdapter {
402
402
  cwd: workDir,
403
403
  model: resolvedModel,
404
404
  permissionMode,
405
+ // 启用完整工具集,与 cc 终端一致
406
+ tools: { type: 'preset', preset: 'claude_code' },
407
+ // 启用所有技能(superpowers, playwright 等),与 cc 终端一致
408
+ skills: 'all',
405
409
  ...(resumeId ? { resume: resumeId } : {}),
406
410
  ...(options?.fallbackModel ? { fallbackModel: options.fallbackModel } : {}),
407
411
  ...(options?.disallowedTools?.length ? { disallowedTools: options.disallowedTools } : {}),
@@ -110,6 +110,8 @@ function startPolling() {
110
110
  }
111
111
  // Process messages
112
112
  const messages = res.messages ?? [];
113
+ // Step 1: Extract valid USER messages and cache context tokens
114
+ const userMessages = [];
113
115
  for (const msg of messages) {
114
116
  if (signal.aborted)
115
117
  break;
@@ -120,7 +122,6 @@ function startPolling() {
120
122
  continue;
121
123
  const chatId = msg.from_user_id ?? '';
122
124
  const msgId = String(msg.message_id ?? msg.seq ?? '');
123
- const content = extracted;
124
125
  if (!chatId) {
125
126
  log.warn('ClawBot message missing from_user_id, skipping');
126
127
  continue;
@@ -130,10 +131,29 @@ function startPolling() {
130
131
  cacheContextToken(chatId, msg.context_token);
131
132
  setClawbotContextToken(msg.context_token);
132
133
  }
133
- log.info(`ClawBot message: chatId=${chatId}, msgId=${msgId}, content="${content.substring(0, 100)}"`);
134
+ userMessages.push({ chatId, msgId, content: extracted, contextToken: msg.context_token });
135
+ }
136
+ // Step 2: Aggregate consecutive messages from the same user
137
+ // ClawBot splits image+text into separate messages; combine them
138
+ const aggregated = [];
139
+ for (const m of userMessages) {
140
+ const last = aggregated[aggregated.length - 1];
141
+ if (last && last.chatId === m.chatId) {
142
+ // Same user — merge content (image marker + text)
143
+ last.content = `${last.content}\n${m.content}`;
144
+ }
145
+ else {
146
+ aggregated.push({ chatId: m.chatId, msgId: m.msgId, content: m.content });
147
+ }
148
+ }
149
+ // Step 3: Dispatch aggregated messages
150
+ for (const m of aggregated) {
151
+ if (signal.aborted)
152
+ break;
153
+ log.info(`ClawBot message: chatId=${m.chatId}, msgId=${m.msgId}, content="${m.content.substring(0, 100)}"`);
134
154
  if (messageHandler) {
135
155
  try {
136
- await messageHandler(chatId, msgId, content);
156
+ await messageHandler(m.chatId, m.msgId, m.content);
137
157
  }
138
158
  catch (err) {
139
159
  log.error('Error in ClawBot message handler:', err);
@@ -24,6 +24,7 @@ export declare class CommandHandler {
24
24
  /** 若提供,本条消息的斜杠命令回复走此 sender(须与 handleTextFlow 的 sendTextReply 一致,如带 msgId)。 */
25
25
  senderOverride?: MessageSender): Promise<boolean>;
26
26
  private handleHelp;
27
+ private handlePlugins;
27
28
  private handleSessions;
28
29
  private handleResume;
29
30
  private handleNew;
@@ -28,8 +28,9 @@ function truncateSummary(session, maxLen = 30) {
28
28
  }
29
29
  import { AsyncLocalStorage } from 'node:async_hooks';
30
30
  import { execFile } from 'node:child_process';
31
- import { readdirSync } from 'node:fs';
31
+ import { readdirSync, existsSync, readFileSync } from 'node:fs';
32
32
  import { dirname, join } from 'node:path';
33
+ import { homedir } from 'node:os';
33
34
  /**
34
35
  * Telegram 群聊等场景下命令常为 `/new@BotName`,需与 `/new` 等价。
35
36
  * 仅去掉「第一个」命令词上的 `@suffix`,保留 `/resume 1` 等参数。
@@ -75,6 +76,8 @@ export class CommandHandler {
75
76
  }
76
77
  if (t === '/help')
77
78
  return this.handleHelp(chatId);
79
+ if (t === '/plugins')
80
+ return this.handlePlugins(chatId);
78
81
  if (t === '/new')
79
82
  return this.handleNew(chatId, userId);
80
83
  if (t === '/sessions' || t === '/resume')
@@ -125,6 +128,7 @@ export class CommandHandler {
125
128
  '/rename <标题> - 重命名当前会话',
126
129
  '/fork [序号] - 分支会话(创建副本)',
127
130
  '/models - 查看可用模型',
131
+ '/plugins - 查看已安装插件',
128
132
  '/context - 查看上下文窗口占用',
129
133
  '/status - 显示状态',
130
134
  '/cd <路径> - 切换工作目录',
@@ -133,6 +137,34 @@ export class CommandHandler {
133
137
  await this.replySender().sendTextReply(chatId, help);
134
138
  return true;
135
139
  }
140
+ async handlePlugins(chatId) {
141
+ try {
142
+ const settingsPath = join(homedir(), '.claude', 'settings.json');
143
+ if (!existsSync(settingsPath)) {
144
+ await this.replySender().sendTextReply(chatId, '📦 未找到 ~/.claude/settings.json\n💡 先在 Claude Code 终端运行一次会自动创建');
145
+ return true;
146
+ }
147
+ const raw = JSON.parse(readFileSync(settingsPath, 'utf-8'));
148
+ const plugins = (raw.enabledPlugins ?? {});
149
+ const entries = Object.entries(plugins);
150
+ if (entries.length === 0) {
151
+ await this.replySender().sendTextReply(chatId, '📦 暂无已安装插件\n💡 在 Claude Code 终端用 /install 安装插件');
152
+ return true;
153
+ }
154
+ const lines = ['📦 已安装插件:', ''];
155
+ for (const [name, enabled] of entries) {
156
+ lines.push(enabled ? ` ✅ ${name}` : ` ❌ ${name}`);
157
+ }
158
+ lines.push('');
159
+ lines.push('💡 在 ~/.claude/settings.json 管理,或在 Claude Code 终端用 /install');
160
+ await this.replySender().sendTextReply(chatId, lines.join('\n'));
161
+ }
162
+ catch (e) {
163
+ log.warn('Failed to read plugins:', e);
164
+ await this.replySender().sendTextReply(chatId, '❌ 读取插件列表失败');
165
+ }
166
+ return true;
167
+ }
136
168
  async handleSessions(chatId, userId, _platform) {
137
169
  const workDir = this.deps.sessionManager.getWorkDir(userId);
138
170
  const sessions = await ClaudeSDKAdapter.listSessionsForDir(workDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wu529778790/open-im",
3
- "version": "1.11.1-beta.16",
3
+ "version": "1.11.1-beta.18",
4
4
  "description": "Your AI coding assistant, in every chat app. Multi-platform IM bridge for Claude Code, Codex, and CodeBuddy.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",