@wu529778790/open-im 1.9.4-beta.10 → 1.9.4-beta.11
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.
- package/dist/adapters/claude-sdk-adapter.js +2 -1
- package/dist/commands/handler.d.ts +1 -1
- package/dist/commands/handler.js +2 -2
- package/dist/config.js +0 -9
- package/dist/dingtalk/api.js +0 -2
- package/dist/dingtalk/message-sender.js +1 -2
- package/dist/feishu/event-handler.js +0 -43
- package/dist/index.js +11 -4
- package/dist/platform/create-event-context.test.js +2 -0
- package/dist/platform/handle-ai-request.js +1 -1
- package/dist/platform/handle-text-flow.d.ts +5 -1
- package/dist/platform/handle-text-flow.js +3 -3
- package/dist/qq/client.js +1 -0
- package/dist/qq/event-handler.js +1 -1
- package/dist/wework/message-sender.js +0 -3
- package/dist/workbuddy/event-handler.js +7 -7
- package/dist/workbuddy/oauth.js +0 -2
- package/package.json +1 -1
|
@@ -36,7 +36,8 @@ function loadUserPluginSettings() {
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
// Pre-load user plugin settings to cache Claude Code user preferences
|
|
40
|
+
loadUserPluginSettings();
|
|
40
41
|
// 存储所有活跃的 SDKSession 对象,key 为 sessionId
|
|
41
42
|
// 使用 Map 而不是 Set,因为我们需要通过 sessionId 获取 session
|
|
42
43
|
const activeSessions = new Map();
|
|
@@ -18,7 +18,7 @@ export type ClaudeRequestHandler = (userId: string, chatId: string, prompt: stri
|
|
|
18
18
|
export declare class CommandHandler {
|
|
19
19
|
private deps;
|
|
20
20
|
constructor(deps: CommandHandlerDeps);
|
|
21
|
-
dispatch(text: string, chatId: string, userId: string, platform: Platform,
|
|
21
|
+
dispatch(text: string, chatId: string, userId: string, platform: Platform, _handleClaudeRequest: ClaudeRequestHandler): Promise<boolean>;
|
|
22
22
|
private handleHelp;
|
|
23
23
|
private handleNew;
|
|
24
24
|
private handlePwd;
|
package/dist/commands/handler.js
CHANGED
|
@@ -9,7 +9,7 @@ export class CommandHandler {
|
|
|
9
9
|
constructor(deps) {
|
|
10
10
|
this.deps = deps;
|
|
11
11
|
}
|
|
12
|
-
async dispatch(text, chatId, userId, platform,
|
|
12
|
+
async dispatch(text, chatId, userId, platform, _handleClaudeRequest) {
|
|
13
13
|
const t = text.trim();
|
|
14
14
|
if (platform === 'telegram' && t === '/start') {
|
|
15
15
|
await this.deps.sender.sendTextReply(chatId, '欢迎使用 open-im AI CLI 桥接!\n\n发送消息与 AI 交互,输入 /help 查看帮助。');
|
|
@@ -75,7 +75,7 @@ export class CommandHandler {
|
|
|
75
75
|
await this.deps.sender.sendTextReply(chatId, lines.join('\n'));
|
|
76
76
|
return true;
|
|
77
77
|
}
|
|
78
|
-
async handleCd(chatId, userId, dir,
|
|
78
|
+
async handleCd(chatId, userId, dir, _platform) {
|
|
79
79
|
// 如果 dir 为空,显示目录选择界面
|
|
80
80
|
if (!dir) {
|
|
81
81
|
const currentDir = this.deps.sessionManager.getWorkDir(userId);
|
package/dist/config.js
CHANGED
|
@@ -13,15 +13,6 @@ const log = createLogger('config');
|
|
|
13
13
|
// Re-export file I/O and credential helpers from sub-modules
|
|
14
14
|
export { CONFIG_PATH, loadFileConfig, saveFileConfig, getClaudeConfigHome, loadClaudeSettingsEnv, saveClaudeSettingsEnv, normalizeAiCommand, hasCodexAuth, parseCommaSeparated, } from './config/file-io.js';
|
|
15
15
|
import { loadFileConfig, normalizeAiCommand, hasCodexAuth, parseCommaSeparated, loadClaudeSettingsEnv, } from './config/file-io.js';
|
|
16
|
-
const AI_COMMANDS = ['claude', 'codex', 'codebuddy'];
|
|
17
|
-
/** 检查是否已配置 Claude API 凭证 */
|
|
18
|
-
function hasClaudeCredentials() {
|
|
19
|
-
return !!(process.env.ANTHROPIC_API_KEY ||
|
|
20
|
-
process.env.ANTHROPIC_AUTH_TOKEN ||
|
|
21
|
-
process.env.CLAUDE_CODE_OAUTH_TOKEN ||
|
|
22
|
-
process.env.ANTHROPIC_BASE_URL // 使用自定义 API(如第三方模型)时可能不需要标准凭证
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
16
|
/** 检测是否需要交互式配置(无 token 且无环境变量) */
|
|
26
17
|
export function needsSetup() {
|
|
27
18
|
// 环境变量已提供任一平台的凭证,则认为已配置
|
package/dist/dingtalk/api.js
CHANGED
|
@@ -27,8 +27,7 @@ const streamStates = new Map();
|
|
|
27
27
|
// Periodic cleanup of orphaned stream states (max 30 minutes)
|
|
28
28
|
const STREAM_MAX_AGE_MS = 30 * 60 * 1000;
|
|
29
29
|
setInterval(() => {
|
|
30
|
-
const
|
|
31
|
-
for (const [id, state] of streamStates) {
|
|
30
|
+
for (const [id] of streamStates) {
|
|
32
31
|
// streamStates in DingTalk don't have createdAt, clean up by size
|
|
33
32
|
if (streamStates.size > 50) {
|
|
34
33
|
streamStates.delete(id);
|
|
@@ -212,49 +212,6 @@ export function setupFeishuHandlers(config, sessionManager) {
|
|
|
212
212
|
},
|
|
213
213
|
}),
|
|
214
214
|
});
|
|
215
|
-
/**
|
|
216
|
-
* 解析 action value(兼容对象、JSON 字符串)
|
|
217
|
-
*/
|
|
218
|
-
function parseActionValue(raw) {
|
|
219
|
-
if (!raw)
|
|
220
|
-
return null;
|
|
221
|
-
let obj = null;
|
|
222
|
-
if (typeof raw === 'string') {
|
|
223
|
-
try {
|
|
224
|
-
obj = JSON.parse(raw);
|
|
225
|
-
}
|
|
226
|
-
catch (err) {
|
|
227
|
-
log.debug('Failed to parse action value as JSON:', err);
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
else if (typeof raw === 'object' && raw !== null) {
|
|
232
|
-
obj = raw;
|
|
233
|
-
}
|
|
234
|
-
return obj?.action && obj?.value ? obj : null;
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* 从卡片回调事件中提取延时更新 token(格式 c-xxxx)
|
|
238
|
-
* 飞书文档:从卡片交互返回内容获取,用于延时更新接口
|
|
239
|
-
*/
|
|
240
|
-
function extractCardToken(data) {
|
|
241
|
-
const raw = data;
|
|
242
|
-
const event = (raw?.event ?? raw);
|
|
243
|
-
const action = event?.action;
|
|
244
|
-
const context = event?.context;
|
|
245
|
-
const candidates = [
|
|
246
|
-
event?.token,
|
|
247
|
-
event?.open_api_token,
|
|
248
|
-
raw?.token,
|
|
249
|
-
action?.token,
|
|
250
|
-
context?.token,
|
|
251
|
-
].filter((t) => typeof t === 'string' && t.startsWith('c-'));
|
|
252
|
-
const token = candidates[0] ?? null;
|
|
253
|
-
if (!token) {
|
|
254
|
-
log.debug('[extractCardToken] No token found, event keys:', Object.keys(event ?? {}));
|
|
255
|
-
}
|
|
256
|
-
return token;
|
|
257
|
-
}
|
|
258
215
|
/**
|
|
259
216
|
* Handle card button click (card.action.trigger) - 需在 3 秒内返回响应
|
|
260
217
|
* 同步只返回 toast,避免 200672;用延时更新 API 异步替换为只读卡片,防止二次点击
|
package/dist/index.js
CHANGED
|
@@ -93,13 +93,20 @@ const PLATFORM_MODULES = {
|
|
|
93
93
|
};
|
|
94
94
|
async function sendLifecycleNotification(platform, message) {
|
|
95
95
|
const mod = PLATFORM_MODULES[platform];
|
|
96
|
-
if (!mod?.sendNotification)
|
|
96
|
+
if (!mod?.sendNotification) {
|
|
97
|
+
log.debug(`[${platform}] No sendNotification, skipping lifecycle notification`);
|
|
97
98
|
return;
|
|
99
|
+
}
|
|
98
100
|
const chatId = getActiveChatId(platform);
|
|
99
|
-
if (!chatId)
|
|
101
|
+
if (!chatId) {
|
|
102
|
+
log.info(`[${platform}] No active chatId, skipping lifecycle notification`);
|
|
100
103
|
return;
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
}
|
|
105
|
+
log.info(`[${platform}] Sending lifecycle notification to chatId=${chatId}`);
|
|
106
|
+
await mod.sendNotification(chatId, message).then(() => {
|
|
107
|
+
log.info(`[${platform}] Lifecycle notification sent successfully`);
|
|
108
|
+
}).catch((err) => {
|
|
109
|
+
log.warn(`Failed to send ${platform} notification:`, err);
|
|
103
110
|
});
|
|
104
111
|
}
|
|
105
112
|
function buildStartupMessage(platform, appVersion, aiCommand, defaultWorkDir, sessionManager) {
|
|
@@ -5,10 +5,12 @@ import { createPlatformEventContext } from './create-event-context.js';
|
|
|
5
5
|
import { AccessControl } from '../access/access-control.js';
|
|
6
6
|
import { CommandHandler } from '../commands/handler.js';
|
|
7
7
|
// Setup mocks for AccessControl
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
9
|
vi.mocked(AccessControl).mockImplementation(function (ids) {
|
|
9
10
|
this.isAllowed = (userId) => ids.length === 0 || ids.includes(userId);
|
|
10
11
|
});
|
|
11
12
|
// Setup mocks for CommandHandler
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
14
|
vi.mocked(CommandHandler).mockImplementation(function (deps) {
|
|
13
15
|
this.dispatch = vi.fn();
|
|
14
16
|
this.deps = deps;
|
|
@@ -94,7 +94,7 @@ export function createPlatformAIRequestHandler(deps) {
|
|
|
94
94
|
},
|
|
95
95
|
};
|
|
96
96
|
// Merge in platform callbacks (if provided)
|
|
97
|
-
|
|
97
|
+
const mergedCallbacks = { ...defaultCallbacks };
|
|
98
98
|
// Use taskCallbacksFactory if provided (has full context access)
|
|
99
99
|
if (taskCallbacksFactory) {
|
|
100
100
|
const factoryCallbacks = taskCallbacksFactory({
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
import type { Platform } from '../config.js';
|
|
18
18
|
import type { PlatformEventContext } from './create-event-context.js';
|
|
19
19
|
import type { EnqueueResult } from '../queue/request-queue.js';
|
|
20
|
+
import type { HandleAIRequestParams } from './handle-ai-request.js';
|
|
21
|
+
/** AI request handler function type (object params, as returned by createPlatformAIRequestHandler). */
|
|
22
|
+
export type HandleAIRequestFn = (params: HandleAIRequestParams) => Promise<void>;
|
|
20
23
|
/**
|
|
21
24
|
* Callback to send a text reply to the user.
|
|
22
25
|
* Used for access-denied messages and queue status notifications.
|
|
@@ -37,7 +40,8 @@ export interface HandleTextFlowParams {
|
|
|
37
40
|
/** The platform event context (accessControl, commandHandler, requestQueue, etc.). */
|
|
38
41
|
ctx: PlatformEventContext;
|
|
39
42
|
/** The platform-specific AI request handler (from createPlatformAIRequestHandler). */
|
|
40
|
-
|
|
43
|
+
/** The platform-specific AI request handler (from createPlatformAIRequestHandler). */
|
|
44
|
+
handleAIRequest: HandleAIRequestFn;
|
|
41
45
|
/** Function to send a text reply back to the user. */
|
|
42
46
|
sendTextReply: SendTextReplyFn;
|
|
43
47
|
/** Optional: additional workDir override. If not provided, resolved from sessionManager. */
|
|
@@ -53,8 +53,8 @@ export async function handleTextFlow(params) {
|
|
|
53
53
|
setChatUser(chatId, userId, platform);
|
|
54
54
|
// 4. Command dispatch
|
|
55
55
|
try {
|
|
56
|
-
//
|
|
57
|
-
const
|
|
56
|
+
// Wrapper: dispatch expects positional args, handleAIRequest expects an object
|
|
57
|
+
const dispatchHandler = (userId, chatId, prompt, workDir, convId, _threadCtx, replyToMessageId) => {
|
|
58
58
|
return handleAIRequest({
|
|
59
59
|
userId,
|
|
60
60
|
chatId,
|
|
@@ -64,7 +64,7 @@ export async function handleTextFlow(params) {
|
|
|
64
64
|
replyToMessageId,
|
|
65
65
|
});
|
|
66
66
|
};
|
|
67
|
-
const handled = await ctx.commandHandler.dispatch(text, chatId, userId, platform,
|
|
67
|
+
const handled = await ctx.commandHandler.dispatch(text, chatId, userId, platform, dispatchHandler);
|
|
68
68
|
if (handled) {
|
|
69
69
|
return true;
|
|
70
70
|
}
|
package/dist/qq/client.js
CHANGED
|
@@ -98,6 +98,7 @@ async function getGatewayUrl(config) {
|
|
|
98
98
|
}
|
|
99
99
|
function normalizeInboundEvent(payload) {
|
|
100
100
|
const type = payload.t;
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
102
|
const data = (payload.d ?? {});
|
|
102
103
|
const attachments = Array.isArray(data.attachments)
|
|
103
104
|
? data.attachments.map((attachment) => ({
|
package/dist/qq/event-handler.js
CHANGED
|
@@ -118,7 +118,7 @@ export function setupQQHandlers(config, sessionManager) {
|
|
|
118
118
|
sessionManager,
|
|
119
119
|
sender: { sendTextReply, sendDirectorySelection },
|
|
120
120
|
});
|
|
121
|
-
const { accessControl, requestQueue, runningTasks
|
|
121
|
+
const { accessControl, requestQueue, runningTasks } = platformContext;
|
|
122
122
|
const recentEventIds = new Map();
|
|
123
123
|
const recentEventFingerprints = new Map();
|
|
124
124
|
// QQ-specific: Store taskKey -> { { chatId, msgId } } mapping
|
|
@@ -30,16 +30,16 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
|
|
|
30
30
|
const stopTaskCleanup = startTaskCleanup(ctx.runningTasks);
|
|
31
31
|
// WorkBuddy-specific sender callbacks (no thinking message needed)
|
|
32
32
|
const platformSender = {
|
|
33
|
-
sendThinkingMessage: async (
|
|
33
|
+
sendThinkingMessage: async (_chatId, _replyToMessageId, _toolId) => {
|
|
34
34
|
// WorkBuddy uses incoming msgId as thinking message ID
|
|
35
35
|
// This is a no-op since we'll use the incoming msgId
|
|
36
36
|
return 'workbuddy_no_thinking';
|
|
37
37
|
},
|
|
38
|
-
sendTextReply: async (
|
|
38
|
+
sendTextReply: async (_chatId, text) => {
|
|
39
39
|
// WorkBuddy-specific reply (needs msgId captured per event)
|
|
40
|
-
await sendTextReply(null,
|
|
40
|
+
await sendTextReply(null, _chatId, text, '');
|
|
41
41
|
},
|
|
42
|
-
startTyping: (
|
|
42
|
+
startTyping: (_chatId) => {
|
|
43
43
|
// WorkBuddy doesn't support typing indicators
|
|
44
44
|
return () => { };
|
|
45
45
|
},
|
|
@@ -50,10 +50,10 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
|
|
|
50
50
|
// WorkBuddy doesn't support streaming updates via Centrifuge
|
|
51
51
|
log.debug(`Stream update (not sent): ${content.substring(0, 50)}...`);
|
|
52
52
|
},
|
|
53
|
-
sendComplete: async (
|
|
53
|
+
sendComplete: async (_content) => {
|
|
54
54
|
// Will be handled per-event with correct msgId
|
|
55
55
|
},
|
|
56
|
-
sendError: async (
|
|
56
|
+
sendError: async (_error) => {
|
|
57
57
|
// Will be handled per-event with correct msgId
|
|
58
58
|
},
|
|
59
59
|
extraCleanup: () => {
|
|
@@ -72,7 +72,7 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
|
|
|
72
72
|
// Create platform-specific AI request handler
|
|
73
73
|
// Note: WorkBuddy uses a different handleAIRequest signature with msgId
|
|
74
74
|
// We'll need to wrap the standard handler
|
|
75
|
-
|
|
75
|
+
createPlatformAIRequestHandler({
|
|
76
76
|
platform: 'workbuddy',
|
|
77
77
|
config,
|
|
78
78
|
sessionManager,
|
package/dist/workbuddy/oauth.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* WorkBuddy OAuth - CodeBuddy authentication for WeChat KF integration
|
|
3
3
|
*/
|
|
4
4
|
import { hostname } from 'node:os';
|
|
5
|
-
import { createLogger } from '../logger.js';
|
|
6
|
-
const log = createLogger('WorkBuddyOAuth');
|
|
7
5
|
const DEFAULT_BASE_URL = 'https://copilot.tencent.com';
|
|
8
6
|
const PLATFORM = 'ide';
|
|
9
7
|
export class WorkBuddyOAuth {
|