@wu529778790/open-im 1.10.0 → 1.10.1
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/access/access-control.js +2 -2
- package/dist/adapters/claude-sdk-adapter.js +4 -3
- package/dist/config/credentials.d.ts +0 -8
- package/dist/config/credentials.js +0 -49
- package/dist/feishu/client.js +3 -3
- package/dist/feishu/event-handler.js +1 -1
- package/dist/feishu/permission.d.ts +0 -12
- package/dist/feishu/permission.js +3 -3
- package/dist/index.js +2 -1
- package/dist/manager-control.js +2 -17
- package/dist/platform/handle-ai-request.js +3 -2
- package/dist/queue/request-queue.d.ts +3 -0
- package/dist/queue/request-queue.js +26 -14
- package/dist/sanitize.js +1 -0
- package/dist/shared/ai-task.js +2 -2
- package/dist/shared/chat-user-map.d.ts +0 -2
- package/dist/shared/chat-user-map.js +0 -6
- package/dist/wework/client.js +1 -1
- package/dist/wework/event-handler.js +1 -1
- package/dist/wework/message-sender.js +1 -1
- package/dist/wework/types.d.ts +0 -7
- package/dist/workbuddy/client.js +2 -2
- package/dist/workbuddy/message-sender.js +1 -1
- package/dist/workbuddy/oauth.js +10 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ export class AccessControl {
|
|
|
4
4
|
allowedUserIds;
|
|
5
5
|
constructor(allowedUserIds) {
|
|
6
6
|
this.allowedUserIds = new Set(allowedUserIds);
|
|
7
|
-
log.
|
|
7
|
+
log.debug(`AccessControl initialized with ${allowedUserIds.length} allowed users:`, allowedUserIds);
|
|
8
8
|
}
|
|
9
9
|
isAllowed(userId) {
|
|
10
10
|
if (this.allowedUserIds.size === 0) {
|
|
@@ -12,7 +12,7 @@ export class AccessControl {
|
|
|
12
12
|
return true;
|
|
13
13
|
}
|
|
14
14
|
const allowed = this.allowedUserIds.has(userId);
|
|
15
|
-
log.
|
|
15
|
+
log.debug(`Checking user ${userId}: ${allowed ? 'ALLOWED' : 'DENIED'}`);
|
|
16
16
|
return allowed;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -79,8 +79,9 @@ cleanupInterval.unref(); // 不阻止进程退出
|
|
|
79
79
|
* `cwd` parameter, so we must chdir before calling them. This mutex ensures
|
|
80
80
|
* concurrent requests don't race on the working directory.
|
|
81
81
|
*
|
|
82
|
-
* **
|
|
83
|
-
*
|
|
82
|
+
* **TODO:** Remove this mutex entirely once @anthropic-ai/claude-agent-sdk
|
|
83
|
+
* supports a `cwd` option in createSession/resumeSession. Track upstream:
|
|
84
|
+
* https://github.com/anthropics/claude-agent-sdk/issues
|
|
84
85
|
*/
|
|
85
86
|
let chdirMutex = Promise.resolve();
|
|
86
87
|
function withChdirMutex(fn) {
|
|
@@ -429,7 +430,7 @@ export class ClaudeSDKAdapter {
|
|
|
429
430
|
const errIdToClean = actualSessionId ?? pendingTempId;
|
|
430
431
|
if (errIdToClean?.startsWith('pending-')) {
|
|
431
432
|
activeSessions.delete(errIdToClean);
|
|
432
|
-
log.
|
|
433
|
+
log.warn(`Cleaned up pending session after error: ${errIdToClean}`);
|
|
433
434
|
}
|
|
434
435
|
// If error suggests a corrupted session, remove it from cache to prevent reuse
|
|
435
436
|
if (actualSessionId && isSessionCorruptionError(msg)) {
|
|
@@ -17,11 +17,3 @@ export declare function resolvePlatformCredentials(envKeys: Record<string, strin
|
|
|
17
17
|
* Extract WorkBuddy credentials, with legacy platforms.wechat migration support.
|
|
18
18
|
*/
|
|
19
19
|
export declare function resolveWorkBuddyFileConfig(fileConfig: FileConfig): NonNullable<FileConfig['platforms']>['workbuddy'] | undefined;
|
|
20
|
-
/**
|
|
21
|
-
* Check if a CLI tool is available at the given path or on PATH.
|
|
22
|
-
*/
|
|
23
|
-
export declare function checkCliAvailable(cliPath: string, toolName: string): void;
|
|
24
|
-
/**
|
|
25
|
-
* Resolve Windows-specific CLI path for npm global installs.
|
|
26
|
-
*/
|
|
27
|
-
export declare function resolveWindowsCliPath(cliName: string, configuredPath: string): string;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { accessSync, constants } from 'node:fs';
|
|
2
|
-
import { execFileSync } from 'node:child_process';
|
|
3
|
-
import { join, isAbsolute } from 'node:path';
|
|
4
1
|
/**
|
|
5
2
|
* Resolves a single credential value using the standard priority chain:
|
|
6
3
|
* environment variable → platform file config → legacy file config.
|
|
@@ -37,49 +34,3 @@ export function resolveWorkBuddyFileConfig(fileConfig) {
|
|
|
37
34
|
}
|
|
38
35
|
return undefined;
|
|
39
36
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Check if a CLI tool is available at the given path or on PATH.
|
|
42
|
-
*/
|
|
43
|
-
export function checkCliAvailable(cliPath, toolName) {
|
|
44
|
-
if (isAbsolute(cliPath) || cliPath.includes('/') || cliPath.includes('\\')) {
|
|
45
|
-
try {
|
|
46
|
-
accessSync(cliPath, constants.F_OK);
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
throw new Error(`${toolName} CLI not found at: ${cliPath}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
const checkCommand = process.platform === 'win32' ? 'where' : 'which';
|
|
54
|
-
try {
|
|
55
|
-
execFileSync(checkCommand, [cliPath], {
|
|
56
|
-
stdio: 'pipe',
|
|
57
|
-
windowsHide: process.platform === 'win32',
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
throw new Error(`${toolName} CLI not found on PATH: ${cliPath}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Resolve Windows-specific CLI path for npm global installs.
|
|
67
|
-
*/
|
|
68
|
-
export function resolveWindowsCliPath(cliName, configuredPath) {
|
|
69
|
-
if (process.platform !== 'win32' || configuredPath !== cliName)
|
|
70
|
-
return configuredPath;
|
|
71
|
-
const npmPaths = [
|
|
72
|
-
join(process.env.APPDATA || '', 'npm', `${cliName}.cmd`),
|
|
73
|
-
join(process.env.LOCALAPPDATA || '', 'npm', `${cliName}.cmd`),
|
|
74
|
-
];
|
|
75
|
-
for (const p of npmPaths) {
|
|
76
|
-
try {
|
|
77
|
-
accessSync(p, constants.F_OK);
|
|
78
|
-
return p;
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
/* try next */
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return configuredPath;
|
|
85
|
-
}
|
package/dist/feishu/client.js
CHANGED
|
@@ -50,7 +50,7 @@ export async function initFeishu(config, eventHandler) {
|
|
|
50
50
|
eventDispatcher.register({
|
|
51
51
|
'im.message.receive_v1': async (data) => {
|
|
52
52
|
log.info('[EVENT] Received Feishu message event');
|
|
53
|
-
log.
|
|
53
|
+
log.debug('[EVENT] Event data:', JSON.stringify(data).slice(0, 500));
|
|
54
54
|
try {
|
|
55
55
|
await eventHandler(data);
|
|
56
56
|
log.info('[EVENT] Event handler called successfully');
|
|
@@ -62,7 +62,7 @@ export async function initFeishu(config, eventHandler) {
|
|
|
62
62
|
// 卡片按钮点击回调(权限允许/拒绝等)
|
|
63
63
|
'card.action.trigger': async (data) => {
|
|
64
64
|
log.info('[EVENT] Received Feishu card action event');
|
|
65
|
-
log.
|
|
65
|
+
log.debug('[EVENT] Card action data:', JSON.stringify(data).slice(0, 800));
|
|
66
66
|
try {
|
|
67
67
|
const result = await eventHandler(data);
|
|
68
68
|
return result;
|
|
@@ -76,7 +76,7 @@ export async function initFeishu(config, eventHandler) {
|
|
|
76
76
|
// Register catch-all handler using wildcard
|
|
77
77
|
eventDispatcher.register({
|
|
78
78
|
'*': (data) => {
|
|
79
|
-
log.
|
|
79
|
+
log.debug('Received Feishu event (catch-all):', JSON.stringify(data).slice(0, 500));
|
|
80
80
|
// Don't call eventHandler for catch-all, let specific handlers handle it
|
|
81
81
|
},
|
|
82
82
|
});
|
|
@@ -165,7 +165,7 @@ export function setupFeishuHandlers(config, sessionManager) {
|
|
|
165
165
|
return { toast: { type: 'warning', content: '未知操作' } };
|
|
166
166
|
}
|
|
167
167
|
async function handleEvent(data) {
|
|
168
|
-
log.
|
|
168
|
+
log.debug('[handleEvent] Called with data:', JSON.stringify(data).slice(0, 800));
|
|
169
169
|
try {
|
|
170
170
|
const raw = data;
|
|
171
171
|
const event = (raw?.event ?? raw);
|
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
* 统一管理权限错误码、提示消息构建、控制台输出。
|
|
5
5
|
* 所有飞书发送函数遇到错误时应通过此模块检测权限问题。
|
|
6
6
|
*/
|
|
7
|
-
/**
|
|
8
|
-
* 从异常中提取飞书 API 错误码
|
|
9
|
-
*/
|
|
10
|
-
export declare function extractFeishuErrorCode(err: unknown): number | undefined;
|
|
11
7
|
/**
|
|
12
8
|
* 根据错误码判断是否为权限不足
|
|
13
9
|
*/
|
|
@@ -16,14 +12,6 @@ export declare function isPermissionError(err: unknown): boolean;
|
|
|
16
12
|
* 构建飞书应用权限设置页直达链接
|
|
17
13
|
*/
|
|
18
14
|
export declare function buildPermissionUrl(appId: string): string;
|
|
19
|
-
/**
|
|
20
|
-
* 构建飞书开放平台应用列表页链接
|
|
21
|
-
*/
|
|
22
|
-
export declare function buildAppListUrl(): string;
|
|
23
|
-
/**
|
|
24
|
-
* 构建飞书卡片用的权限指引消息(lark_md 格式)
|
|
25
|
-
*/
|
|
26
|
-
export declare function buildPermissionGuideMessage(err: unknown, appId?: string): string;
|
|
27
15
|
/**
|
|
28
16
|
* 启动时输出权限要求提示(仅输出一次)
|
|
29
17
|
*/
|
|
@@ -27,7 +27,7 @@ const OPTIONAL_SCOPES = [
|
|
|
27
27
|
/**
|
|
28
28
|
* 从异常中提取飞书 API 错误码
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
function extractFeishuErrorCode(err) {
|
|
31
31
|
const e = err;
|
|
32
32
|
if (e?.response?.data?.code)
|
|
33
33
|
return e.response.data.code;
|
|
@@ -56,14 +56,14 @@ export function buildPermissionUrl(appId) {
|
|
|
56
56
|
/**
|
|
57
57
|
* 构建飞书开放平台应用列表页链接
|
|
58
58
|
*/
|
|
59
|
-
|
|
59
|
+
function buildAppListUrl() {
|
|
60
60
|
return 'https://open.feishu.cn/app';
|
|
61
61
|
}
|
|
62
62
|
// ── 消息构建 ──
|
|
63
63
|
/**
|
|
64
64
|
* 构建飞书卡片用的权限指引消息(lark_md 格式)
|
|
65
65
|
*/
|
|
66
|
-
|
|
66
|
+
function buildPermissionGuideMessage(err, appId) {
|
|
67
67
|
const code = extractFeishuErrorCode(err);
|
|
68
68
|
const codeHint = code ? ` (错误码: ${code})` : '';
|
|
69
69
|
const lines = [
|
package/dist/index.js
CHANGED
|
@@ -155,6 +155,7 @@ export async function main() {
|
|
|
155
155
|
let config;
|
|
156
156
|
try {
|
|
157
157
|
config = loadConfig();
|
|
158
|
+
initLogger(config.logDir, config.logLevel);
|
|
158
159
|
}
|
|
159
160
|
catch (err) {
|
|
160
161
|
if (err instanceof Error &&
|
|
@@ -165,12 +166,12 @@ export async function main() {
|
|
|
165
166
|
if (!saved)
|
|
166
167
|
process.exit(1);
|
|
167
168
|
config = loadConfig();
|
|
169
|
+
initLogger(config.logDir, config.logLevel);
|
|
168
170
|
}
|
|
169
171
|
else {
|
|
170
172
|
throw err;
|
|
171
173
|
}
|
|
172
174
|
}
|
|
173
|
-
initLogger(config.logDir, config.logLevel);
|
|
174
175
|
loadActiveChats();
|
|
175
176
|
initAdapters(config);
|
|
176
177
|
// 尽早启动 shutdown 并写入 port 文件,使 open-im start 的 8s 就绪超时能通过(平台初始化可能较慢)
|
package/dist/manager-control.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, extname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { APP_HOME } from "./constants.js";
|
|
6
|
+
import { isRunning } from "./service-control.js";
|
|
6
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
8
|
const PID_FILE = join(APP_HOME, "open-im.pid");
|
|
8
9
|
const READY_FILE = join(APP_HOME, "open-im.ready");
|
|
@@ -23,22 +24,6 @@ function getManagerEntry() {
|
|
|
23
24
|
args: [join(__dirname, "manager.js")],
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
|
-
function isRunning(pid) {
|
|
27
|
-
try {
|
|
28
|
-
if (process.platform === "win32") {
|
|
29
|
-
const result = execFileSync("tasklist", ["/FI", `PID eq ${pid}`, "/NH"], {
|
|
30
|
-
stdio: "pipe",
|
|
31
|
-
windowsHide: true,
|
|
32
|
-
}).toString();
|
|
33
|
-
return result.includes(String(pid));
|
|
34
|
-
}
|
|
35
|
-
process.kill(pid, 0);
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
27
|
export function getManagerPid() {
|
|
43
28
|
if (!existsSync(PID_FILE))
|
|
44
29
|
return null;
|
|
@@ -96,8 +96,9 @@ export function createPlatformAIRequestHandler(deps) {
|
|
|
96
96
|
// Merge in platform callbacks (if provided)
|
|
97
97
|
const mergedCallbacks = { ...defaultCallbacks };
|
|
98
98
|
// Use taskCallbacksFactory if provided (has full context access)
|
|
99
|
+
let factoryCallbacks;
|
|
99
100
|
if (taskCallbacksFactory) {
|
|
100
|
-
|
|
101
|
+
factoryCallbacks = taskCallbacksFactory({
|
|
101
102
|
chatId,
|
|
102
103
|
msgId,
|
|
103
104
|
taskKey,
|
|
@@ -140,7 +141,7 @@ export function createPlatformAIRequestHandler(deps) {
|
|
|
140
141
|
mergedCallbacks.sendImage = (imagePath) => sender.sendImage(chatId, imagePath);
|
|
141
142
|
}
|
|
142
143
|
// Wrap extraCleanup to also call the platform's extraCleanup
|
|
143
|
-
const platformExtraCleanup = taskCallbacks?.extraCleanup ??
|
|
144
|
+
const platformExtraCleanup = taskCallbacks?.extraCleanup ?? factoryCallbacks?.extraCleanup;
|
|
144
145
|
const originalExtraCleanup = mergedCallbacks.extraCleanup;
|
|
145
146
|
mergedCallbacks.extraCleanup = () => {
|
|
146
147
|
originalExtraCleanup();
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { createLogger } from '../logger.js';
|
|
2
2
|
const log = createLogger('Queue');
|
|
3
|
+
export class QueueTimeoutError extends Error {
|
|
4
|
+
constructor(timeoutMs) {
|
|
5
|
+
super(`Task timed out after ${timeoutMs / 1000}s`);
|
|
6
|
+
this.name = 'QueueTimeoutError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
3
9
|
const MAX_QUEUE_SIZE = 3;
|
|
4
10
|
const TASK_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
|
|
5
11
|
export class RequestQueue {
|
|
@@ -19,7 +25,7 @@ export class RequestQueue {
|
|
|
19
25
|
return 'queued';
|
|
20
26
|
}
|
|
21
27
|
q.running = true;
|
|
22
|
-
this.run(key, prompt, execute);
|
|
28
|
+
this.run(key, prompt, execute).catch(() => { });
|
|
23
29
|
return 'running';
|
|
24
30
|
}
|
|
25
31
|
/** 清除指定用户会话的所有排队任务(不中止正在运行的任务) */
|
|
@@ -41,28 +47,34 @@ export class RequestQueue {
|
|
|
41
47
|
const timeoutPromise = new Promise((_, reject) => {
|
|
42
48
|
timer = setTimeout(() => {
|
|
43
49
|
controller.abort();
|
|
44
|
-
reject(new
|
|
50
|
+
reject(new QueueTimeoutError(TASK_TIMEOUT_MS));
|
|
45
51
|
}, TASK_TIMEOUT_MS);
|
|
46
52
|
});
|
|
47
53
|
await Promise.race([execute(prompt, controller.signal), timeoutPromise]);
|
|
48
54
|
}
|
|
49
55
|
catch (err) {
|
|
50
|
-
|
|
56
|
+
if (err instanceof QueueTimeoutError) {
|
|
57
|
+
log.error(`Timeout executing task for ${key}: ${err.message}`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
log.error(`Error executing task for ${key}:`, err);
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
51
63
|
}
|
|
52
64
|
finally {
|
|
53
65
|
if (timer)
|
|
54
66
|
clearTimeout(timer);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
const q = this.queues.get(key);
|
|
68
|
+
if (!q)
|
|
69
|
+
return;
|
|
70
|
+
const next = q.tasks.shift();
|
|
71
|
+
if (next) {
|
|
72
|
+
setImmediate(() => this.run(key, next.prompt, next.execute).catch(() => { }));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
q.running = false;
|
|
76
|
+
this.queues.delete(key);
|
|
77
|
+
}
|
|
66
78
|
}
|
|
67
79
|
}
|
|
68
80
|
}
|
package/dist/sanitize.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const PATTERNS = [
|
|
2
2
|
[/\b(sk|pk|bot)[-_][a-zA-Z0-9_-]{8,}/gi, (m) => (m.match(/^[a-zA-Z]+/)?.[0] || m.slice(0, 2)) + '_****'],
|
|
3
3
|
[/\b(AIza|AKIA)[a-zA-Z0-9]{12,}/g, (m) => m.slice(0, 4) + '****'],
|
|
4
|
+
[/\b[a-zA-Z0-9]{40,}\b/g, (m) => m.slice(0, 6) + '****'],
|
|
4
5
|
];
|
|
5
6
|
export function sanitize(text) {
|
|
6
7
|
let result = text;
|
package/dist/shared/ai-task.js
CHANGED
|
@@ -203,10 +203,10 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
203
203
|
sessionManager.clearSessionForConv(ctx.userId, ctx.convId, aiCommand);
|
|
204
204
|
else
|
|
205
205
|
sessionManager.clearActiveToolSession(ctx.userId, aiCommand);
|
|
206
|
-
log.
|
|
206
|
+
log.warn(`Session reset for user ${ctx.userId} due to ${aiCommand} task error`);
|
|
207
207
|
}
|
|
208
208
|
else if (aiCommand === 'codex' && isUsageLimitError(error)) {
|
|
209
|
-
log.
|
|
209
|
+
log.warn(`Keeping codex session for user ${ctx.userId} after usage limit error`);
|
|
210
210
|
}
|
|
211
211
|
const friendlyError = hadSessionInvalid
|
|
212
212
|
? '当前 Claude 会话已失效,已自动执行 /new 重置会话,请重新发送刚才的问题。'
|
|
@@ -20,9 +20,3 @@ export function setChatUser(chatId, userId, platform) {
|
|
|
20
20
|
if (platform)
|
|
21
21
|
chatToPlatform.set(chatId, platform);
|
|
22
22
|
}
|
|
23
|
-
export function getUserIdByChatId(chatId) {
|
|
24
|
-
return chatToUser.get(chatId);
|
|
25
|
-
}
|
|
26
|
-
export function getPlatformByChatId(chatId) {
|
|
27
|
-
return chatToPlatform.get(chatId);
|
|
28
|
-
}
|
package/dist/wework/client.js
CHANGED
|
@@ -111,7 +111,7 @@ export async function initWeWork(cfg, eventHandler, onStateChange) {
|
|
|
111
111
|
stateChangeHandler = onStateChange ?? null;
|
|
112
112
|
isStopping = false;
|
|
113
113
|
shouldReconnect = false;
|
|
114
|
-
log.info(
|
|
114
|
+
log.info('Initializing WeWork client');
|
|
115
115
|
// 首次连接支持重试:单独启用企微时偶发 TLS 连接失败,加飞书后因初始化顺序有“预热”效果则稳定
|
|
116
116
|
const maxAttempts = 3;
|
|
117
117
|
const retryDelayMs = 1500;
|
|
@@ -251,7 +251,7 @@ export function setupWeWorkHandlers(config, sessionManager) {
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
async function handleEvent(data) {
|
|
254
|
-
log.
|
|
254
|
+
log.debug('[handleEvent] Called with data:', JSON.stringify(data).slice(0, 800));
|
|
255
255
|
const reqId = data.headers?.req_id ?? '';
|
|
256
256
|
senderCtx.reqId = reqId;
|
|
257
257
|
try {
|
|
@@ -332,7 +332,7 @@ export async function sendErrorMessage(chatId, error, reqId) {
|
|
|
332
332
|
const message = formatWeWorkMessage('错误', error, 'error');
|
|
333
333
|
try {
|
|
334
334
|
sendText(getReqId(reqId), message);
|
|
335
|
-
log.
|
|
335
|
+
log.warn(`Error message sent to user ${chatId}`);
|
|
336
336
|
}
|
|
337
337
|
catch (err) {
|
|
338
338
|
log.error('Failed to send error message:', err);
|
package/dist/wework/types.d.ts
CHANGED
|
@@ -131,13 +131,6 @@ export interface MessageState {
|
|
|
131
131
|
/** 流式回复的 streamId,用于保持同一个流式回复使用相同的 streamId */
|
|
132
132
|
streamId?: string;
|
|
133
133
|
}
|
|
134
|
-
export interface WeWorkResponse {
|
|
135
|
-
headers: {
|
|
136
|
-
req_id: string;
|
|
137
|
-
};
|
|
138
|
-
errcode: number;
|
|
139
|
-
errmsg: string;
|
|
140
|
-
}
|
|
141
134
|
export interface WeWorkHttpResponseBody {
|
|
142
135
|
msgtype: 'text' | 'markdown' | 'stream';
|
|
143
136
|
text?: {
|
package/dist/workbuddy/client.js
CHANGED
|
@@ -153,7 +153,7 @@ async function connect() {
|
|
|
153
153
|
channelId: pc.userId ?? '', // plugin uses userId, not full channel name
|
|
154
154
|
userId: pc.userId ?? '',
|
|
155
155
|
})
|
|
156
|
-
.then((res) => log.
|
|
156
|
+
.then((res) => log.debug(`WeChat KF channel registered (online): ${JSON.stringify(res)}`))
|
|
157
157
|
.catch((err) => log.warn(`registerChannel failed: ${String(err)}`));
|
|
158
158
|
};
|
|
159
159
|
doRegister();
|
|
@@ -176,7 +176,7 @@ async function connect() {
|
|
|
176
176
|
channelId: pc.userId ?? '',
|
|
177
177
|
userId: pc.userId ?? '',
|
|
178
178
|
})
|
|
179
|
-
.then((res) => log.
|
|
179
|
+
.then((res) => log.debug(`WeChat KF channel registered (fallback): ${JSON.stringify(res)}`))
|
|
180
180
|
.catch((e) => log.warn(`registerChannel failed: ${String(e)}`));
|
|
181
181
|
};
|
|
182
182
|
doRegister();
|
|
@@ -30,7 +30,7 @@ export async function sendErrorReply(_client, chatId, error, msgId) {
|
|
|
30
30
|
log.warn('WorkBuddy client not available, cannot send error');
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
log.
|
|
33
|
+
log.warn(`Sending WorkBuddy error to chatId=${chatId}, msgId=${msgId}`);
|
|
34
34
|
await client.sendPromptResponse({
|
|
35
35
|
session_id: chatId,
|
|
36
36
|
prompt_id: msgId,
|
package/dist/workbuddy/oauth.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
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');
|
|
5
7
|
const DEFAULT_BASE_URL = 'https://copilot.tencent.com';
|
|
6
8
|
const PLATFORM = 'ide';
|
|
7
9
|
export class WorkBuddyOAuth {
|
|
@@ -196,7 +198,14 @@ export class WorkBuddyOAuth {
|
|
|
196
198
|
return { success: false, message: `获取链接失败: ${res.status} ${body}` };
|
|
197
199
|
}
|
|
198
200
|
const body = (await res.json());
|
|
199
|
-
|
|
201
|
+
log.debug('getWeChatKfLink response:', JSON.stringify(body).slice(0, 500));
|
|
202
|
+
if (body.data)
|
|
203
|
+
return body.data;
|
|
204
|
+
// API may return fields directly without data wrapper
|
|
205
|
+
if (body.success !== undefined || body.url !== undefined) {
|
|
206
|
+
return body;
|
|
207
|
+
}
|
|
208
|
+
return { success: false, message: `Empty response: ${JSON.stringify(body).slice(0, 200)}` };
|
|
200
209
|
}
|
|
201
210
|
/**
|
|
202
211
|
* Check WeChat KF binding status
|