@wu529778790/open-im 1.11.1-beta.15 → 1.11.1-beta.17

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.
@@ -15,6 +15,17 @@ import { createLogger } from '../logger.js';
15
15
  import { refreshClaudeEnvToProcess } from '../config/file-io.js';
16
16
  import { toReplyPlainText } from '../shared/utils.js';
17
17
  const log = createLogger('ClaudeSDK');
18
+ /**
19
+ * 注入交互式上下文指令,让 Claude 认为这是交互式终端会话。
20
+ * 解决 query() 非交互环境下 Claude 跳过用户选择、直接自主决策的问题。
21
+ */
22
+ const INTERACTIVE_CONTEXT = `[SYSTEM: You are in an interactive chat session via instant messenger. The user CAN and WILL respond to your messages — treat this like an interactive terminal session. Rules:
23
+ 1. When you need to make a decision involving user preference (choosing an approach, selecting between options, deciding what to do next), ALWAYS present clearly numbered options and WAIT for the user's response.
24
+ 2. Do NOT proceed autonomously when user input would be valuable.
25
+ 3. Only proceed autonomously for obvious single-path tasks (e.g. reading a file, running a simple command).
26
+ 4. When presenting options, format them as a numbered list and end with a question.
27
+ ]
28
+ `;
18
29
  function loadUserPluginSettings() {
19
30
  try {
20
31
  const settingsPath = join(homedir(), '.claude', 'settings.json');
@@ -386,11 +397,15 @@ export class ClaudeSDKAdapter {
386
397
  }
387
398
  }
388
399
  const q = query({
389
- prompt,
400
+ prompt: INTERACTIVE_CONTEXT + prompt,
390
401
  options: {
391
402
  cwd: workDir,
392
403
  model: resolvedModel,
393
404
  permissionMode,
405
+ // 启用完整工具集,与 cc 终端一致
406
+ tools: { type: 'preset', preset: 'claude_code' },
407
+ // 启用所有技能(superpowers, playwright 等),与 cc 终端一致
408
+ skills: 'all',
394
409
  ...(resumeId ? { resume: resumeId } : {}),
395
410
  ...(options?.fallbackModel ? { fallbackModel: options.fallbackModel } : {}),
396
411
  ...(options?.disallowedTools?.length ? { disallowedTools: options.disallowedTools } : {}),
@@ -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.15",
3
+ "version": "1.11.1-beta.17",
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",